Merge "When a new group summary is added, clean up any ungrouped children" into main
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 8bfac03..4e05cbc 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -110,6 +110,7 @@
         "com.android.window.flags.window-aconfig-java",
         "configinfra_framework_flags_java_exported_lib",
         "conscrypt_exported_aconfig_flags_lib",
+        "sdk_sandbox_exported_flags_lib",
         "device_policy_aconfig_flags_lib",
         "display_flags_lib",
         "dropbox_flags_lib",
@@ -123,7 +124,6 @@
         "libcore_readonly_aconfig_flags_lib",
         "libgui_flags_java_lib",
         "power_flags_lib",
-        "sdk_sandbox_flags_lib",
         "surfaceflinger_flags_java_lib",
         "telecom_flags_core_java_lib",
         "telephony_flags_core_java_lib",
diff --git a/Android.bp b/Android.bp
index 303fa2c..444725e 100644
--- a/Android.bp
+++ b/Android.bp
@@ -103,10 +103,10 @@
         ":android.hardware.gnss-V2-java-source",
         ":android.hardware.graphics.common-V3-java-source",
         ":android.hardware.keymaster-V4-java-source",
-        ":android.hardware.radio-V4-java-source",
-        ":android.hardware.radio.data-V4-java-source",
-        ":android.hardware.radio.network-V4-java-source",
-        ":android.hardware.radio.voice-V4-java-source",
+        ":android.hardware.radio-V5-java-source",
+        ":android.hardware.radio.data-V5-java-source",
+        ":android.hardware.radio.network-V5-java-source",
+        ":android.hardware.radio.voice-V5-java-source",
         ":android.hardware.security.secureclock-V1-java-source",
         ":android.hardware.thermal-V3-java-source",
         ":android.hardware.tv.tuner-V3-java-source",
@@ -232,13 +232,13 @@
         "android.hardware.gnss-V2.1-java",
         "android.hardware.health-V1.0-java-constants",
         "android.hardware.radio-V1.6-java",
-        "android.hardware.radio.data-V4-java",
-        "android.hardware.radio.ims-V3-java",
-        "android.hardware.radio.messaging-V4-java",
-        "android.hardware.radio.modem-V4-java",
-        "android.hardware.radio.network-V4-java",
-        "android.hardware.radio.sim-V4-java",
-        "android.hardware.radio.voice-V4-java",
+        "android.hardware.radio.data-V5-java",
+        "android.hardware.radio.ims-V4-java",
+        "android.hardware.radio.messaging-V5-java",
+        "android.hardware.radio.modem-V5-java",
+        "android.hardware.radio.network-V5-java",
+        "android.hardware.radio.sim-V5-java",
+        "android.hardware.radio.voice-V5-java",
         "android.hardware.thermal-V1.0-java-constants",
         "android.hardware.thermal-V1.0-java",
         "android.hardware.thermal-V1.1-java",
diff --git a/PREUPLOAD.cfg b/PREUPLOAD.cfg
index 05d6e88..e862cd9 100644
--- a/PREUPLOAD.cfg
+++ b/PREUPLOAD.cfg
@@ -6,6 +6,7 @@
 [Builtin Hooks Options]
 # Only turn on clang-format check for the following subfolders.
 clang_format = --commit ${PREUPLOAD_COMMIT} --style file --extensions c,h,cc,cpp
+               apct-tests/
                cmds/hid/
                cmds/input/
                cmds/uinput/
@@ -18,7 +19,7 @@
                tests/
                tools/
 bpfmt = -d
-ktfmt = --kotlinlang-style --include-dirs=services/permission,packages/SystemUI,libs/WindowManager/Shell/src/com/android/wm/shell/freeform,libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode,libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode
+ktfmt = --kotlinlang-style --include-dirs=services/permission,packages/SystemUI,libs/WindowManager/Shell/src/com/android/wm/shell/freeform,libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode,libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode,apct-tests
 
 [Hook Scripts]
 checkstyle_hook = ${REPO_ROOT}/prebuilts/checkstyle/checkstyle.py --sha ${PREUPLOAD_COMMIT}
diff --git a/Ravenwood.bp b/Ravenwood.bp
index 2e038e0..a16b440 100644
--- a/Ravenwood.bp
+++ b/Ravenwood.bp
@@ -19,6 +19,7 @@
     name: "framework-minus-apex-for-host",
     installable: false,
     static_libs: ["framework-minus-apex"],
+    srcs: [":framework-ravenwood-sources"],
     visibility: ["//frameworks/base/ravenwood"],
 }
 
diff --git a/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt b/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt
index add0a08..cf93331 100644
--- a/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt
+++ b/apct-tests/perftests/core/src/android/input/MotionPredictorBenchmark.kt
@@ -25,11 +25,10 @@
 import android.view.MotionEvent.PointerCoords
 import android.view.MotionEvent.PointerProperties
 import android.view.MotionPredictor
-
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.filters.LargeTest
 import androidx.test.ext.junit.runners.AndroidJUnit4
-
+import androidx.test.filters.LargeTest
+import androidx.test.platform.app.InstrumentationRegistry
+import java.time.Duration
 import org.junit.After
 import org.junit.Assert.assertTrue
 import org.junit.Before
@@ -37,14 +36,12 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 
-import java.time.Duration
-
 private fun getStylusMotionEvent(
-        eventTime: Duration,
-        action: Int,
-        x: Float,
-        y: Float,
-        ): MotionEvent{
+    eventTime: Duration,
+    action: Int,
+    x: Float,
+    y: Float,
+): MotionEvent {
     val pointerCount = 1
     val properties = arrayOfNulls<MotionEvent.PointerProperties>(pointerCount)
     val coords = arrayOfNulls<MotionEvent.PointerCoords>(pointerCount)
@@ -58,37 +55,49 @@
         coords[i]!!.y = y
     }
 
-    return MotionEvent.obtain(/*downTime=*/0, eventTime.toMillis(), action, properties.size,
-                properties, coords, /*metaState=*/0, /*buttonState=*/0,
-                /*xPrecision=*/0f, /*yPrecision=*/0f, /*deviceId=*/0, /*edgeFlags=*/0,
-                InputDevice.SOURCE_STYLUS, /*flags=*/0)
+    return MotionEvent.obtain(
+        /*downTime=*/ 0,
+        eventTime.toMillis(),
+        action,
+        properties.size,
+        properties,
+        coords,
+        /*metaState=*/ 0,
+        /*buttonState=*/ 0,
+        /*xPrecision=*/ 0f,
+        /*yPrecision=*/ 0f,
+        /*deviceId=*/ 0,
+        /*edgeFlags=*/ 0,
+        InputDevice.SOURCE_STYLUS,
+        /*flags=*/ 0,
+    )
 }
 
 @RunWith(AndroidJUnit4::class)
 @LargeTest
 class MotionPredictorBenchmark {
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
-    @get:Rule
-    val perfStatusReporter = PerfStatusReporter()
+    @get:Rule val perfStatusReporter = PerfStatusReporter()
     private val initialPropertyValue =
-            SystemProperties.get("persist.input.enable_motion_prediction")
-
+        SystemProperties.get("persist.input.enable_motion_prediction")
 
     @Before
     fun setUp() {
         instrumentation.uiAutomation.executeShellCommand(
-            "setprop persist.input.enable_motion_prediction true")
+            "setprop persist.input.enable_motion_prediction true"
+        )
     }
 
     @After
     fun tearDown() {
         instrumentation.uiAutomation.executeShellCommand(
-            "setprop persist.input.enable_motion_prediction $initialPropertyValue")
+            "setprop persist.input.enable_motion_prediction $initialPropertyValue"
+        )
     }
 
     /**
-     * In a typical usage, app will send the event to the predictor and then call .predict to draw
-     * a prediction. In a loop, we keep sending MOVE and then calling .predict to simulate this.
+     * In a typical usage, app will send the event to the predictor and then call .predict to draw a
+     * prediction. In a loop, we keep sending MOVE and then calling .predict to simulate this.
      */
     @Test
     fun timeRecordAndPredict() {
@@ -99,10 +108,16 @@
         var eventPosition = 0f
         val positionInterval = 10f
 
-        val predictor = MotionPredictor(/*isPredictionEnabled=*/true, offset.toNanos().toInt())
+        val predictor = MotionPredictor(/* isPredictionEnabled= */ true, offset.toNanos().toInt())
         // ACTION_DOWN t=0 x=0 y=0
-        predictor.record(getStylusMotionEvent(
-            eventTime, ACTION_DOWN, /*x=*/eventPosition, /*y=*/eventPosition))
+        predictor.record(
+            getStylusMotionEvent(
+                eventTime,
+                ACTION_DOWN,
+                /*x=*/ eventPosition,
+                /*y=*/ eventPosition,
+            )
+        )
 
         val state = perfStatusReporter.getBenchmarkState()
         while (state.keepRunning()) {
@@ -110,8 +125,13 @@
             eventPosition += positionInterval
 
             // Send MOVE event and then call .predict
-            val moveEvent = getStylusMotionEvent(
-                eventTime, ACTION_MOVE, /*x=*/eventPosition, /*y=*/eventPosition)
+            val moveEvent =
+                getStylusMotionEvent(
+                    eventTime,
+                    ACTION_MOVE,
+                    /*x=*/ eventPosition,
+                    /*y=*/ eventPosition,
+                )
             predictor.record(moveEvent)
             val predictionTime = eventTime + eventInterval
             val predicted = checkNotNull(predictor.predict(predictionTime.toNanos()))
@@ -129,7 +149,7 @@
 
         val state = perfStatusReporter.getBenchmarkState()
         while (state.keepRunning()) {
-            MotionPredictor(/*isPredictionEnabled=*/true, offsetNanos)
+            MotionPredictor(/* isPredictionEnabled= */ true, offsetNanos)
         }
     }
 }
diff --git a/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt b/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt
index 530ca7b..c6fe324 100644
--- a/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt
+++ b/apct-tests/perftests/core/src/android/input/VelocityTrackerBenchmarkTest.kt
@@ -19,12 +19,9 @@
 import android.view.InputDevice
 import android.view.MotionEvent
 import android.view.VelocityTracker
-
 import androidx.test.filters.LargeTest
 import androidx.test.runner.AndroidJUnit4
-
 import java.time.Duration
-
 import org.junit.Assert
 import org.junit.Before
 import org.junit.Rule
@@ -74,22 +71,23 @@
         props.id = 0
         val coords = MotionEvent.PointerCoords()
         coords.setAxisValue(MotionEvent.AXIS_SCROLL, DEFAULT_SCROLL_AMOUNT)
-        val motionEvent = MotionEvent.obtain(
-            /*downTime=*/0,
-            currentTime.toMillis(),
-            MotionEvent.ACTION_SCROLL,
-            /*pointerCount=*/1,
-            arrayOf(props),
-            arrayOf(coords),
-            /*metaState=*/0,
-            /*buttonState=*/0,
-            /*xPrecision=*/0f,
-            /*yPrecision=*/0f,
-            /*deviceId=*/1,
-            /*edgeFlags=*/0,
-            InputDevice.SOURCE_ROTARY_ENCODER,
-            /*flags=*/0
-        )
+        val motionEvent =
+            MotionEvent.obtain(
+                /*downTime=*/ 0,
+                currentTime.toMillis(),
+                MotionEvent.ACTION_SCROLL,
+                /*pointerCount=*/ 1,
+                arrayOf(props),
+                arrayOf(coords),
+                /*metaState=*/ 0,
+                /*buttonState=*/ 0,
+                /*xPrecision=*/ 0f,
+                /*yPrecision=*/ 0f,
+                /*deviceId=*/ 1,
+                /*edgeFlags=*/ 0,
+                InputDevice.SOURCE_ROTARY_ENCODER,
+                /*flags=*/ 0,
+            )
 
         currentTime = currentTime.plus(DEFAULT_TIME_JUMP)
 
@@ -113,13 +111,15 @@
 
     override fun createMotionEvent(): MotionEvent {
         val action: Int = if (downEventCreated) MotionEvent.ACTION_MOVE else MotionEvent.ACTION_DOWN
-        val motionEvent = MotionEvent.obtain(
-            /*downTime=*/START_TIME.toMillis(),
-            currentTime.toMillis(),
-            action,
-            x,
-            y,
-            /*metaState=*/0)
+        val motionEvent =
+            MotionEvent.obtain(
+                /*downTime=*/ START_TIME.toMillis(),
+                currentTime.toMillis(),
+                action,
+                x,
+                y,
+                /*metaState=*/ 0,
+            )
 
         if (downEventCreated) {
             x += INCREMENT
@@ -155,16 +155,15 @@
 /**
  * Benchmark tests for [VelocityTracker]
  *
- * Build/Install/Run:
- * atest VelocityTrackerBenchmarkTest
+ * Build/Install/Run: atest VelocityTrackerBenchmarkTest
  */
 @LargeTest
 @RunWith(AndroidJUnit4::class)
 class VelocityTrackerBenchmarkTest {
-    @get:Rule
-    val perfStatusReporter: PerfStatusReporter = PerfStatusReporter()
+    @get:Rule val perfStatusReporter: PerfStatusReporter = PerfStatusReporter()
 
     private val velocityTracker = VelocityTracker.obtain()
+
     @Before
     fun setup() {
         velocityTracker.clear()
@@ -255,4 +254,4 @@
     companion object {
         private const val TEST_NUM_DATAPOINTS = 100
     }
-}
\ No newline at end of file
+}
diff --git a/apct-tests/perftests/core/src/android/view/ViewConfigurationPerfTest.java b/apct-tests/perftests/core/src/android/view/ViewConfigurationPerfTest.java
index 7a7250b..8e3ed6d 100644
--- a/apct-tests/perftests/core/src/android/view/ViewConfigurationPerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/ViewConfigurationPerfTest.java
@@ -19,24 +19,27 @@
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
 import android.content.Context;
+import android.perftests.utils.BenchmarkState;
+import android.perftests.utils.PerfStatusReporter;
 
-import androidx.benchmark.BenchmarkState;
-import androidx.benchmark.junit4.BenchmarkRule;
-import androidx.test.filters.SmallTest;
+import androidx.test.filters.LargeTest;
+import androidx.test.runner.AndroidJUnit4;
 
 import org.junit.Rule;
 import org.junit.Test;
+import org.junit.runner.RunWith;
 
-@SmallTest
+@LargeTest
+@RunWith(AndroidJUnit4.class)
 public class ViewConfigurationPerfTest {
     @Rule
-    public final BenchmarkRule mBenchmarkRule = new BenchmarkRule();
+    public PerfStatusReporter mPerfStatusReporter = new PerfStatusReporter();
 
     private final Context mContext = getInstrumentation().getTargetContext();
 
     @Test
     public void testGet_newViewConfiguration() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
 
         while (state.keepRunning()) {
             state.pauseTiming();
@@ -50,7 +53,7 @@
 
     @Test
     public void testGet_cachedViewConfiguration() {
-        final BenchmarkState state = mBenchmarkRule.getState();
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
         // Do `get` once to make sure there's something cached.
         ViewConfiguration.get(mContext);
 
@@ -58,4 +61,265 @@
             ViewConfiguration.get(mContext);
         }
     }
+
+    @Test
+    public void testGetPressedStateDuration_unCached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            // Reset any caches.
+            ViewConfiguration.resetCacheForTesting();
+            state.resumeTiming();
+
+            ViewConfiguration.getPressedStateDuration();
+        }
+    }
+
+    @Test
+    public void testGetPressedStateDuration_cached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        // Do `get` once to make sure the value gets cached.
+        ViewConfiguration.getPressedStateDuration();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getPressedStateDuration();
+        }
+    }
+
+    @Test
+    public void testGetTapTimeout_unCached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            // Reset any caches.
+            ViewConfiguration.resetCacheForTesting();
+            state.resumeTiming();
+
+            ViewConfiguration.getTapTimeout();
+        }
+    }
+
+    @Test
+    public void testGetTapTimeout_cached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        // Do `get` once to make sure the value gets cached.
+        ViewConfiguration.getTapTimeout();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getTapTimeout();
+        }
+    }
+
+    @Test
+    public void testGetJumpTapTimeout_unCached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            // Reset any caches.
+            ViewConfiguration.resetCacheForTesting();
+            state.resumeTiming();
+
+            ViewConfiguration.getJumpTapTimeout();
+        }
+    }
+
+    @Test
+    public void testGetJumpTapTimeout_cached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        // Do `get` once to make sure the value gets cached.
+        ViewConfiguration.getJumpTapTimeout();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getJumpTapTimeout();
+        }
+    }
+
+    @Test
+    public void testGetDoubleTapTimeout_unCached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            // Reset any caches.
+            ViewConfiguration.resetCacheForTesting();
+            state.resumeTiming();
+
+            ViewConfiguration.getDoubleTapTimeout();
+        }
+    }
+
+    @Test
+    public void testGetDoubleTapTimeout_cached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        // Do `get` once to make sure the value gets cached.
+        ViewConfiguration.getDoubleTapTimeout();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getDoubleTapTimeout();
+        }
+    }
+
+    @Test
+    public void testGetDoubleTapMinTime_unCached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            // Reset any caches.
+            ViewConfiguration.resetCacheForTesting();
+            state.resumeTiming();
+
+            ViewConfiguration.getDoubleTapMinTime();
+        }
+    }
+
+    @Test
+    public void testGetDoubleTapMinTime_cached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        // Do `get` once to make sure the value gets cached.
+        ViewConfiguration.getDoubleTapMinTime();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getDoubleTapMinTime();
+        }
+    }
+
+    @Test
+    public void testGetZoomControlsTimeout_unCached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            // Reset any caches.
+            ViewConfiguration.resetCacheForTesting();
+            state.resumeTiming();
+
+            ViewConfiguration.getZoomControlsTimeout();
+        }
+    }
+
+    @Test
+    public void testGetZoomControlsTimeout_cached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        // Do `get` once to make sure the value gets cached.
+        ViewConfiguration.getZoomControlsTimeout();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getZoomControlsTimeout();
+        }
+    }
+
+    @Test
+    public void testGetLongPressTimeout() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getLongPressTimeout();
+        }
+    }
+
+    @Test
+    public void testGetMultiPressTimeout() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getMultiPressTimeout();
+        }
+    }
+
+    @Test
+    public void testGetKeyRepeatTimeout() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getKeyRepeatTimeout();
+        }
+    }
+
+    @Test
+    public void testGetKeyRepeatDelay() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getKeyRepeatDelay();
+        }
+    }
+
+    @Test
+    public void testGetHoverTapSlop_unCached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            // Reset any caches.
+            ViewConfiguration.resetCacheForTesting();
+            state.resumeTiming();
+
+            ViewConfiguration.getHoverTapSlop();
+        }
+    }
+
+    @Test
+    public void testGetHoverTapSlop_cached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        // Do `get` once to make sure the value gets cached.
+        ViewConfiguration.getHoverTapSlop();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getHoverTapSlop();
+        }
+    }
+
+    @Test
+    public void testGetScrollFriction_unCached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            // Reset any caches.
+            ViewConfiguration.resetCacheForTesting();
+            state.resumeTiming();
+
+            ViewConfiguration.getScrollFriction();
+        }
+    }
+
+    @Test
+    public void testGetScrollFriction_cached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        // Do `get` once to make sure the value gets cached.
+        ViewConfiguration.getScrollFriction();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getScrollFriction();
+        }
+    }
+
+    @Test
+    public void testGetDefaultActionModeHideDuration_unCached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+
+        while (state.keepRunning()) {
+            state.pauseTiming();
+            // Reset any caches.
+            ViewConfiguration.resetCacheForTesting();
+            state.resumeTiming();
+
+            ViewConfiguration.getDefaultActionModeHideDuration();
+        }
+    }
+
+    @Test
+    public void testGetDefaultActionModeHideDuration_cached() {
+        final BenchmarkState state = mPerfStatusReporter.getBenchmarkState();
+        // Do `get` once to make sure the value gets cached.
+        ViewConfiguration.getDefaultActionModeHideDuration();
+
+        while (state.keepRunning()) {
+            ViewConfiguration.getDefaultActionModeHideDuration();
+        }
+    }
 }
diff --git a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
index 67b33e5..d2321ec 100644
--- a/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
+++ b/apct-tests/perftests/core/src/android/view/ViewPerfTest.java
@@ -84,12 +84,10 @@
 
         final BenchmarkState state = mBenchmarkRule.getState();
         mActivityRule.runOnUiThread(() -> {
-            state.pauseTiming();
             View view = new View(mContext);
             mActivityRule.getActivity().setContentView(view);
             assertTrue("View needs to be attached to Window to perform haptic feedback",
                     view.isAttachedToWindow());
-            state.resumeTiming();
 
             // Disable settings so perform will never be ignored.
             int flags = HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING
diff --git a/apct-tests/perftests/healthconnect/src/com/android/perftests/healthconnect/HealthConnectReadWritePerfTest.kt b/apct-tests/perftests/healthconnect/src/com/android/perftests/healthconnect/HealthConnectReadWritePerfTest.kt
index 21a4ca0..bdb54c9 100644
--- a/apct-tests/perftests/healthconnect/src/com/android/perftests/healthconnect/HealthConnectReadWritePerfTest.kt
+++ b/apct-tests/perftests/healthconnect/src/com/android/perftests/healthconnect/HealthConnectReadWritePerfTest.kt
@@ -32,8 +32,7 @@
 @RunWith(AndroidJUnit4::class)
 class HealthConnectReadWritePerfTest {
 
-    @get:Rule
-    val perfStatusReporter = PerfStatusReporter()
+    @get:Rule val perfStatusReporter = PerfStatusReporter()
 
     private val context by lazy { InstrumentationRegistry.getInstrumentation().context }
 
@@ -41,9 +40,7 @@
         requireNotNull(context.getSystemService(HealthConnectManager::class.java))
     }
 
-    /**
-     * A first empty test just to setup the test package and make sure it runs properly.
-     */
+    /** A first empty test just to setup the test package and make sure it runs properly. */
     @Test
     fun placeholder() {
         val state = perfStatusReporter.benchmarkState
@@ -51,4 +48,4 @@
             SystemClock.sleep(100)
         }
     }
-}
\ No newline at end of file
+}
diff --git a/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
index ea10690..48f2c15 100644
--- a/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
+++ b/apct-tests/perftests/packagemanager/src/android/os/PackageParsingPerfTest.kt
@@ -51,51 +51,52 @@
         private const val QUEUE_POLL_TIMEOUT_SECONDS = 5L
 
         // TODO: Replace this with core version of SYSTEM_PARTITIONS
-        val FOLDERS_TO_TEST = listOf(
-            Environment.getRootDirectory(),
-            Environment.getVendorDirectory(),
-            Environment.getOdmDirectory(),
-            Environment.getOemDirectory(),
-            Environment.getOemDirectory(),
-            Environment.getSystemExtDirectory()
-        )
+        val FOLDERS_TO_TEST =
+            listOf(
+                Environment.getRootDirectory(),
+                Environment.getVendorDirectory(),
+                Environment.getOdmDirectory(),
+                Environment.getOemDirectory(),
+                Environment.getOemDirectory(),
+                Environment.getSystemExtDirectory(),
+            )
 
         @JvmStatic
         @Parameterized.Parameters(name = "{0}")
         fun parameters(): Array<Params> {
-            val apks = FOLDERS_TO_TEST
-                .filter(File::exists)
-                .map(File::walkTopDown)
-                .flatMap(Sequence<File>::asIterable)
-                .filter { it.name.endsWith(".apk") }
+            val apks =
+                FOLDERS_TO_TEST.filter(File::exists)
+                    .map(File::walkTopDown)
+                    .flatMap(Sequence<File>::asIterable)
+                    .filter { it.name.endsWith(".apk") }
 
             return arrayOf(
                 Params(1, apks) { ParallelParser1(it?.let(::PackageCacher1)) },
-                Params(2, apks) { ParallelParser2(it?.let(::PackageCacher2)) }
+                Params(2, apks) { ParallelParser2(it?.let(::PackageCacher2)) },
             )
         }
 
         data class Params(
             val version: Int,
             val apks: List<File>,
-            val cacheDirToParser: (File?) -> ParallelParser<*>
+            val cacheDirToParser: (File?) -> ParallelParser<*>,
         ) {
             // For test name formatting
             override fun toString() = "v$version"
         }
     }
 
-    @get:Rule
-    var perfStatusReporter = PerfStatusReporter()
+    @get:Rule var perfStatusReporter = PerfStatusReporter()
 
-    @get:Rule
-    var testFolder = TemporaryFolder()
+    @get:Rule var testFolder = TemporaryFolder()
 
-    @Parameterized.Parameter(0)
-    lateinit var params: Params
+    @Parameterized.Parameter(0) lateinit var params: Params
 
-    private val state: BenchmarkState get() = perfStatusReporter.benchmarkState
-    private val apks: List<File> get() = params.apks
+    private val state: BenchmarkState
+        get() = perfStatusReporter.benchmarkState
+
+    private val apks: List<File>
+        get() = params.apks
 
     private fun safeParse(parser: ParallelParser<*>, file: File) {
         try {
@@ -109,9 +110,7 @@
     fun sequentialNoCache() {
         params.cacheDirToParser(null).use { parser ->
             while (state.keepRunning()) {
-                apks.forEach {
-                    safeParse(parser, it)
-                }
+                apks.forEach { safeParse(parser, it) }
             }
         }
     }
@@ -155,18 +154,21 @@
         private val cacher: PackageCacher<PackageType>? = null
     ) : AutoCloseable {
         private val queue = ArrayBlockingQueue<Any>(PARALLEL_QUEUE_CAPACITY)
-        private val service = ConcurrentUtils.newFixedThreadPool(
-            PARALLEL_MAX_THREADS, "package-parsing-test",
-            Process.THREAD_PRIORITY_FOREGROUND)
+        private val service =
+            ConcurrentUtils.newFixedThreadPool(
+                PARALLEL_MAX_THREADS,
+                "package-parsing-test",
+                Process.THREAD_PRIORITY_FOREGROUND,
+            )
 
         fun submit(file: File) {
-                service.submit {
-                    try {
-                        queue.put(parse(file))
-                    } catch (e: Exception) {
-                        queue.put(e)
-                    }
+            service.submit {
+                try {
+                    queue.put(parse(file))
+                } catch (e: Exception) {
+                    queue.put(e)
                 }
+            }
         }
 
         fun take() = queue.poll(QUEUE_POLL_TIMEOUT_SECONDS, TimeUnit.SECONDS)
@@ -175,57 +177,51 @@
             service.shutdownNow()
         }
 
-        fun parse(file: File) = cacher?.getCachedResult(file)
-            ?: parseImpl(file).also { cacher?.cacheResult(file, it) }
+        fun parse(file: File) =
+            cacher?.getCachedResult(file) ?: parseImpl(file).also { cacher?.cacheResult(file, it) }
 
         protected abstract fun parseImpl(file: File): PackageType
     }
 
     class ParallelParser1(private val cacher: PackageCacher1? = null) :
         ParallelParser<PackageParser.Package>(cacher) {
-        val parser = PackageParser().apply {
-            setCallback { true }
-        }
+        val parser = PackageParser().apply { setCallback { true } }
 
         override fun parseImpl(file: File) = parser.parsePackage(file, 0, cacher != null)
     }
 
-    class ParallelParser2(cacher: PackageCacher2? = null) :
-        ParallelParser<PackageImpl>(cacher) {
-        val input = ThreadLocal.withInitial {
-            // For testing, just disable enforcement to avoid hooking up to compat framework
-            ParseTypeImpl(ParseInput.Callback { _, _, _ -> false })
-        }
-        val parser = ParsingPackageUtils(null,
-            null,
-            emptyList(),
-            object :
-                ParsingPackageUtils.Callback {
-                override fun hasFeature(feature: String) = true
+    class ParallelParser2(cacher: PackageCacher2? = null) : ParallelParser<PackageImpl>(cacher) {
+        val input =
+            ThreadLocal.withInitial {
+                // For testing, just disable enforcement to avoid hooking up to compat framework
+                ParseTypeImpl(ParseInput.Callback { _, _, _ -> false })
+            }
+        val parser =
+            ParsingPackageUtils(
+                null,
+                null,
+                emptyList(),
+                object : ParsingPackageUtils.Callback {
+                    override fun hasFeature(feature: String) = true
 
-                override fun startParsingPackage(
-                    packageName: String,
-                    baseApkPath: String,
-                    path: String,
-                    manifestArray: TypedArray,
-                    isCoreApp: Boolean
-                ) = PackageImpl(
-                    packageName,
-                    baseApkPath,
-                    path,
-                    manifestArray,
-                    isCoreApp,
-                    this,
-                )
-                override fun getHiddenApiWhitelistedApps() =
+                    override fun startParsingPackage(
+                        packageName: String,
+                        baseApkPath: String,
+                        path: String,
+                        manifestArray: TypedArray,
+                        isCoreApp: Boolean,
+                    ) = PackageImpl(packageName, baseApkPath, path, manifestArray, isCoreApp, this)
+
+                    override fun getHiddenApiWhitelistedApps() =
                         SystemConfig.getInstance().hiddenApiWhitelistedApps
-                override fun getInstallConstraintsAllowlist() =
+
+                    override fun getInstallConstraintsAllowlist() =
                         SystemConfig.getInstance().installConstraintsAllowlist
-            })
+                },
+            )
 
         override fun parseImpl(file: File) =
-                parser.parsePackage(input.get()!!.reset(), file, 0).result
-                        as PackageImpl
+            parser.parsePackage(input.get()!!.reset(), file, 0).result as PackageImpl
     }
 
     abstract class PackageCacher<PackageType : Parcelable>(private val cacheDir: File) {
@@ -237,14 +233,13 @@
             }
 
             val bytes = IoUtils.readFileAsByteArray(cacheFile.absolutePath)
-            val parcel = Parcel.obtain().apply {
-                unmarshall(bytes, 0, bytes.size)
-                setDataPosition(0)
-            }
+            val parcel =
+                Parcel.obtain().apply {
+                    unmarshall(bytes, 0, bytes.size)
+                    setDataPosition(0)
+                }
             ReadHelper(parcel).apply { startAndInstall() }
-            return fromParcel(parcel).also {
-                parcel.recycle()
-            }
+            return fromParcel(parcel).also { parcel.recycle() }
         }
 
         fun cacheResult(file: File, parsed: Parcelable) {
@@ -263,26 +258,19 @@
             val helper = WriteHelper(parcel)
             pkg.writeToParcel(parcel, 0 /* flags */)
             helper.finishAndUninstall()
-            return parcel.marshall().also {
-                parcel.recycle()
-            }
+            return parcel.marshall().also { parcel.recycle() }
         }
 
         protected abstract fun fromParcel(parcel: Parcel): PackageType
     }
 
-    /**
-     * Re-implementation of v1's cache, since that's gone in R+.
-     */
+    /** Re-implementation of v1's cache, since that's gone in R+. */
     class PackageCacher1(cacheDir: File) : PackageCacher<PackageParser.Package>(cacheDir) {
         override fun fromParcel(parcel: Parcel) = PackageParser.Package(parcel)
     }
 
-    /**
-     * Re-implementation of the server side PackageCacher, as it's inaccessible here.
-     */
+    /** Re-implementation of the server side PackageCacher, as it's inaccessible here. */
     class PackageCacher2(cacheDir: File) : PackageCacher<PackageImpl>(cacheDir) {
-        override fun fromParcel(parcel: Parcel) =
-            PackageImpl(parcel)
+        override fun fromParcel(parcel: Parcel) = PackageImpl(parcel)
     }
 }
diff --git a/apct-tests/perftests/permission/src/android/perftests/permission/AppOpsPerfTest.kt b/apct-tests/perftests/permission/src/android/perftests/permission/AppOpsPerfTest.kt
index b6a53bf..7d4061a 100644
--- a/apct-tests/perftests/permission/src/android/perftests/permission/AppOpsPerfTest.kt
+++ b/apct-tests/perftests/permission/src/android/perftests/permission/AppOpsPerfTest.kt
@@ -50,7 +50,7 @@
                 opPackageUid,
                 opPackageName,
                 null,
-                null
+                null,
             )
         }
     }
@@ -62,7 +62,7 @@
             appOpsManager.unsafeCheckOp(
                 AppOpsManager.OPSTR_FINE_LOCATION,
                 opPackageUid,
-                opPackageName
+                opPackageName,
             )
         }
     }
diff --git a/apct-tests/perftests/permission/src/android/perftests/permission/PermissionServicePerfTest.kt b/apct-tests/perftests/permission/src/android/perftests/permission/PermissionServicePerfTest.kt
index 1139835..b64d5d9 100644
--- a/apct-tests/perftests/permission/src/android/perftests/permission/PermissionServicePerfTest.kt
+++ b/apct-tests/perftests/permission/src/android/perftests/permission/PermissionServicePerfTest.kt
@@ -28,24 +28,26 @@
 import com.android.compatibility.common.util.SystemUtil.eventually
 import com.android.compatibility.common.util.SystemUtil.runShellCommand
 import com.google.common.truth.Truth.assertThat
-import org.junit.Rule
-import org.junit.Test
-import org.junit.runner.RunWith
 import java.io.BufferedReader
 import java.io.IOException
 import java.io.InputStreamReader
 import java.util.concurrent.TimeUnit
 import java.util.function.BiConsumer
 import org.junit.Ignore
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
 
 @RunWith(AndroidJUnit4::class)
 class PermissionServicePerfTest {
     @get:Rule val mPerfManualStatusReporter = PerfManualStatusReporter()
-    @get:Rule val mAdoptShellPermissionsRule = AdoptShellPermissionsRule(
-        InstrumentationRegistry.getInstrumentation().getUiAutomation(),
-        Manifest.permission.INSTALL_PACKAGES,
-        Manifest.permission.DELETE_PACKAGES
-    )
+    @get:Rule
+    val mAdoptShellPermissionsRule =
+        AdoptShellPermissionsRule(
+            InstrumentationRegistry.getInstrumentation().getUiAutomation(),
+            Manifest.permission.INSTALL_PACKAGES,
+            Manifest.permission.DELETE_PACKAGES,
+        )
     val mUiAutomation = InstrumentationRegistry.getInstrumentation().getUiAutomation()
 
     @Test
@@ -95,13 +97,14 @@
 
     private fun dumpResult(
         parser: TraceMarkParser,
-        handler: BiConsumer<String, List<TraceMarkParser.TraceMarkSlice>>
+        handler: BiConsumer<String, List<TraceMarkParser.TraceMarkSlice>>,
     ) {
         parser.reset()
         try {
-            val inputStream = ParcelFileDescriptor.AutoCloseInputStream(
-                mUiAutomation.executeShellCommand(COMMAND_TRACE_DUMP)
-            )
+            val inputStream =
+                ParcelFileDescriptor.AutoCloseInputStream(
+                    mUiAutomation.executeShellCommand(COMMAND_TRACE_DUMP)
+                )
             val reader = BufferedReader(InputStreamReader(inputStream))
             var line = reader.readLine()
             while (line != null) {
diff --git a/apex/jobscheduler/service/aconfig/app_idle.aconfig b/apex/jobscheduler/service/aconfig/app_idle.aconfig
index 74d2a59..8993410 100644
--- a/apex/jobscheduler/service/aconfig/app_idle.aconfig
+++ b/apex/jobscheduler/service/aconfig/app_idle.aconfig
@@ -28,3 +28,14 @@
     description: "Adjust the default bucket evaluation parameters"
     bug: "379909479"
 }
+
+flag {
+    name: "persist_restore_to_rare_apps_list"
+    namespace: "backstage_power"
+    description: "Persist the list of apps which are put in the RARE bucket upon restore."
+    is_fixed_read_only: true
+    bug: "383766428"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
index abec170..d52bbc2 100644
--- a/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
+++ b/apex/jobscheduler/service/java/com/android/server/job/controllers/DeviceIdleJobsController.java
@@ -18,6 +18,7 @@
 
 import static com.android.server.job.JobSchedulerService.sElapsedRealtimeClock;
 
+import android.annotation.NonNull;
 import android.app.job.JobInfo;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -28,6 +29,7 @@
 import android.os.Message;
 import android.os.PowerManager;
 import android.os.UserHandle;
+import android.provider.DeviceConfig;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
 import android.util.Log;
@@ -56,7 +58,10 @@
     private static final boolean DEBUG = JobSchedulerService.DEBUG
             || Log.isLoggable(TAG, Log.DEBUG);
 
-    private static final long BACKGROUND_JOBS_DELAY = 3000;
+    /** Prefix to use with all constant keys in order to "sub-namespace" the keys. */
+    private static final String DIJC_CONSTANT_PREFIX = "dijc_";
+    private static final String KEY_BACKGROUND_JOBS_DELAY_MS =
+            DIJC_CONSTANT_PREFIX + "background_jobs_delay_ms";
 
     static final int PROCESS_BACKGROUND_JOBS = 1;
 
@@ -78,6 +83,8 @@
     private int[] mDeviceIdleWhitelistAppIds;
     private int[] mPowerSaveTempWhitelistAppIds;
 
+    private long mBackgroundJobsDelay;
+
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
@@ -128,6 +135,9 @@
     public DeviceIdleJobsController(JobSchedulerService service) {
         super(service);
 
+        mBackgroundJobsDelay = mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_jobSchedulerBackgroundJobsDelay);
+
         mHandler = new DeviceIdleJobsDelayHandler(AppSchedulingModuleThread.get().getLooper());
         // Register for device idle mode changes
         mPowerManager = (PowerManager) mContext.getSystemService(Context.POWER_SERVICE);
@@ -165,7 +175,7 @@
                 // When coming out of doze, process all foreground uids and EJs immediately,
                 // while others will be processed after a delay of 3 seconds.
                 mService.getJobStore().forEachJob(mShouldRushEvaluation, mDeviceIdleUpdateFunctor);
-                mHandler.sendEmptyMessageDelayed(PROCESS_BACKGROUND_JOBS, BACKGROUND_JOBS_DELAY);
+                mHandler.sendEmptyMessageDelayed(PROCESS_BACKGROUND_JOBS, mBackgroundJobsDelay);
             }
         }
         // Inform the job scheduler service about idle mode changes
@@ -237,6 +247,26 @@
     }
 
     @Override
+    public void processConstantLocked(@NonNull DeviceConfig.Properties properties,
+            @NonNull String key) {
+        switch (key) {
+            case KEY_BACKGROUND_JOBS_DELAY_MS:
+                mBackgroundJobsDelay = Math.max(0, properties.getLong(key, mBackgroundJobsDelay));
+                break;
+        }
+    }
+
+    @Override
+    public void dumpConstants(IndentingPrintWriter pw) {
+        pw.println();
+        pw.print(DeviceIdleJobsController.class.getSimpleName());
+        pw.println(":");
+        pw.increaseIndent();
+        pw.print(KEY_BACKGROUND_JOBS_DELAY_MS, mBackgroundJobsDelay).println();
+        pw.decreaseIndent();
+    }
+
+    @Override
     public void dumpControllerStateLocked(final IndentingPrintWriter pw,
             final Predicate<JobStatus> predicate) {
         pw.println("Idle mode: " + mDeviceIdleMode);
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
index a8641ae..4acfebc 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppIdleHistory.java
@@ -38,6 +38,7 @@
 import android.app.usage.UsageStatsManager;
 import android.os.SystemClock;
 import android.util.ArrayMap;
+import android.util.ArraySet;
 import android.util.AtomicFile;
 import android.util.IndentingPrintWriter;
 import android.util.Slog;
@@ -83,6 +84,9 @@
     private SparseArray<ArrayMap<String,AppUsageHistory>> mIdleHistory = new SparseArray<>();
     private static final long ONE_MINUTE = 60 * 1000;
 
+    // Only keep the persisted restore-to-rare apps list for 2 days.
+    static final long RESTORE_TO_RARE_APPS_LIST_EXPIRY = ONE_MINUTE * 60 * 24 * 2;
+
     static final int STANDBY_BUCKET_UNKNOWN = -1;
 
     /**
@@ -277,6 +281,58 @@
         writeScreenOnTime();
     }
 
+    private File getRestoreToRareAppsListFile(int userId) {
+        return new File(getUserDirectory(userId), "restore_to_rare_apps_list");
+    }
+
+    public ArraySet<String> readRestoreToRareAppsList(int userId) {
+        File restoreToRareAppsListFile = getRestoreToRareAppsListFile(userId);
+        if (!restoreToRareAppsListFile.exists()) {
+            return null;
+        }
+
+        try (BufferedReader reader =
+                     new BufferedReader(new FileReader(restoreToRareAppsListFile))) {
+            final ArraySet<String> appsList = new ArraySet<>();
+            final long restoreTime = Long.parseLong(reader.readLine());
+            if (System.currentTimeMillis() - restoreTime > RESTORE_TO_RARE_APPS_LIST_EXPIRY) {
+                // the apps list should only be kept around for 2 days
+                reader.close();
+                restoreToRareAppsListFile.delete();
+                return null;
+            }
+            String pkgName;
+            while ((pkgName = reader.readLine()) != null) {
+                appsList.add(pkgName);
+            }
+            return appsList;
+        } catch (IOException | NumberFormatException e) {
+            return null;
+        }
+    }
+
+    public void writeRestoreToRareAppsList(int userId, ArraySet<String> restoreAppsToRare) {
+        File fileHandle = getRestoreToRareAppsListFile(userId);
+        if (fileHandle.exists()) {
+            // don't update the persisted file - it should only be written once.
+            return;
+        }
+        AtomicFile restoreToRareAppsListFile = new AtomicFile(fileHandle);
+        FileOutputStream fos = null;
+        try {
+            fos = restoreToRareAppsListFile.startWrite();
+            final StringBuilder sb = new StringBuilder();
+            sb.append(System.currentTimeMillis()).append("\n");
+            for (String pkgName : restoreAppsToRare) {
+                sb.append(pkgName).append("\n");
+            }
+            fos.write(sb.toString().getBytes());
+            restoreToRareAppsListFile.finishWrite(fos);
+        } catch (IOException ioe) {
+            restoreToRareAppsListFile.failWrite(fos);
+        }
+    }
+
     /**
      * Mark the app as used and update the bucket if necessary. If there is a expiry time specified
      * that's in the future, then the usage event is temporary and keeps the app in the specified
@@ -694,10 +750,13 @@
         return appUsageHistory.bucketExpiryTimesMs.get(bucket, 0);
     }
 
+    private File getUserDirectory(int userId) {
+        return new File(new File(mStorageDir, "users"), Integer.toString(userId));
+    }
+
     @VisibleForTesting
     File getUserFile(int userId) {
-        return new File(new File(new File(mStorageDir, "users"),
-                Integer.toString(userId)), APP_IDLE_FILENAME);
+        return new File(getUserDirectory(userId), APP_IDLE_FILENAME);
     }
 
     void clearLastUsedTimestamps(String packageName, int userId) {
diff --git a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
index ab8131b..b87b5ce 100644
--- a/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
+++ b/apex/jobscheduler/service/java/com/android/server/usage/AppStandbyController.java
@@ -1706,10 +1706,18 @@
             restoreAppToRare(packageName, userId, nowElapsed, reason);
         }
         // Clear out the list of restored apps that need to have their standby buckets adjusted
-        // if they still haven't been installed eight hours after restore.
-        // Note: if the device reboots within these first 8 hours, this list will be lost since it's
-        // not persisted - this is the expected behavior for now and may be updated in the future.
-        mHandler.postDelayed(() -> mAppsToRestoreToRare.remove(userId), 8 * ONE_HOUR);
+        // if they still haven't been installed two days after initial restore.
+        final long delayMillis = Flags.persistRestoreToRareAppsList()
+                ? AppIdleHistory.RESTORE_TO_RARE_APPS_LIST_EXPIRY : 8 * ONE_HOUR;
+        mHandler.postDelayed(() -> mAppsToRestoreToRare.remove(userId), delayMillis);
+
+        // Persist the file in case the device reboots within 2 days after the initial restore.
+        if (Flags.persistRestoreToRareAppsList()) {
+            synchronized (mAppIdleLock) {
+                mAppIdleHistory.writeRestoreToRareAppsList(
+                        userId, mAppsToRestoreToRare.get(userId));
+            }
+        }
     }
 
     /** Adjust the standby bucket of the given package for the user to RARE. */
@@ -2272,6 +2280,22 @@
                 } else if (!Intent.ACTION_PACKAGE_ADDED.equals(action)) {
                     clearAppIdleForPackage(pkgName, userId);
                 } else {
+                    // Do a lazy read of the persisted list, if necessary.
+                    if (Flags.persistRestoreToRareAppsList()
+                            && mAppsToRestoreToRare.get(userId) == null) {
+                        synchronized (mAppIdleLock) {
+                            final ArraySet<String> restoredApps =
+                                    mAppIdleHistory.readRestoreToRareAppsList(userId);
+                            if (restoredApps != null) {
+                                mAppsToRestoreToRare.addAll(userId, restoredApps);
+                                // Clear out the list of restored apps if they still haven't been
+                                // installed in two days - at worst, we are allowing for up to
+                                // 4 days for reinstallation (device reboots just before 2 days)
+                                mHandler.postDelayed(() -> mAppsToRestoreToRare.remove(userId),
+                                        AppIdleHistory.RESTORE_TO_RARE_APPS_LIST_EXPIRY);
+                            }
+                        }
+                    }
                     // Package was just added and it's not being replaced.
                     if (mAppsToRestoreToRare.contains(userId, pkgName)) {
                         restoreAppToRare(pkgName, userId, mInjector.elapsedRealtime(),
@@ -2454,6 +2478,8 @@
                 + ": " + Flags.avoidIdleCheck());
         pw.println("    " + Flags.FLAG_ADJUST_DEFAULT_BUCKET_ELEVATION_PARAMS
                 + ": " + Flags.adjustDefaultBucketElevationParams());
+        pw.println("    " + Flags.FLAG_PERSIST_RESTORE_TO_RARE_APPS_LIST
+                + ": " + Flags.persistRestoreToRareAppsList());
         pw.println();
 
         synchronized (mCarrierPrivilegedLock) {
diff --git a/cmds/bootanimation/BootAnimation.cpp b/cmds/bootanimation/BootAnimation.cpp
index 844e52c..b0070c5 100644
--- a/cmds/bootanimation/BootAnimation.cpp
+++ b/cmds/bootanimation/BootAnimation.cpp
@@ -207,7 +207,7 @@
         : Thread(false), mLooper(new Looper(false)), mClockEnabled(true), mTimeIsAccurate(false),
         mTimeFormat12Hour(false), mTimeCheckThread(nullptr), mCallbacks(callbacks) {
     ATRACE_CALL();
-    mSession = new SurfaceComposerClient();
+    mSession = sp<SurfaceComposerClient>::make();
 
     std::string powerCtl = android::base::GetProperty("sys.powerctl", "");
     if (powerCtl.empty()) {
diff --git a/core/api/current.txt b/core/api/current.txt
index 3da5a5c..7bc0fb2 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -56108,6 +56108,17 @@
     method @NonNull public android.view.WindowInsets getWindowInsets();
   }
 
+  @FlaggedApi("android.xr.xr_manifest_entries") public final class XrWindowProperties {
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String PROPERTY_XR_ACTIVITY_START_MODE = "android.window.PROPERTY_XR_ACTIVITY_START_MODE";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED = "android.window.PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED = "XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED = "XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_ACTIVITY_START_MODE_HOME_SPACE = "XR_ACTIVITY_START_MODE_HOME_SPACE";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_ACTIVITY_START_MODE_UNDEFINED = "XR_ACTIVITY_START_MODE_UNDEFINED";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_BOUNDARY_TYPE_LARGE = "XR_BOUNDARY_TYPE_LARGE";
+    field @FlaggedApi("android.xr.xr_manifest_entries") public static final String XR_BOUNDARY_TYPE_NO_RECOMMENDATION = "XR_BOUNDARY_TYPE_NO_RECOMMENDATION";
+  }
+
 }
 
 package android.view.accessibility {
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 00ec48b..d651010 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -3031,6 +3031,7 @@
     field public static final String DISABLED_PRINT_SERVICES = "disabled_print_services";
     field @Deprecated public static final String ENABLED_NOTIFICATION_POLICY_ACCESS_PACKAGES = "enabled_notification_policy_access_packages";
     field public static final String ENABLED_VR_LISTENERS = "enabled_vr_listeners";
+    field public static final String GLANCEABLE_HUB_ENABLED = "glanceable_hub_enabled";
     field public static final String IMMERSIVE_MODE_CONFIRMATIONS = "immersive_mode_confirmations";
     field public static final String NOTIFICATION_BADGING = "notification_badging";
     field public static final String NOTIFICATION_BUBBLES = "notification_bubbles";
diff --git a/core/java/Android.bp b/core/java/Android.bp
index 1ad247e..980d973 100644
--- a/core/java/Android.bp
+++ b/core/java/Android.bp
@@ -29,6 +29,15 @@
         "android/os/*MessageQueue/**/*.java",
         "android/ranging/**/*.java",
         ":dynamic_instrumentation_manager_aidl_sources",
+        "**/*_ravenwood.java",
+    ],
+    visibility: ["//frameworks/base"],
+}
+
+filegroup {
+    name: "framework-ravenwood-sources",
+    srcs: [
+        "**/*_ravenwood.java",
     ],
     visibility: ["//frameworks/base"],
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index b4f6533..d5df48a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -10060,9 +10060,11 @@
                     }
                 });
                 if (mJankTracker == null) {
-                    // TODO b/377960907 use the Choreographer attached to the ViewRootImpl instead.
-                    mJankTracker = new JankTracker(Choreographer.getInstance(),
-                            decorView);
+                    if (android.app.jank.Flags.viewrootChoreographer()) {
+                        mJankTracker = new JankTracker(decorView);
+                    } else {
+                        mJankTracker = new JankTracker(Choreographer.getInstance(), decorView);
+                    }
                 }
                 // TODO b/377674765 confirm this is the string we want logged.
                 mJankTracker.setActivityName(getComponentName().getClassName());
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index f9ec214..b38f5da 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -4975,6 +4975,25 @@
     }
 
     /**
+     * Fully stop the given app's processes without restoring service starts or
+     * bindings, but without the other durable effects of the full-scale
+     * "force stop" intervention.
+     *
+     * @param packageName The name of the package to be stopped.
+     *
+     * @hide This is not available to third party applications due to
+     * it allowing them to break other applications by stopping their
+     * services.
+     */
+    public void stopPackageForUser(String packageName) {
+        try {
+            getService().stopAppForUser(packageName, mContext.getUserId());
+        } catch (RemoteException e) {
+            throw e.rethrowFromSystemServer();
+        }
+    }
+
+    /**
      * Sets the current locales of the device. Calling app must have the permission
      * {@code android.permission.CHANGE_CONFIGURATION} and
      * {@code android.permission.WRITE_SETTINGS}.
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index c765298..2c1df73 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1137,12 +1137,19 @@
                 CompatibilityInfo compatInfo, int resultCode, String data, Bundle extras,
                 boolean ordered, boolean assumeDelivered, int sendingUser, int processState,
                 int sendingUid, String sendingPackage) {
+            long debugStoreId = -1;
+            if (DEBUG_STORE_ENABLED) {
+                debugStoreId = DebugStore.recordScheduleReceiver();
+            }
             updateProcessState(processState, false);
             ReceiverData r = new ReceiverData(intent, resultCode, data, extras,
                     ordered, false, assumeDelivered, mAppThread.asBinder(), sendingUser,
                     sendingUid, sendingPackage);
             r.info = info;
             sendMessage(H.RECEIVER, r);
+            if (DEBUG_STORE_ENABLED) {
+                DebugStore.recordEventEnd(debugStoreId);
+            }
         }
 
         public final void scheduleReceiverList(List<ReceiverInfo> info) throws RemoteException {
@@ -1490,6 +1497,10 @@
                 boolean sticky, boolean assumeDelivered, int sendingUser, int processState,
                 int sendingUid, String sendingPackage)
                 throws RemoteException {
+            long debugStoreId = -1;
+            if (DEBUG_STORE_ENABLED) {
+                debugStoreId = DebugStore.recordScheduleRegisteredReceiver();
+            }
             updateProcessState(processState, false);
 
             // We can't modify IIntentReceiver due to UnsupportedAppUsage, so
@@ -1514,6 +1525,9 @@
                 receiver.performReceive(intent, resultCode, dataStr, extras, ordered, sticky,
                         sendingUser);
             }
+            if (DEBUG_STORE_ENABLED) {
+                DebugStore.recordEventEnd(debugStoreId);
+            }
         }
 
         @Override
@@ -2505,8 +2519,15 @@
             switch (msg.what) {
                 case BIND_APPLICATION:
                     Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER, "bindApplication");
+                    if (DEBUG_STORE_ENABLED) {
+                        debugStoreId =
+                                DebugStore.recordHandleBindApplication();
+                    }
                     AppBindData data = (AppBindData)msg.obj;
                     handleBindApplication(data);
+                    if (DEBUG_STORE_ENABLED) {
+                        DebugStore.recordEventEnd(debugStoreId);
+                    }
                     Trace.traceEnd(Trace.TRACE_TAG_ACTIVITY_MANAGER);
                     break;
                 case EXIT_APPLICATION:
@@ -2529,7 +2550,8 @@
                     ReceiverData receiverData = (ReceiverData) msg.obj;
                     if (DEBUG_STORE_ENABLED) {
                         debugStoreId =
-                                DebugStore.recordBroadcastHandleReceiver(receiverData.intent);
+                            DebugStore.recordBroadcastReceive(
+                                receiverData.intent, System.identityHashCode(receiverData));
                     }
 
                     try {
@@ -7340,16 +7362,6 @@
         }
 
         WindowManagerGlobal.getInstance().trimMemory(level);
-
-        if (SystemProperties.getInt("debug.am.run_gc_trim_level", Integer.MAX_VALUE) <= level) {
-            unscheduleGcIdler();
-            doGcIfNeeded("tm");
-        }
-        if (SystemProperties.getInt("debug.am.run_mallopt_trim_level", Integer.MAX_VALUE)
-                <= level) {
-            unschedulePurgeIdler();
-            purgePendingResources();
-        }
     }
 
     private void setupGraphicsSupport(Context context) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index dc5974f..7e5c0fb 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2944,7 +2944,11 @@
 
     private void updateResourceOverlayConstraints() {
         if (mResources != null) {
-            mResources.getAssets().setOverlayConstraints(getDisplayId(), getDeviceId());
+            // Avoid calling getDisplay() here, as it makes a binder call into
+            // DisplayManagerService if the relevant DisplayInfo is not cached in
+            // DisplayManagerGlobal.
+            int displayId = mDisplay != null ? mDisplay.getDisplayId() : Display.DEFAULT_DISPLAY;
+            mResources.getAssets().setOverlayConstraints(displayId, getDeviceId());
         }
     }
 
diff --git a/core/java/android/app/LoadedApk.java b/core/java/android/app/LoadedApk.java
index ffd235f..d0949ad 100644
--- a/core/java/android/app/LoadedApk.java
+++ b/core/java/android/app/LoadedApk.java
@@ -61,6 +61,7 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.os.DebugStore;
 import com.android.internal.util.ArrayUtils;
 
 import dalvik.system.BaseDexClassLoader;
@@ -107,6 +108,9 @@
     static final String TAG = "LoadedApk";
     static final boolean DEBUG = false;
 
+    private static final boolean DEBUG_STORE_ENABLED =
+            com.android.internal.os.Flags.debugStoreEnabled();
+
     @UnsupportedAppUsage
     private final ActivityThread mActivityThread;
     @UnsupportedAppUsage
@@ -1816,6 +1820,12 @@
                         Trace.traceBegin(Trace.TRACE_TAG_ACTIVITY_MANAGER,
                                 "broadcastReceiveReg: " + intent.getAction());
                     }
+                    long debugStoreId = -1;
+                    if (DEBUG_STORE_ENABLED) {
+                        debugStoreId =
+                                DebugStore.recordBroadcastReceiveReg(
+                                        intent, System.identityHashCode(this));
+                    }
 
                     try {
                         ClassLoader cl = mReceiver.getClass().getClassLoader();
@@ -1838,6 +1848,10 @@
                                     "Error receiving broadcast " + intent
                                             + " in " + mReceiver, e);
                         }
+                    } finally {
+                        if (DEBUG_STORE_ENABLED) {
+                            DebugStore.recordEventEnd(debugStoreId);
+                        }
                     }
 
                     if (receiver.getPendingResult() != null) {
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index cc72d8f..8d4925d 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -3266,7 +3266,6 @@
         final Class<? extends Style> notificationStyle = getNotificationStyle();
 
         return notificationStyle == null
-                || BigPictureStyle.class.equals(notificationStyle)
                 || BigTextStyle.class.equals(notificationStyle)
                 || CallStyle.class.equals(notificationStyle)
                 || ProgressStyle.class.equals(notificationStyle);
diff --git a/core/java/android/app/admin/DeviceAdminInfo.java b/core/java/android/app/admin/DeviceAdminInfo.java
index cb2b8ad..8a8877f 100644
--- a/core/java/android/app/admin/DeviceAdminInfo.java
+++ b/core/java/android/app/admin/DeviceAdminInfo.java
@@ -558,6 +558,11 @@
     }
 
     public void dump(Printer pw, String prefix) {
+        pw.println("mVisible: " + mVisible);
+        pw.println("mUsesPolicies: " + mUsesPolicies);
+        pw.println("mSupportsTransferOwnership: " + mSupportsTransferOwnership);
+        pw.println("mHeadlessDeviceOwnerMode: " + mHeadlessDeviceOwnerMode);
+
         pw.println(prefix + "Receiver:");
         mActivityInfo.dump(pw, prefix + "  ");
     }
diff --git a/core/java/android/app/jank/JankTracker.java b/core/java/android/app/jank/JankTracker.java
index 9c85b09..e3f6781 100644
--- a/core/java/android/app/jank/JankTracker.java
+++ b/core/java/android/app/jank/JankTracker.java
@@ -25,6 +25,7 @@
 import android.view.Choreographer;
 import android.view.SurfaceControl;
 import android.view.View;
+import android.view.ViewRootImpl;
 import android.view.ViewTreeObserver;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -100,7 +101,7 @@
                         public void run() {
                             mDecorView.getViewTreeObserver()
                                     .removeOnWindowAttachListener(mOnWindowAttachListener);
-                            registerForJankData();
+                            initializeJankTrackingComponents();
                         }
                     }, REGISTRATION_DELAY_MS);
                 }
@@ -115,6 +116,7 @@
                 }
             };
 
+    // TODO remove this once the viewroot_choreographer bugfix has been rolled out. b/399724640
     public JankTracker(Choreographer choreographer, View decorView) {
         mStateTracker = new StateTracker(choreographer);
         mJankDataProcessor = new JankDataProcessor(mStateTracker);
@@ -124,6 +126,19 @@
     }
 
     /**
+     * Using this constructor delays the instantiation of the StateTracker and JankDataProcessor
+     * until after the OnWindowAttachListener is fired and the instance of Choreographer attached to
+     * the ViewRootImpl can be passed to StateTracker. This should ensures the vsync ids we are
+     * using to keep track of active states line up with the ids that are being returned by
+     * OnJankDataListener.
+     */
+    public JankTracker(View decorView) {
+        mDecorView = decorView;
+        mHandlerThread.start();
+        registerWindowListeners();
+    }
+
+    /**
      * Merges app jank stats reported by components outside the platform to the current pending
      * stats
      */
@@ -131,6 +146,9 @@
         getHandler().post(new Runnable() {
             @Override
             public void run() {
+                if (mJankDataProcessor == null) {
+                    return;
+                }
                 mJankDataProcessor.mergeJankStats(appJankStats, mActivityName);
             }
         });
@@ -192,8 +210,7 @@
     public void enableAppJankTracking() {
         // Add the activity as a state, this will ensure we track frames to the activity without the
         // need for a decorated widget to be used.
-        // TODO b/376116199 replace "NONE" with UNSPECIFIED once the API changes are merged.
-        mStateTracker.putState("NONE", mActivityName, "NONE");
+        addActivityToStateTracking();
         mTrackingEnabled = true;
         registerForJankData();
     }
@@ -203,27 +220,33 @@
      */
     public void disableAppJankTracking() {
         mTrackingEnabled = false;
-        // TODO b/376116199 replace "NONE" with UNSPECIFIED once the API changes are merged.
-        mStateTracker.removeState("NONE", mActivityName, "NONE");
+        removeActivityFromStateTracking();
         unregisterForJankData();
     }
 
     /**
-     * Retrieve all pending widget states, this is intended for testing purposes only.
+     * Retrieve all pending widget states, this is intended for testing purposes only. If
+     * this is called before StateTracker has been created the method will just return without
+     * copying any data to the stateDataList parameter.
      *
      * @param stateDataList the ArrayList that will be populated with the pending states.
      */
     @VisibleForTesting
     public void getAllUiStates(@NonNull ArrayList<StateTracker.StateData> stateDataList) {
+        if (mStateTracker == null) return;
         mStateTracker.retrieveAllStates(stateDataList);
     }
 
     /**
      * Retrieve all pending jank stats before they are logged, this is intended for testing
-     * purposes only.
+     * purposes only. If this method is called before JankDataProcessor is created it will return
+     * an empty HashMap.
      */
     @VisibleForTesting
     public HashMap<String, JankDataProcessor.PendingJankStat> getPendingJankStats() {
+        if (mJankDataProcessor == null) {
+            return new HashMap<>();
+        }
         return mJankDataProcessor.getPendingJankStats();
     }
 
@@ -233,8 +256,10 @@
      */
     @VisibleForTesting
     public void forceListenerRegistration() {
+        addActivityToStateTracking();
         mSurfaceControl = mDecorView.getRootSurfaceControl();
         registerJankDataListener();
+        mListenersRegistered = true;
     }
 
     private void unregisterForJankData() {
@@ -270,6 +295,10 @@
      */
     @VisibleForTesting
     public boolean shouldTrack() {
+        if (DEBUG) {
+            Log.d(DEBUG_KEY, String.format("mTrackingEnabled: %s | mListenersRegistered: %s",
+                    mTrackingEnabled, mListenersRegistered));
+        }
         return mTrackingEnabled && mListenersRegistered;
     }
 
@@ -313,4 +342,36 @@
         }
         return mHandler;
     }
+
+    private void addActivityToStateTracking() {
+        if (mStateTracker == null) return;
+
+        mStateTracker.putState(AppJankStats.WIDGET_CATEGORY_UNSPECIFIED, mActivityName,
+                AppJankStats.WIDGET_STATE_UNSPECIFIED);
+    }
+
+    private void removeActivityFromStateTracking() {
+        if (mStateTracker == null) return;
+
+        mStateTracker.removeState(AppJankStats.WIDGET_CATEGORY_UNSPECIFIED, mActivityName,
+                AppJankStats.WIDGET_STATE_UNSPECIFIED);
+    }
+
+    private void initializeJankTrackingComponents() {
+        ViewRootImpl viewRoot = mDecorView.getViewRootImpl();
+        if (viewRoot == null || viewRoot.getChoreographer() == null) {
+            return;
+        }
+
+        if (mStateTracker == null) {
+            mStateTracker = new StateTracker(viewRoot.getChoreographer());
+        }
+
+        if (mJankDataProcessor == null) {
+            mJankDataProcessor = new JankDataProcessor(mStateTracker);
+        }
+
+        addActivityToStateTracking();
+        registerForJankData();
+    }
 }
diff --git a/core/java/android/app/jank/flags.aconfig b/core/java/android/app/jank/flags.aconfig
index a62df1b..de98b88 100644
--- a/core/java/android/app/jank/flags.aconfig
+++ b/core/java/android/app/jank/flags.aconfig
@@ -14,4 +14,14 @@
   namespace: "system_performance"
   description: "Controls whether the system will log frame metrics related to app jank"
   bug: "366265225"
+}
+
+flag {
+  name: "viewroot_choreographer"
+  namespace: "system_performance"
+  description: "when enabled janktracker will get the instance of choreographer from viewrootimpl"
+  bug: "377960907"
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
 }
\ No newline at end of file
diff --git a/core/java/android/app/notification.aconfig b/core/java/android/app/notification.aconfig
index 8e6b88c..5c267c9 100644
--- a/core/java/android/app/notification.aconfig
+++ b/core/java/android/app/notification.aconfig
@@ -255,6 +255,16 @@
 }
 
 flag {
+  name: "redaction_on_lockscreen_metrics"
+  namespace: "systemui"
+  description: "enables metrics when redacting notifications on the lockscreen"
+  bug: "343631648"
+    metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
   name: "api_rich_ongoing"
   is_exported: true
   namespace: "systemui"
diff --git a/core/java/android/companion/virtual/flags/flags.aconfig b/core/java/android/companion/virtual/flags/flags.aconfig
index 0085e4f..4fb3982 100644
--- a/core/java/android/companion/virtual/flags/flags.aconfig
+++ b/core/java/android/companion/virtual/flags/flags.aconfig
@@ -150,3 +150,11 @@
     description: "Settings override for virtual devices"
     bug: "371801645"
 }
+
+flag {
+    namespace: "virtual_devices"
+    name: "viewconfiguration_apis"
+    description: "APIs for settings ViewConfiguration attributes on virtual devices"
+    bug: "370720522"
+    is_exported: true
+}
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index cf68487..357baa3 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -263,7 +263,7 @@
                         1);
             }
             if (DEBUG_STORE_ENABLED) {
-                DebugStore.recordFinish(mReceiverClassName);
+                DebugStore.recordFinish(System.identityHashCode(this));
             }
 
             if (mType == TYPE_COMPONENT) {
@@ -444,7 +444,7 @@
         PendingResult res = mPendingResult;
         mPendingResult = null;
         if (DEBUG_STORE_ENABLED) {
-            DebugStore.recordGoAsync(getClass().getName());
+            DebugStore.recordGoAsync(System.identityHashCode(res));
         }
         if (res != null && Trace.isTagEnabled(Trace.TRACE_TAG_ACTIVITY_MANAGER)) {
             res.mReceiverClassName = getClass().getName();
diff --git a/core/java/android/content/pm/ActivityInfo.java b/core/java/android/content/pm/ActivityInfo.java
index fd59ea9..f61d695 100644
--- a/core/java/android/content/pm/ActivityInfo.java
+++ b/core/java/android/content/pm/ActivityInfo.java
@@ -950,6 +950,8 @@
             CONFIG_COLOR_MODE,
             CONFIG_FONT_SCALE,
             CONFIG_GRAMMATICAL_GENDER,
+            CONFIG_FONT_WEIGHT_ADJUSTMENT,
+            CONFIG_WINDOW_CONFIGURATION,
             CONFIG_ASSETS_PATHS,
             CONFIG_RESOURCES_UNUSED,
     })
diff --git a/core/java/android/database/sqlite/SQLiteConnection.java b/core/java/android/database/sqlite/SQLiteConnection.java
index 75c7e26..e43a5fc 100644
--- a/core/java/android/database/sqlite/SQLiteConnection.java
+++ b/core/java/android/database/sqlite/SQLiteConnection.java
@@ -138,7 +138,7 @@
     private static native long nativeOpen(String path, int openFlags, String label,
             boolean enableTrace, boolean enableProfile, int lookasideSlotSize,
             int lookasideSlotCount);
-    private static native void nativeClose(long connectionPtr);
+    private static native void nativeClose(long connectionPtr, boolean fast);
     private static native void nativeRegisterCustomScalarFunction(long connectionPtr,
             String name, UnaryOperator<String> function);
     private static native void nativeRegisterCustomAggregateFunction(long connectionPtr,
@@ -183,6 +183,11 @@
     private static native long nativeChanges(long connectionPtr);
     private static native long nativeTotalChanges(long connectionPtr);
 
+    // This method is deprecated and should be removed when it is no longer needed by the
+    // robolectric tests.  It should not be called from any frameworks java code.
+    @Deprecated
+    private static native void nativeClose(long connectionPtr);
+
     private SQLiteConnection(SQLiteConnectionPool pool,
             SQLiteDatabaseConfiguration configuration,
             int connectionId, boolean primaryConnection) {
@@ -300,7 +305,7 @@
             final int cookie = mRecentOperations.beginOperation("close", null, null);
             try {
                 mPreparedStatementCache.evictAll();
-                nativeClose(mConnectionPtr);
+                nativeClose(mConnectionPtr, finalized && Flags.noCheckpointOnFinalize());
                 mConnectionPtr = 0;
             } finally {
                 mRecentOperations.endOperation(cookie);
diff --git a/core/java/android/database/sqlite/flags.aconfig b/core/java/android/database/sqlite/flags.aconfig
index 1d17a51..9f4f1a1 100644
--- a/core/java/android/database/sqlite/flags.aconfig
+++ b/core/java/android/database/sqlite/flags.aconfig
@@ -5,7 +5,7 @@
      name: "oneway_finalizer_close_fixed"
      namespace: "system_performance"
      is_fixed_read_only: true
-     description: "Make BuildCursorNative.close oneway if in the the finalizer"
+     description: "Make BuildCursorNative.close oneway if in the finalizer"
      bug: "368221351"
 }
 
@@ -26,3 +26,10 @@
      description: "Make SQLiteOpenHelper thread-safe"
      bug: "335904370"
 }
+
+flag {
+     name: "no_checkpoint_on_finalize"
+     namespace: "system_performance"
+     description: "Do not checkpoint WAL if closing in the finalizer"
+     bug: "397982577"
+}
diff --git a/core/java/android/hardware/display/DisplayManagerInternal.java b/core/java/android/hardware/display/DisplayManagerInternal.java
index 343e4b5..0c8a9ed 100644
--- a/core/java/android/hardware/display/DisplayManagerInternal.java
+++ b/core/java/android/hardware/display/DisplayManagerInternal.java
@@ -476,6 +476,16 @@
     public abstract boolean isDisplayReadyForMirroring(int displayId);
 
     /**
+     * Called by {@link com.android.server.wm.WindowManagerService} to notify whether a display
+     * should be in the topology.
+     * @param displayId The logical ID of the display
+     * @param inTopology Whether the display should be in the topology. This being true does not
+     *                   guarantee that the display will be in the topology - Display Manager might
+     *                   also check other parameters.
+     */
+    public abstract void onDisplayBelongToTopologyChanged(int displayId, boolean inTopology);
+
+    /**
      * Called by {@link  com.android.server.display.DisplayBackupHelper} when backup files were
      * restored and are ready to be reloaded.
      */
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/core/java/android/hardware/usb/IUsbManagerInternal.aidl
similarity index 63%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to core/java/android/hardware/usb/IUsbManagerInternal.aidl
index 9b7cd70..32479d4 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/core/java/android/hardware/usb/IUsbManagerInternal.aidl
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,8 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package android.hardware.usb;
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import android.hardware.usb.IUsbOperationInternal;
+
+/** @hide */
+interface IUsbManagerInternal {
+
+    /* Disable/enable USB data on a port for System Service callers. */
+    boolean enableUsbDataSignal(boolean enable, int disableReason);
+}
diff --git a/core/java/android/inputmethodservice/InputMethodService.java b/core/java/android/inputmethodservice/InputMethodService.java
index 7b47efd4..894b068 100644
--- a/core/java/android/inputmethodservice/InputMethodService.java
+++ b/core/java/android/inputmethodservice/InputMethodService.java
@@ -527,22 +527,13 @@
     public static final int IME_ACTIVE = 1 << 0;
 
     /**
-     * The IME is perceptibly visible to the user.
+     * The IME is visible.
      *
      * @hide
      */
     public static final int IME_VISIBLE = 1 << 1;
 
     /**
-     * The IME is visible, but not yet perceptible to the user (e.g. fading in)
-     * by {@link android.view.WindowInsetsController}.
-     *
-     * @see InputMethodManager#reportPerceptible
-     * @hide
-     */
-    public static final int IME_VISIBLE_IMPERCEPTIBLE = 1 << 2;
-
-    /**
      * The IME window visibility state.
      *
      * @hide
@@ -550,7 +541,6 @@
     @IntDef(flag = true, prefix = { "IME_" }, value = {
             IME_ACTIVE,
             IME_VISIBLE,
-            IME_VISIBLE_IMPERCEPTIBLE,
     })
     public @interface ImeWindowVisibility {}
 
diff --git a/core/java/android/os/CombinedMessageQueue/MessageQueue.java b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
index ce1717b..0964cde 100644
--- a/core/java/android/os/CombinedMessageQueue/MessageQueue.java
+++ b/core/java/android/os/CombinedMessageQueue/MessageQueue.java
@@ -76,8 +76,13 @@
     @SuppressWarnings("unused")
     private long mPtr; // used by native code
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(
+            maxTargetSdk = Build.VERSION_CODES.BAKLAVA,
+            publicAlternatives =
+                    "To manipulate the queue in Instrumentation tests, use {@link"
+                        + " android.os.TestLooperManager}")
     Message mMessages;
+
     private Message mLast;
     @UnsupportedAppUsage
     private final ArrayList<IdleHandler> mIdleHandlers = new ArrayList<IdleHandler>();
@@ -139,8 +144,8 @@
             return;
         }
 
-        if (RavenwoodEnvironment.getInstance().isRunningOnRavenwood()) {
-            sIsProcessAllowedToUseConcurrent = false;
+        if (Flags.forceConcurrentMessageQueue()) {
+            sIsProcessAllowedToUseConcurrent = true;
             return;
         }
 
@@ -995,7 +1000,11 @@
         }
     }
 
-    @UnsupportedAppUsage
+    @UnsupportedAppUsage(
+            maxTargetSdk = Build.VERSION_CODES.BAKLAVA,
+            publicAlternatives =
+                    "To manipulate the queue in Instrumentation tests, use {@link"
+                        + " android.os.TestLooperManager}")
     Message next() {
         if (mUseConcurrent) {
             return nextConcurrent();
diff --git a/core/java/android/os/ExternalVibration.java b/core/java/android/os/ExternalVibration.java
index 3aad0fd..70a17ab 100644
--- a/core/java/android/os/ExternalVibration.java
+++ b/core/java/android/os/ExternalVibration.java
@@ -87,8 +87,12 @@
         int capturePreset = in.readInt();
         int flags = in.readInt();
         AudioAttributes.Builder builder = new AudioAttributes.Builder();
-        return builder.setUsage(usage)
-                .setContentType(contentType)
+        if (AudioAttributes.isSystemUsage(usage)) {
+            builder.setSystemUsage(usage);
+        } else {
+            builder.setUsage(usage);
+        }
+        return builder.setContentType(contentType)
                 .setCapturePreset(capturePreset)
                 .setFlags(flags)
                 .build();
@@ -196,7 +200,9 @@
     }
 
     private static void writeAudioAttributes(AudioAttributes attrs, Parcel out) {
-        out.writeInt(attrs.getUsage());
+        // Since we allow audio system usages, must use getSystemUsage() instead of getUsage() for
+        // all usages.
+        out.writeInt(attrs.getSystemUsage());
         out.writeInt(attrs.getContentType());
         out.writeInt(attrs.getCapturePreset());
         out.writeInt(attrs.getAllFlags());
diff --git a/core/java/android/os/PerfettoTrackEventExtra.java b/core/java/android/os/PerfettoTrackEventExtra.java
index 8a3a5be..07b44a8 100644
--- a/core/java/android/os/PerfettoTrackEventExtra.java
+++ b/core/java/android/os/PerfettoTrackEventExtra.java
@@ -674,6 +674,7 @@
     /**
      * Resets the track event extra.
      */
+    @android.ravenwood.annotation.RavenwoodReplace
     public void reset() {
         native_clear_args(mPtr);
         mPendingPointers.clear();
@@ -1303,4 +1304,8 @@
         // Tracing currently completely disabled under Ravenwood
         return null;
     }
+
+    private void reset$ravenwood() {
+        // Tracing currently completely disabled under Ravenwood
+    }
 }
diff --git a/core/java/android/os/Process.java b/core/java/android/os/Process.java
index 0c5d9e97..b68b9a7 100644
--- a/core/java/android/os/Process.java
+++ b/core/java/android/os/Process.java
@@ -1347,6 +1347,7 @@
      * Return the name of this process. By default, the process name is the same as the app's
      * package name, but this can be changed using {@code android:process}.
      */
+    @RavenwoodReplace
     @NonNull
     public static String myProcessName() {
         // Note this could be different from the actual process name if someone changes the
@@ -1355,6 +1356,12 @@
         return sArgV0;
     }
 
+    /** @hide */
+    @NonNull
+    public static String myProcessName$ravenwood() {
+        return "ravenwood";
+    }
+
     /**
      * Kill the process with the given PID.
      * Note that, though this API allows us to request to
diff --git a/core/java/android/os/flags.aconfig b/core/java/android/os/flags.aconfig
index d3c677b..86acb2b 100644
--- a/core/java/android/os/flags.aconfig
+++ b/core/java/android/os/flags.aconfig
@@ -211,6 +211,14 @@
 }
 
 flag {
+     name: "force_concurrent_message_queue"
+     namespace: "system_performance"
+     is_exported: true
+     description: "Whether MessageQueue uses the new concurrent implementation"
+     bug: "336880969"
+}
+
+flag {
     name: "get_private_space_settings"
     namespace: "profile_experiences"
     description: "Guards a new Private Profile API in LauncherApps"
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index ca24c0c..0476f62 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -358,7 +358,16 @@
     is_fixed_read_only: true
     is_exported: true
     namespace: "permissions"
-    description: "Enables SQlite for recording discrete and historical AppOp accesses"
+    description: "Enables SQlite for recording individual/discrete AppOp accesses"
+    bug: "377584611"
+}
+
+flag {
+    name: "enable_all_sqlite_appops_accesses"
+    is_fixed_read_only: true
+    is_exported: true
+    namespace: "permissions"
+    description: "Enables SQlite for storing aggregated & individual/discrete AppOp accesses"
     bug: "377584611"
 }
 
diff --git a/core/java/android/preference/PreferenceScreen.java b/core/java/android/preference/PreferenceScreen.java
index 6b813b0..9654851 100644
--- a/core/java/android/preference/PreferenceScreen.java
+++ b/core/java/android/preference/PreferenceScreen.java
@@ -109,6 +109,7 @@
     private int mLayoutResId = com.android.internal.R.layout.preference_list_fragment;
     private Drawable mDividerDrawable;
     private boolean mDividerSpecified;
+    private boolean mDialogFitsSystemWindows = false;
 
     /**
      * Do NOT use this constructor, use {@link PreferenceManager#createPreferenceScreen(Context)}.
@@ -136,6 +137,18 @@
     }
 
     /**
+     * Used in {@link #onClick()} to override the {@link View#setFitsSystemWindows(boolean)} for
+     * the dialog that shows.  This is set separately to limit the scope of this change to just
+     * the {@link PreferenceScreen} instances which have demonstrated an issue with edge to edge.
+     *
+     * @param dialogFitsSystemWindows value passed to {@link View#setFitsSystemWindows(boolean)}.
+     * @hide
+     */
+    public void setDialogFitsSystemWindows(boolean dialogFitsSystemWindows) {
+        mDialogFitsSystemWindows = dialogFitsSystemWindows;
+    }
+
+    /**
      * Returns an adapter that can be attached to a {@link PreferenceActivity}
      * or {@link PreferenceFragment} to show the preferences contained in this
      * {@link PreferenceScreen}.
@@ -201,6 +214,11 @@
         View childPrefScreen = inflater.inflate(mLayoutResId, null);
         View titleView = childPrefScreen.findViewById(android.R.id.title);
         mListView = (ListView) childPrefScreen.findViewById(android.R.id.list);
+        // Don't override any potential state that may exist on mListView.  If it was already marked
+        // as "setFitsSystemWindows(true)" somewhere else don't change to "false" here.
+        if (mDialogFitsSystemWindows) {
+            mListView.setFitsSystemWindows(true);
+        }
         if (mDividerSpecified) {
             mListView.setDivider(mDividerDrawable);
         }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 1210790..b97c9b5 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -9465,24 +9465,6 @@
                 "reduce_bright_colors_persist_across_reboots";
 
         /**
-         * Setting that specifies whether Even Dimmer - a feature that allows the brightness
-         * slider to go below what the display can conventionally do, should be enabled.
-         *
-         * @hide
-         */
-        public static final String EVEN_DIMMER_ACTIVATED =
-                "even_dimmer_activated";
-
-        /**
-         * Setting that specifies which nits level Even Dimmer should allow the screen brightness
-         * to go down to.
-         *
-         * @hide
-         */
-        public static final String EVEN_DIMMER_MIN_NITS =
-                "even_dimmer_min_nits";
-
-        /**
          * Setting that holds EM_VALUE (proprietary)
          *
          * @hide
@@ -10601,6 +10583,9 @@
          *
          * @hide
          */
+        @TestApi
+        @Readable
+        @SuppressLint({"UnflaggedApi", "NoSettingsProvider"}) // @TestApi purely for CTS support.
         public static final String GLANCEABLE_HUB_ENABLED = "glanceable_hub_enabled";
 
         /**
diff --git a/core/java/android/provider/Telephony.java b/core/java/android/provider/Telephony.java
index f7f4eec..7d70876 100644
--- a/core/java/android/provider/Telephony.java
+++ b/core/java/android/provider/Telephony.java
@@ -4988,6 +4988,66 @@
         public static final String COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM =
                 "is_satellite_provisioned_for_non_ip_datagram";
 
+        /**
+         * TelephonyProvider column name for satellite entitlement barred plmns list separated by
+         * comma [,]. The value of this column is set based on entitlement query result for
+         * satellite configuration. Ex : 31026,302820,40445
+         * By default, it's empty.
+         *
+         * @hide
+         */
+        public static final String COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS =
+                "satellite_entitlement_barred_plmns";
+
+
+        /**
+         * TelephonyProvider column name for satellite entitlement data plan for plmns which is
+         * built in Json format in Key:Value pair. The value  of this column is set based on
+         * entitlement query result for satellite configuration.
+         * Ex : {"302820":0,"31026":1, "40445":0}
+         * By default, it's empty.
+         *
+         * @hide
+         */
+        public static final String COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS =
+                "satellite_entitlement_data_plan_plmns";
+
+        /**
+         * TelephonyProvider column name for satellite entitlement service type map which is
+         * built in Json format in Key:Value pair. The value of this column is set based on
+         * entitlement query result for satellite configuration.
+         * Ex : {"302820":[1,3],"31026":[2,3],"40445":[1,3]}
+         * By default, it's empty.
+         *
+         * @hide
+         */
+        public static final String COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP =
+                "satellite_entitlement_service_type_map";
+
+        /**
+         * TelephonyProvider column name for satellite entitlement data service policy type map
+         * which is built in Json format in Key:Value pair. The value of this column is set based
+         * on entitlement query result for satellite configuration.
+         * Ex : {"302820":2, "31026":1}
+         * By default, it's empty.
+         *
+         * @hide
+         */
+        public static final String COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY =
+                "satellite_entitlement_data_service_policy";
+
+        /**
+         * TelephonyProvider column name for satellite entitlement voice service policy  type map
+         * which is built in Json format in Key:Value pair. The value of this column is set
+         * based on entitlement query result for satellite configuration.
+         * Ex : {"302820":2, "31026":1}.
+         * By default, it's empty.
+         *
+         * @hide
+         */
+        public static final String COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY =
+                "satellite_entitlement_voice_service_policy";
+
         /** All columns in {@link SimInfo} table. */
         private static final List<String> ALL_COLUMNS = List.of(
                 COLUMN_UNIQUE_KEY_SUBSCRIPTION_ID,
@@ -5065,7 +5125,12 @@
                 COLUMN_SATELLITE_ENTITLEMENT_STATUS,
                 COLUMN_SATELLITE_ENTITLEMENT_PLMNS,
                 COLUMN_SATELLITE_ESOS_SUPPORTED,
-                COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM
+                COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM,
+                COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS,
+                COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS,
+                COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP,
+                COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY,
+                COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY
         );
 
         /**
diff --git a/core/java/android/security/flags.aconfig b/core/java/android/security/flags.aconfig
index 3a3ea18..7013f7d 100644
--- a/core/java/android/security/flags.aconfig
+++ b/core/java/android/security/flags.aconfig
@@ -52,13 +52,6 @@
 }
 
 flag {
-    name: "deprecate_fsv_sig"
-    namespace: "hardware_backed_security"
-    description: "Feature flag for deprecating .fsv_sig"
-    bug: "277916185"
-}
-
-flag {
     name: "extend_vb_chain_to_updated_apk"
     namespace: "hardware_backed_security"
     description: "Use v4 signature and fs-verity to chain verification of allowlisted APKs to Verified Boot"
diff --git a/core/java/android/service/notification/Adjustment.java b/core/java/android/service/notification/Adjustment.java
index 505db30..772fd96 100644
--- a/core/java/android/service/notification/Adjustment.java
+++ b/core/java/android/service/notification/Adjustment.java
@@ -225,7 +225,7 @@
     public static final int TYPE_CONTENT_RECOMMENDATION = 4;
 
     /**
-     * Data type: String, a summarization of the text of the notification, or, if provided for
+     * Data type: CharSequence, a summarization of the text of the notification, or, if provided for
      * a group summary, a summarization of the text of all of the notificatrions in the group.
      * Send this key with a null value to remove an existing summarization.
      */
diff --git a/core/java/android/view/ImeBackAnimationController.java b/core/java/android/view/ImeBackAnimationController.java
index 19e0913..c39456a 100644
--- a/core/java/android/view/ImeBackAnimationController.java
+++ b/core/java/android/view/ImeBackAnimationController.java
@@ -16,7 +16,11 @@
 
 package android.view;
 
+import static android.view.InsetsController.ANIMATION_DURATION_SYNC_IME_MS;
+import static android.view.InsetsController.ANIMATION_DURATION_UNSYNC_IME_MS;
 import static android.view.InsetsController.ANIMATION_TYPE_USER;
+import static android.view.InsetsController.FAST_OUT_LINEAR_IN_INTERPOLATOR;
+import static android.view.InsetsController.SYNC_IME_INTERPOLATOR;
 import static android.view.WindowInsets.Type.ime;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN;
 import static android.view.WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE;
@@ -56,8 +60,6 @@
     private static final Interpolator BACK_GESTURE = new BackGestureInterpolator();
     private static final Interpolator EMPHASIZED_DECELERATE = new PathInterpolator(
             0.05f, 0.7f, 0.1f, 1f);
-    private static final Interpolator STANDARD_ACCELERATE = new PathInterpolator(0.3f, 0f, 1f, 1f);
-
     private final InsetsController mInsetsController;
     private final ViewRootImpl mViewRoot;
     private WindowInsetsAnimationController mWindowInsetsAnimationController = null;
@@ -183,8 +185,21 @@
         float targetProgress = triggerBack ? 1f : 0f;
         mPostCommitAnimator = ValueAnimator.ofFloat(
                 BACK_GESTURE.getInterpolation(mLastProgress) * PEEK_FRACTION, targetProgress);
-        mPostCommitAnimator.setInterpolator(
-                triggerBack ? STANDARD_ACCELERATE : EMPHASIZED_DECELERATE);
+        Interpolator interpolator;
+        long duration;
+        if (triggerBack && mViewRoot.mView.hasWindowInsetsAnimationCallback()
+                && mWindowInsetsAnimationController.getShownStateInsets().bottom != 0) {
+            interpolator = SYNC_IME_INTERPOLATOR;
+            duration = ANIMATION_DURATION_SYNC_IME_MS;
+        } else if (triggerBack) {
+            interpolator = FAST_OUT_LINEAR_IN_INTERPOLATOR;
+            duration = ANIMATION_DURATION_UNSYNC_IME_MS;
+        } else {
+            interpolator = EMPHASIZED_DECELERATE;
+            duration = POST_COMMIT_CANCEL_DURATION_MS;
+        }
+        mPostCommitAnimator.setInterpolator(interpolator);
+        mPostCommitAnimator.setDuration(duration);
         mPostCommitAnimator.addUpdateListener(animation -> {
             if (mWindowInsetsAnimationController != null) {
                 setInterpolatedProgress((float) animation.getAnimatedValue());
@@ -207,8 +222,6 @@
                 reset();
             }
         });
-        mPostCommitAnimator.setDuration(
-                triggerBack ? POST_COMMIT_DURATION_MS : POST_COMMIT_CANCEL_DURATION_MS);
         mPostCommitAnimator.start();
         if (triggerBack) {
             mInsetsController.setPredictiveBackImeHideAnimInProgress(true);
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index 462c5c6..6f346bd 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -235,8 +235,8 @@
 
     private static final int ANIMATION_DELAY_DIM_MS = 500;
 
-    private static final int ANIMATION_DURATION_SYNC_IME_MS = 285;
-    private static final int ANIMATION_DURATION_UNSYNC_IME_MS = 200;
+    static final int ANIMATION_DURATION_SYNC_IME_MS = 285;
+    static final int ANIMATION_DURATION_UNSYNC_IME_MS = 200;
 
     private static final int PENDING_CONTROL_TIMEOUT_MS = 2000;
 
@@ -256,11 +256,11 @@
             return 1f - SYSTEM_BARS_ALPHA_INTERPOLATOR.getInterpolation(innerFraction);
         }
     };
-    private static final Interpolator SYNC_IME_INTERPOLATOR =
+    static final Interpolator SYNC_IME_INTERPOLATOR =
             new PathInterpolator(0.2f, 0f, 0f, 1f);
     private static final Interpolator LINEAR_OUT_SLOW_IN_INTERPOLATOR =
             new PathInterpolator(0, 0, 0.2f, 1f);
-    private static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR =
+    static final Interpolator FAST_OUT_LINEAR_IN_INTERPOLATOR =
             new PathInterpolator(0.4f, 0f, 1f, 1f);
 
     /** Visible for WindowManagerWrapper */
diff --git a/core/java/android/view/NotificationTopLineView.java b/core/java/android/view/NotificationTopLineView.java
index e567414..beaf211 100644
--- a/core/java/android/view/NotificationTopLineView.java
+++ b/core/java/android/view/NotificationTopLineView.java
@@ -385,6 +385,13 @@
     }
 
     /**
+     * Returns whether the title is present.
+     */
+    public boolean isTitlePresent() {
+        return mTitle != null;
+    }
+
+    /**
      * Determine if the given point is touching an active part of the top line.
      */
     public boolean isInTouchRect(float x, float y) {
diff --git a/core/java/android/view/ViewConfiguration.java b/core/java/android/view/ViewConfiguration.java
index 9e97a8e..2895bf3 100644
--- a/core/java/android/view/ViewConfiguration.java
+++ b/core/java/android/view/ViewConfiguration.java
@@ -21,7 +21,9 @@
 import android.annotation.TestApi;
 import android.annotation.UiContext;
 import android.app.Activity;
+import android.app.ActivityThread;
 import android.app.AppGlobals;
+import android.app.Application;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Context;
 import android.content.res.Configuration;
@@ -39,14 +41,13 @@
 import android.util.TypedValue;
 import android.view.flags.Flags;
 
+import com.android.internal.R;
 import com.android.internal.annotations.VisibleForTesting;
 
 /**
  * Contains methods to standard constants used in the UI for timeouts, sizes, and distances.
  */
 public class ViewConfiguration {
-    private static final String TAG = "ViewConfiguration";
-
     /**
      * Defines the width of the horizontal scrollbar and the height of the vertical scrollbar in
      * dips
@@ -349,6 +350,8 @@
      */
     private static final int SMART_SELECTION_INITIALIZING_TIMEOUT_IN_MILLISECOND = 500;
 
+    private static ResourceCache sResourceCache = new ResourceCache();
+
     private final boolean mConstructedWithContext;
     private final int mEdgeSlop;
     private final int mFadingEdgeLength;
@@ -374,7 +377,6 @@
     private final int mOverscrollDistance;
     private final int mOverflingDistance;
     private final boolean mViewTouchScreenHapticScrollFeedbackEnabled;
-    @UnsupportedAppUsage
     private final boolean mFadingMarqueeEnabled;
     private final long mGlobalActionsKeyTimeout;
     private final float mVerticalScrollFactor;
@@ -468,14 +470,12 @@
 
         mEdgeSlop = (int) (sizeAndDensity * EDGE_SLOP + 0.5f);
         mFadingEdgeLength = (int) (sizeAndDensity * FADING_EDGE_LENGTH + 0.5f);
-        mScrollbarSize = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_scrollbarSize);
+        mScrollbarSize = res.getDimensionPixelSize(R.dimen.config_scrollbarSize);
         mDoubleTapSlop = (int) (sizeAndDensity * DOUBLE_TAP_SLOP + 0.5f);
         mWindowTouchSlop = (int) (sizeAndDensity * WINDOW_TOUCH_SLOP + 0.5f);
 
         final TypedValue multiplierValue = new TypedValue();
-        res.getValue(
-                com.android.internal.R.dimen.config_ambiguousGestureMultiplier,
+        res.getValue(R.dimen.config_ambiguousGestureMultiplier,
                 multiplierValue,
                 true /*resolveRefs*/);
         mAmbiguousGestureMultiplier = Math.max(1.0f, multiplierValue.getFloat());
@@ -488,8 +488,7 @@
         mOverflingDistance = (int) (sizeAndDensity * OVERFLING_DISTANCE + 0.5f);
 
         if (!sHasPermanentMenuKeySet) {
-            final int configVal = res.getInteger(
-                    com.android.internal.R.integer.config_overrideHasPermanentMenuKey);
+            final int configVal = res.getInteger(R.integer.config_overrideHasPermanentMenuKey);
 
             switch (configVal) {
                 default:
@@ -516,32 +515,27 @@
             }
         }
 
-        mFadingMarqueeEnabled = res.getBoolean(
-                com.android.internal.R.bool.config_ui_enableFadingMarquee);
-        mTouchSlop = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_viewConfigurationTouchSlop);
+        mFadingMarqueeEnabled = res.getBoolean(R.bool.config_ui_enableFadingMarquee);
+        mTouchSlop = res.getDimensionPixelSize(R.dimen.config_viewConfigurationTouchSlop);
         mHandwritingSlop = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_viewConfigurationHandwritingSlop);
-        mHoverSlop = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_viewConfigurationHoverSlop);
+                R.dimen.config_viewConfigurationHandwritingSlop);
+        mHoverSlop = res.getDimensionPixelSize(R.dimen.config_viewConfigurationHoverSlop);
         mMinScrollbarTouchTarget = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_minScrollbarTouchTarget);
+                R.dimen.config_minScrollbarTouchTarget);
         mPagingTouchSlop = mTouchSlop * 2;
 
         mDoubleTapTouchSlop = mTouchSlop;
 
         mHandwritingGestureLineMargin = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_viewConfigurationHandwritingGestureLineMargin);
+                R.dimen.config_viewConfigurationHandwritingGestureLineMargin);
 
-        mMinimumFlingVelocity = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_viewMinFlingVelocity);
-        mMaximumFlingVelocity = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_viewMaxFlingVelocity);
+        mMinimumFlingVelocity = res.getDimensionPixelSize(R.dimen.config_viewMinFlingVelocity);
+        mMaximumFlingVelocity = res.getDimensionPixelSize(R.dimen.config_viewMaxFlingVelocity);
 
         int configMinRotaryEncoderFlingVelocity = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_viewMinRotaryEncoderFlingVelocity);
+                R.dimen.config_viewMinRotaryEncoderFlingVelocity);
         int configMaxRotaryEncoderFlingVelocity = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_viewMaxRotaryEncoderFlingVelocity);
+                R.dimen.config_viewMaxRotaryEncoderFlingVelocity);
         if (configMinRotaryEncoderFlingVelocity < 0 || configMaxRotaryEncoderFlingVelocity < 0) {
             mMinimumRotaryEncoderFlingVelocity = NO_FLING_MIN_VELOCITY;
             mMaximumRotaryEncoderFlingVelocity = NO_FLING_MAX_VELOCITY;
@@ -551,8 +545,7 @@
         }
 
         int configRotaryEncoderHapticScrollFeedbackTickIntervalPixels =
-                res.getDimensionPixelSize(
-                        com.android.internal.R.dimen
+                res.getDimensionPixelSize(R.dimen
                                 .config_rotaryEncoderAxisScrollTickInterval);
         mRotaryEncoderHapticScrollFeedbackTickIntervalPixels =
                 configRotaryEncoderHapticScrollFeedbackTickIntervalPixels > 0
@@ -560,41 +553,31 @@
                         : NO_HAPTIC_SCROLL_TICK_INTERVAL;
 
         mRotaryEncoderHapticScrollFeedbackEnabled =
-                res.getBoolean(
-                        com.android.internal.R.bool
+                res.getBoolean(R.bool
                                 .config_viewRotaryEncoderHapticScrollFedbackEnabled);
 
-        mGlobalActionsKeyTimeout = res.getInteger(
-                com.android.internal.R.integer.config_globalActionsKeyTimeout);
+        mGlobalActionsKeyTimeout = res.getInteger(R.integer.config_globalActionsKeyTimeout);
 
-        mHorizontalScrollFactor = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_horizontalScrollFactor);
-        mVerticalScrollFactor = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_verticalScrollFactor);
+        mHorizontalScrollFactor = res.getDimensionPixelSize(R.dimen.config_horizontalScrollFactor);
+        mVerticalScrollFactor = res.getDimensionPixelSize(R.dimen.config_verticalScrollFactor);
 
         mShowMenuShortcutsWhenKeyboardPresent = res.getBoolean(
-            com.android.internal.R.bool.config_showMenuShortcutsWhenKeyboardPresent);
+                R.bool.config_showMenuShortcutsWhenKeyboardPresent);
 
-        mMinScalingSpan = res.getDimensionPixelSize(
-                com.android.internal.R.dimen.config_minScalingSpan);
+        mMinScalingSpan = res.getDimensionPixelSize(R.dimen.config_minScalingSpan);
 
-        mScreenshotChordKeyTimeout = res.getInteger(
-                com.android.internal.R.integer.config_screenshotChordKeyTimeout);
+        mScreenshotChordKeyTimeout = res.getInteger(R.integer.config_screenshotChordKeyTimeout);
 
         mSmartSelectionInitializedTimeout = res.getInteger(
-                com.android.internal.R.integer.config_smartSelectionInitializedTimeoutMillis);
+                R.integer.config_smartSelectionInitializedTimeoutMillis);
         mSmartSelectionInitializingTimeout = res.getInteger(
-                com.android.internal.R.integer.config_smartSelectionInitializingTimeoutMillis);
-        mPreferKeepClearForFocusEnabled = res.getBoolean(
-                com.android.internal.R.bool.config_preferKeepClearForFocus);
+                R.integer.config_smartSelectionInitializingTimeoutMillis);
+        mPreferKeepClearForFocusEnabled = res.getBoolean(R.bool.config_preferKeepClearForFocus);
         mViewBasedRotaryEncoderScrollHapticsEnabledConfig =
-                res.getBoolean(
-                        com.android.internal.R.bool.config_viewBasedRotaryEncoderHapticsEnabled);
+                res.getBoolean(R.bool.config_viewBasedRotaryEncoderHapticsEnabled);
         mViewTouchScreenHapticScrollFeedbackEnabled =
                 Flags.enableScrollFeedbackForTouch()
-                        ? res.getBoolean(
-                        com.android.internal.R.bool
-                                .config_viewTouchScreenHapticScrollFeedbackEnabled)
+                        ? res.getBoolean(R.bool.config_viewTouchScreenHapticScrollFeedbackEnabled)
                         : false;
     }
 
@@ -632,6 +615,7 @@
     @VisibleForTesting
     public static void resetCacheForTesting() {
         sConfigurations.clear();
+        sResourceCache = new ResourceCache();
     }
 
     /**
@@ -707,7 +691,7 @@
      * components.
      */
     public static int getPressedStateDuration() {
-        return PRESSED_STATE_DURATION;
+        return sResourceCache.getPressedStateDuration();
     }
 
     /**
@@ -752,7 +736,7 @@
      * considered to be a tap.
      */
     public static int getTapTimeout() {
-        return TAP_TIMEOUT;
+        return sResourceCache.getTapTimeout();
     }
 
     /**
@@ -761,7 +745,7 @@
      * considered to be a tap.
      */
     public static int getJumpTapTimeout() {
-        return JUMP_TAP_TIMEOUT;
+        return sResourceCache.getJumpTapTimeout();
     }
 
     /**
@@ -770,7 +754,7 @@
      * double-tap.
      */
     public static int getDoubleTapTimeout() {
-        return DOUBLE_TAP_TIMEOUT;
+        return sResourceCache.getDoubleTapTimeout();
     }
 
     /**
@@ -782,7 +766,7 @@
      */
     @UnsupportedAppUsage
     public static int getDoubleTapMinTime() {
-        return DOUBLE_TAP_MIN_TIME;
+        return sResourceCache.getDoubleTapMinTime();
     }
 
     /**
@@ -792,7 +776,7 @@
      * @hide
      */
     public static int getHoverTapTimeout() {
-        return HOVER_TAP_TIMEOUT;
+        return sResourceCache.getHoverTapTimeout();
     }
 
     /**
@@ -803,7 +787,7 @@
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
     public static int getHoverTapSlop() {
-        return HOVER_TAP_SLOP;
+        return sResourceCache.getHoverTapSlop();
     }
 
     /**
@@ -1044,7 +1028,7 @@
      * in milliseconds.
      */
     public static long getZoomControlsTimeout() {
-        return ZOOM_CONTROLS_TIMEOUT;
+        return sResourceCache.getZoomControlsTimeout();
     }
 
     /**
@@ -1113,14 +1097,14 @@
      *         friction.
      */
     public static float getScrollFriction() {
-        return SCROLL_FRICTION;
+        return sResourceCache.getScrollFriction();
     }
 
     /**
      * @return the default duration in milliseconds for {@link ActionMode#hide(long)}.
      */
     public static long getDefaultActionModeHideDuration() {
-        return ACTION_MODE_HIDE_DURATION_DEFAULT;
+        return sResourceCache.getDefaultActionModeHideDuration();
     }
 
     /**
@@ -1471,8 +1455,137 @@
         return HOVER_TOOLTIP_HIDE_SHORT_TIMEOUT;
     }
 
-    private static final int getDisplayDensity(Context context) {
+    private static int getDisplayDensity(Context context) {
         final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
         return (int) (100.0f * metrics.density);
     }
+
+    /**
+     * Fetches resource values statically and caches them locally for fast lookup. Note that these
+     * values will not be updated during the lifetime of a process, even if resource overlays are
+     * applied.
+     */
+    private static final class ResourceCache {
+
+        private int mPressedStateDuration = -1;
+        private int mTapTimeout = -1;
+        private int mJumpTapTimeout = -1;
+        private int mDoubleTapTimeout = -1;
+        private int mDoubleTapMinTime = -1;
+        private int mHoverTapTimeout = -1;
+        private int mHoverTapSlop = -1;
+        private long mZoomControlsTimeout = -1L;
+        private float mScrollFriction = -1f;
+        private long mDefaultActionModeHideDuration = -1L;
+
+        public int getPressedStateDuration() {
+            if (mPressedStateDuration < 0) {
+                Resources resources = getCurrentResources();
+                mPressedStateDuration = resources != null
+                        ? resources.getInteger(R.integer.config_pressedStateDurationMillis)
+                        : PRESSED_STATE_DURATION;
+            }
+            return mPressedStateDuration;
+        }
+
+        public int getTapTimeout() {
+            if (mTapTimeout < 0) {
+                Resources resources = getCurrentResources();
+                mTapTimeout = resources != null
+                        ? resources.getInteger(R.integer.config_tapTimeoutMillis)
+                        : TAP_TIMEOUT;
+            }
+            return mTapTimeout;
+        }
+
+        public int getJumpTapTimeout() {
+            if (mJumpTapTimeout < 0) {
+                Resources resources = getCurrentResources();
+                mJumpTapTimeout = resources != null
+                        ? resources.getInteger(R.integer.config_jumpTapTimeoutMillis)
+                        : JUMP_TAP_TIMEOUT;
+            }
+            return mJumpTapTimeout;
+        }
+
+        public int getDoubleTapTimeout() {
+            if (mDoubleTapTimeout < 0) {
+                Resources resources = getCurrentResources();
+                mDoubleTapTimeout = resources != null
+                        ? resources.getInteger(R.integer.config_doubleTapTimeoutMillis)
+                        : DOUBLE_TAP_TIMEOUT;
+            }
+            return mDoubleTapTimeout;
+        }
+
+        public int getDoubleTapMinTime() {
+            if (mDoubleTapMinTime < 0) {
+                Resources resources = getCurrentResources();
+                mDoubleTapMinTime = resources != null
+                        ? resources.getInteger(R.integer.config_doubleTapMinTimeMillis)
+                        : DOUBLE_TAP_MIN_TIME;
+            }
+            return mDoubleTapMinTime;
+        }
+
+        public int getHoverTapTimeout() {
+            if (mHoverTapTimeout < 0) {
+                Resources resources = getCurrentResources();
+                mHoverTapTimeout = resources != null
+                        ? resources.getInteger(R.integer.config_hoverTapTimeoutMillis)
+                        : HOVER_TAP_TIMEOUT;
+            }
+            return mHoverTapTimeout;
+        }
+
+        public int getHoverTapSlop() {
+            if (mHoverTapSlop < 0) {
+                Resources resources = getCurrentResources();
+                mHoverTapSlop = resources != null
+                        ? resources.getDimensionPixelSize(R.dimen.config_hoverTapSlop)
+                        : HOVER_TAP_SLOP;
+            }
+            return mHoverTapSlop;
+        }
+
+        public long getZoomControlsTimeout() {
+            if (mZoomControlsTimeout < 0) {
+                Resources resources = getCurrentResources();
+                mZoomControlsTimeout = resources != null
+                        ? resources.getInteger(R.integer.config_zoomControlsTimeoutMillis)
+                        : ZOOM_CONTROLS_TIMEOUT;
+            }
+            return mZoomControlsTimeout;
+        }
+
+        public float getScrollFriction() {
+            if (mScrollFriction < 0) {
+                Resources resources = getCurrentResources();
+                mScrollFriction = resources != null
+                        ? resources.getFloat(R.dimen.config_scrollFriction)
+                        : SCROLL_FRICTION;
+            }
+            return mScrollFriction;
+        }
+
+        public long getDefaultActionModeHideDuration() {
+            if (mDefaultActionModeHideDuration < 0) {
+                Resources resources = getCurrentResources();
+                mDefaultActionModeHideDuration = resources != null
+                        ? resources.getInteger(R.integer.config_defaultActionModeHideDurationMillis)
+                        : ACTION_MODE_HIDE_DURATION_DEFAULT;
+            }
+            return mDefaultActionModeHideDuration;
+        }
+
+        private static Resources getCurrentResources() {
+            if (!android.companion.virtualdevice.flags.Flags
+                    .migrateViewconfigurationConstantsToResources()) {
+                return null;
+            }
+            Application application = ActivityThread.currentApplication();
+            Context context = application != null ? application.getApplicationContext() : null;
+            return context != null ? context.getResources() : null;
+        }
+    }
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 9d0773f..7dc96f2 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -1836,6 +1836,7 @@
                         eventsToBeRegistered,
                         mBasePackageName);
 
+        // LINT.IfChange(fi_cb)
         if (forceInvertColor()) {
             if (mForceInvertObserver == null) {
                 mForceInvertObserver = new ContentObserver(mHandler) {
@@ -1844,7 +1845,6 @@
                         updateForceDarkMode();
                     }
                 };
-
                 final Uri[] urisToObserve = {
                     Settings.Secure.getUriFor(
                         Settings.Secure.ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED),
@@ -1859,6 +1859,7 @@
                 }
             }
         }
+        // LINT.ThenChange(/services/core/java/com/android/server/UiModeManagerService.java:fi_cb)
     }
 
     /**
@@ -13654,4 +13655,11 @@
             ThreadedRenderer.preInitBufferAllocator();
         }
     }
+
+    /**
+     * @hide
+     */
+    public Choreographer getChoreographer() {
+        return mChoreographer;
+    }
 }
diff --git a/core/java/android/view/XrWindowProperties.java b/core/java/android/view/XrWindowProperties.java
new file mode 100644
index 0000000..23021a5
--- /dev/null
+++ b/core/java/android/view/XrWindowProperties.java
@@ -0,0 +1,159 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import android.annotation.FlaggedApi;
+
+/**
+ * Class for XR-specific window properties to put in application manifests.
+ */
+@FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+public final class XrWindowProperties {
+    /** @hide */
+    private XrWindowProperties() {}
+
+    /**
+     * Both Application and activity level
+     * {@link android.content.pm.PackageManager.Property PackageManager.Property} for an app to
+     * inform the system of the activity launch mode in XR. When it is declared at the application
+     * level, all activities are set to the defined value, unless it is overridden at the activity
+     * level.
+     *
+     * <p>The default value is {@link #XR_ACTIVITY_START_MODE_UNDEFINED}.
+     *
+     * <p>The available values are:
+     * <ul>
+     *   <li>{@link #XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED}
+     *   <li>{@link #XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED}
+     *   <li>{@link #XR_ACTIVITY_START_MODE_HOME_SPACE}
+     *   <li>{@link #XR_ACTIVITY_START_MODE_UNDEFINED}
+     * </ul>
+     *
+     * <p><b>Syntax:</b>
+     * <pre>
+     * &lt;application&gt;
+     *   &lt;property
+     *     android:name="android.window.PROPERTY_ACTIVITY_XR_START_MODE"
+     *     android:value="XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED|
+     *                    XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED|
+     *                    XR_ACTIVITY_START_MODE_HOME_SPACE|
+     *                    XR_ACTIVITY_START_MODE_UNDEFINED"/&gt;
+     * &lt;/application&gt;
+     * </pre>
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String PROPERTY_XR_ACTIVITY_START_MODE =
+            "android.window.PROPERTY_XR_ACTIVITY_START_MODE";
+
+    /**
+     * Defines the value to launch an activity in unmanaged full space mode in XR, where the
+     * activity itself is rendering the space and controls its own scene graph. This should be used
+     * for all activities that use OpenXR to render.
+     *
+     * @see #PROPERTY_XR_ACTIVITY_START_MODE
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED =
+            "XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED";
+
+    /**
+     * The default value if not specified. If used, the actual launching mode will be determined by
+     * the system based on the launching activity's current mode and the launching flags.  When
+     * {@link #PROPERTY_XR_ACTIVITY_START_MODE} is used at the application level, apps can use this
+     * value to reset at individual activity level.
+     *
+     * @see #PROPERTY_XR_ACTIVITY_START_MODE
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String XR_ACTIVITY_START_MODE_UNDEFINED =
+            "XR_ACTIVITY_START_MODE_UNDEFINED";
+
+    /**
+     * Defines the value to launch an activity in
+     * <a href="https://developer.android.com/develop/xr/jetpack-xr-sdk/transition-home-space-to-full-space">managed
+     * full space mode</a> in XR, where the system is rendering the activity from a scene graph.
+     *
+     * @see #PROPERTY_XR_ACTIVITY_START_MODE
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED =
+            "XR_ACTIVITY_START_MODE_FULL_SPACE_MANAGED";
+
+    /**
+     * Defines the value to launch an activity in
+     * <a href="https://developer.android.com/develop/xr/jetpack-xr-sdk/transition-home-space-to-full-space">home
+     * space mode</a> in XR.
+     *
+     * @see #PROPERTY_XR_ACTIVITY_START_MODE
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String XR_ACTIVITY_START_MODE_HOME_SPACE =
+            "XR_ACTIVITY_START_MODE_HOME_SPACE";
+
+    /**
+     * Both Application and activity level
+     * {@link android.content.pm.PackageManager.Property PackageManager.Property} for an app to
+     * inform the system of the type of safety boundary recommended for the activity. When it is
+     * declared at the application level, all activities are set to the defined value, unless it is
+     * overridden at the activity level. When not declared, the system will not enforce any
+     * recommendations for a type of safety boundary and will continue to use the type that is
+     * currently in use.
+     *
+     * <p>The default value is {@link #XR_BOUNDARY_TYPE_NO_RECOMMENDATION}.
+     *
+     * <p>The available values are:
+     * <ul>
+     *   <li>{@link #XR_BOUNDARY_TYPE_LARGE}
+     *   <li>{@link #XR_BOUNDARY_TYPE_NO_RECOMMENDATION}
+     * </ul>
+     *
+     * <p><b>Syntax:</b>
+     * <pre>
+     * &lt;application&gt;
+     *   &lt;property
+     *     android:name="android.window.PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED"
+     *     android:value="XR_BOUNDARY_TYPE_LARGE|
+     *                    XR_BOUNDARY_TYPE_NO_RECOMMENDATION"/&gt;
+     * &lt;/application&gt;
+     * </pre>
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED =
+            "android.window.PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED";
+
+    /**
+     * Defines the value to launch an activity with no recommendations for the type of safety
+     * boundary. The system will continue to use the type of safety boundary that is currently
+     * in use.
+     *
+     * @see #PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String XR_BOUNDARY_TYPE_NO_RECOMMENDATION =
+            "XR_BOUNDARY_TYPE_NO_RECOMMENDATION";
+
+    /**
+     * Defines the value to launch an activity with a large boundary recommended. This is useful for
+     * activities which expect users to be moving around. The system will ask the user to use a
+     * larger size for their safety boundary and check that their space is clear, if the larger
+     * size is not already in use. This larger size will be determined by the system.
+     *
+     * @see #PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED
+     */
+    @FlaggedApi(android.xr.Flags.FLAG_XR_MANIFEST_ENTRIES)
+    public static final String XR_BOUNDARY_TYPE_LARGE = "XR_BOUNDARY_TYPE_LARGE";
+}
diff --git a/core/java/android/webkit/LegacyErrorStrings.java b/core/java/android/webkit/LegacyErrorStrings.java
index 60a6ee1..f52214c 100644
--- a/core/java/android/webkit/LegacyErrorStrings.java
+++ b/core/java/android/webkit/LegacyErrorStrings.java
@@ -22,7 +22,7 @@
 /**
  * Localized strings for the error codes defined in EventHandler.
  *
- * {@hide}
+ * @hide
  */
 class LegacyErrorStrings {
     private LegacyErrorStrings() { /* Utility class, don't instantiate. */ }
diff --git a/core/java/android/webkit/WebIconDatabase.java b/core/java/android/webkit/WebIconDatabase.java
index b705658..76d2e4c 100644
--- a/core/java/android/webkit/WebIconDatabase.java
+++ b/core/java/android/webkit/WebIconDatabase.java
@@ -73,7 +73,7 @@
      */
     public abstract void requestIconForPageUrl(String url, IconListener listener);
 
-    /** {@hide}
+    /** @hide
      */
     @SuppressWarnings("HiddenAbstractMethod")
     @SystemApi
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 5e828ba..99fe0cb 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -5211,11 +5211,7 @@
      */
     @Nullable
     public String getFontVariationSettings() {
-        if (Flags.typefaceRedesignReadonly()) {
-            return mTextPaint.getFontVariationOverride();
-        } else {
-            return mTextPaint.getFontVariationSettings();
-        }
+        return mTextPaint.getFontVariationSettings();
     }
 
     /**
@@ -5571,10 +5567,10 @@
                             Math.clamp(400 + mFontWeightAdjustment,
                                     FontStyle.FONT_WEIGHT_MIN, FontStyle.FONT_WEIGHT_MAX)));
                 }
-                mTextPaint.setFontVariationOverride(
+                mTextPaint.setFontVariationSettings(
                         FontVariationAxis.toFontVariationSettings(axes));
             } else {
-                mTextPaint.setFontVariationOverride(fontVariationSettings);
+                mTextPaint.setFontVariationSettings(fontVariationSettings);
             }
             effective = true;
         } else {
diff --git a/core/java/android/window/DesktopExperienceFlags.java b/core/java/android/window/DesktopExperienceFlags.java
index e0c48b0..b4ff8e7 100644
--- a/core/java/android/window/DesktopExperienceFlags.java
+++ b/core/java/android/window/DesktopExperienceFlags.java
@@ -60,10 +60,13 @@
     ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT(Flags::enableMoveToNextDisplayShortcut, false),
     ENABLE_MULTIPLE_DESKTOPS_BACKEND(Flags::enableMultipleDesktopsBackend, false),
     ENABLE_MULTIPLE_DESKTOPS_FRONTEND(Flags::enableMultipleDesktopsFrontend, false),
+    ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS(
+            Flags::enablePersistingDisplaySizeForConnectedDisplays, false),
     ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY(Flags::enablePerDisplayDesktopWallpaperActivity,
             false),
     ENABLE_PER_DISPLAY_PACKAGE_CONTEXT_CACHE_IN_STATUSBAR_NOTIF(
             Flags::enablePerDisplayPackageContextCacheInStatusbarNotif, false),
+    ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE(Flags::enableProjectedDisplayDesktopMode, false),
     ENABLE_TASKBAR_CONNECTED_DISPLAYS(Flags::enableTaskbarConnectedDisplays, false),
     ENTER_DESKTOP_BY_DEFAULT_ON_FREEFORM_DISPLAYS(Flags::enterDesktopByDefaultOnFreeformDisplays,
             false),
diff --git a/core/java/android/window/DesktopModeFlags.java b/core/java/android/window/DesktopModeFlags.java
index 1b8f73a..7876924 100644
--- a/core/java/android/window/DesktopModeFlags.java
+++ b/core/java/android/window/DesktopModeFlags.java
@@ -53,12 +53,14 @@
     ENABLE_CAPTION_COMPAT_INSET_FORCE_CONSUMPTION_ALWAYS(
             Flags::enableCaptionCompatInsetForceConsumptionAlways, true),
     ENABLE_CASCADING_WINDOWS(Flags::enableCascadingWindows, true),
+    ENABLE_DESKTOP_APP_HANDLE_ANIMATION(Flags::enableDesktopAppHandleAnimation, false),
     ENABLE_DESKTOP_APP_LAUNCH_ALTTAB_TRANSITIONS_BUGFIX(
             Flags::enableDesktopAppLaunchAlttabTransitionsBugfix, true),
     ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX(Flags::enableDesktopAppLaunchTransitionsBugfix,
             true),
     ENABLE_DESKTOP_CLOSE_SHORTCUT_BUGFIX(Flags::enableDesktopCloseShortcutBugfix, false),
     ENABLE_DESKTOP_COMPAT_UI_VISIBILITY_STATUS(Flags::enableCompatUiVisibilityStatus, true),
+    ENABLE_DESKTOP_IMMERSIVE_DRAG_BUGFIX(Flags::enableDesktopImmersiveDragBugfix, false),
     ENABLE_DESKTOP_INDICATOR_IN_SEPARATE_THREAD_BUGFIX(
             Flags::enableDesktopIndicatorInSeparateThreadBugfix, false),
     ENABLE_DESKTOP_OPENING_DEEPLINK_MINIMIZE_ANIMATION_BUGFIX(
@@ -92,6 +94,7 @@
     ENABLE_DESKTOP_WINDOWING_MULTI_INSTANCE_FEATURES(
             Flags::enableDesktopWindowingMultiInstanceFeatures, true),
     ENABLE_DESKTOP_WINDOWING_PERSISTENCE(Flags::enableDesktopWindowingPersistence, true),
+    ENABLE_DESKTOP_WINDOWING_PIP(Flags::enableDesktopWindowingPip, false),
     ENABLE_DESKTOP_WINDOWING_QUICK_SWITCH(Flags::enableDesktopWindowingQuickSwitch, true),
     ENABLE_DESKTOP_WINDOWING_SCVH_CACHE(Flags::enableDesktopWindowingScvhCacheBugFix, true),
     ENABLE_DESKTOP_WINDOWING_SIZE_CONSTRAINTS(Flags::enableDesktopWindowingSizeConstraints, true),
@@ -106,6 +109,7 @@
     ENABLE_FULLY_IMMERSIVE_IN_DESKTOP(Flags::enableFullyImmersiveInDesktop, true),
     ENABLE_HANDLE_INPUT_FIX(Flags::enableHandleInputFix, true),
     ENABLE_HOLD_TO_DRAG_APP_HANDLE(Flags::enableHoldToDragAppHandle, true),
+    ENABLE_INPUT_LAYER_TRANSITION_FIX(Flags::enableInputLayerTransitionFix, false),
     ENABLE_MINIMIZE_BUTTON(Flags::enableMinimizeButton, true),
     ENABLE_MODALS_FULLSCREEN_WITH_PERMISSIONS(Flags::enableModalsFullscreenWithPermission, false),
     ENABLE_OPAQUE_BACKGROUND_FOR_TRANSPARENT_WINDOWS(
diff --git a/core/java/android/window/flags/lse_desktop_experience.aconfig b/core/java/android/window/flags/lse_desktop_experience.aconfig
index 2f2a09a..1f710c1 100644
--- a/core/java/android/window/flags/lse_desktop_experience.aconfig
+++ b/core/java/android/window/flags/lse_desktop_experience.aconfig
@@ -154,6 +154,16 @@
 }
 
 flag {
+    name: "enable_input_layer_transition_fix"
+    namespace: "lse_desktop_experience"
+    description: "Enables a bugfix for input layer disposal during certain transitions."
+    bug: "371473978"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "enable_accessible_custom_headers"
     namespace: "lse_desktop_experience"
     description: "Enables a11y-friendly custom header input handling"
@@ -803,6 +813,26 @@
 }
 
 flag {
+    name: "enable_desktop_app_handle_animation"
+    namespace: "lse_desktop_experience"
+    description: "Enables the animation that occurs when the app handle of a task in immersive mode is shown or hidden."
+    bug: "375252977"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    name: "enable_desktop_immersive_drag_bugfix"
+    namespace: "lse_desktop_experience"
+    description: "Keeps the app handle visible during a drag."
+    bug: "381280828"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
     name: "enable_desktop_indicator_in_separate_thread_bugfix"
     namespace: "lse_desktop_experience"
     description: "Enables running visual indicator view operations in ShellDesktopThread."
@@ -816,7 +846,7 @@
     name: "enable_taskbar_overflow"
     namespace: "lse_desktop_experience"
     description: "Show recent apps in the taskbar overflow."
-    bug: "368119679"
+    bug: "375627272"
 }
 
 flag {
@@ -827,13 +857,10 @@
 }
 
 flag {
-    name: "enable_persisting_density_scale_for_connected_displays"
+    name: "enable_persisting_display_size_for_connected_displays"
     namespace: "lse_desktop_experience"
-    description: "Enables persisting density scale on resolution change for connected displays."
+    description: "Enables persisting display size on resolution change for connected displays."
     bug: "392855657"
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
 }
 
 flag {
@@ -875,3 +902,17 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "enable_size_compat_mode_improvements_for_connected_displays"
+    namespace: "lse_desktop_experience"
+    description: "Enable some improvements in size compat mode for connected displays."
+    bug: "399752440"
+}
+
+flag {
+    name: "form_factor_based_desktop_first_switch"
+    namespace: "lse_desktop_experience"
+    description: "Enables the desktop-first mode switching logic based on its form factor."
+    bug: "394736817"
+}
diff --git a/core/java/android/window/flags/windowing_frontend.aconfig b/core/java/android/window/flags/windowing_frontend.aconfig
index 0e19eb2..b4fec41 100644
--- a/core/java/android/window/flags/windowing_frontend.aconfig
+++ b/core/java/android/window/flags/windowing_frontend.aconfig
@@ -51,6 +51,17 @@
 }
 
 flag {
+  name: "use_cached_insets_for_display_switch"
+  namespace: "windowing_frontend"
+  description: "Reduce intermediate insets changes for display switch"
+  bug: "266197298"
+  is_fixed_read_only: true
+  metadata {
+    purpose: PURPOSE_BUGFIX
+  }
+}
+
+flag {
   name: "edge_to_edge_by_default"
   namespace: "windowing_frontend"
   description: "Make app go edge-to-edge by default when targeting SDK 35 or greater"
@@ -482,4 +493,15 @@
     metadata {
         purpose: PURPOSE_BUGFIX
     }
+}
+
+flag {
+    name: "early_launch_hint"
+    namespace: "windowing_frontend"
+    description: "Sets Launch powermode for activity launches earlier"
+    bug: "399380676"
+    is_fixed_read_only: true
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
 }
\ No newline at end of file
diff --git a/core/java/android/window/flags/windowing_sdk.aconfig b/core/java/android/window/flags/windowing_sdk.aconfig
index f2efa20..cbeaeda 100644
--- a/core/java/android/window/flags/windowing_sdk.aconfig
+++ b/core/java/android/window/flags/windowing_sdk.aconfig
@@ -81,6 +81,16 @@
 
 flag {
     namespace: "windowing_sdk"
+    name: "activity_embedding_delay_task_fragment_finish_for_activity_launch"
+    description: "Fixes a race condition that we finish the TaskFragment too early when there is a pending activity launch."
+    bug: "390452023"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    namespace: "windowing_sdk"
     name: "wlinfo_oncreate"
     description: "Makes WindowLayoutInfo accessible without racing in the Activity#onCreate()"
     bug: "337820752"
@@ -127,17 +137,6 @@
 
 flag {
     namespace: "windowing_sdk"
-    name: "use_self_sync_transaction_for_layer"
-    description: "Always use this.getSyncTransaction for assignLayer"
-    bug: "388127825"
-    is_fixed_read_only: true
-    metadata {
-        purpose: PURPOSE_BUGFIX
-    }
-}
-
-flag {
-    namespace: "windowing_sdk"
     name: "safe_region_letterboxing"
     description: "Enables letterboxing for a safe region"
     bug: "380132497"
diff --git a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
index 6498c53..a2d6c2b 100644
--- a/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
+++ b/core/java/com/android/internal/accessibility/dialog/AccessibilityTargetHelper.java
@@ -215,7 +215,6 @@
                         Settings.Secure.ACCESSIBILITY_DISPLAY_INVERSION_ENABLED);
         targets.add(colorInversion);
 
-        // TODO(b/394683600): Update Icon with the autoclick asset.
         final ToggleAllowListingFeatureTarget autoclick =
                 new ToggleAllowListingFeatureTarget(context,
                         shortcutType,
@@ -224,7 +223,7 @@
                         AUTOCLICK_COMPONENT_NAME.flattenToString(),
                         uid,
                         context.getString(R.string.autoclick_feature_name),
-                        context.getDrawable(R.drawable.ic_accessibility_generic),
+                        context.getDrawable(R.drawable.ic_accessibility_autoclick),
                         Settings.Secure.ACCESSIBILITY_AUTOCLICK_ENABLED);
         targets.add(autoclick);
 
diff --git a/core/java/com/android/internal/os/DEBUG_STORE_OWNERS b/core/java/com/android/internal/os/DEBUG_STORE_OWNERS
new file mode 100644
index 0000000..c8e22b7
--- /dev/null
+++ b/core/java/com/android/internal/os/DEBUG_STORE_OWNERS
@@ -0,0 +1,2 @@
+benmiles@google.com
+mohamadmahmoud@google.com
diff --git a/core/java/com/android/internal/os/DebugStore.java b/core/java/com/android/internal/os/DebugStore.java
index 4c45fee..3dca786 100644
--- a/core/java/com/android/internal/os/DebugStore.java
+++ b/core/java/com/android/internal/os/DebugStore.java
@@ -20,6 +20,7 @@
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.Intent;
 import android.content.pm.ServiceInfo;
+import android.util.Log;
 
 import com.android.internal.annotations.VisibleForTesting;
 
@@ -43,6 +44,9 @@
  * @hide
  */
 public class DebugStore {
+    private static final boolean DEBUG_EVENTS = false;
+    private static final String TAG = "DebugStore";
+
     private static DebugStoreNative sDebugStoreNative = new DebugStoreNativeImpl();
 
     @UnsupportedAppUsage
@@ -120,7 +124,7 @@
      * @param receiverClassName The class name of the broadcast receiver.
      */
     @UnsupportedAppUsage
-    public static void recordGoAsync(String receiverClassName) {
+    public static void recordGoAsync(int pendingResultId) {
         sDebugStoreNative.recordEvent(
                 "GoAsync",
                 List.of(
@@ -128,8 +132,8 @@
                         Thread.currentThread().getName(),
                         "tid",
                         String.valueOf(Thread.currentThread().getId()),
-                        "rcv",
-                        Objects.toString(receiverClassName)));
+                        "prid",
+                        Integer.toHexString(pendingResultId)));
     }
 
     /**
@@ -138,7 +142,7 @@
      * @param receiverClassName The class of the broadcast receiver that completed the operation.
      */
     @UnsupportedAppUsage
-    public static void recordFinish(String receiverClassName) {
+    public static void recordFinish(int pendingResultId) {
         sDebugStoreNative.recordEvent(
                 "Finish",
                 List.of(
@@ -146,9 +150,10 @@
                         Thread.currentThread().getName(),
                         "tid",
                         String.valueOf(Thread.currentThread().getId()),
-                        "rcv",
-                        Objects.toString(receiverClassName)));
+                        "prid",
+                        Integer.toHexString(pendingResultId)));
     }
+
     /**
      * Records the completion of a long-running looper message.
      *
@@ -172,21 +177,92 @@
 
 
     /**
-     * Records the reception of a broadcast.
+     * Records the reception of a broadcast by a manifest-declared receiver.
      *
      * @param intent The Intent associated with the broadcast.
      * @return A unique ID for the recorded event.
      */
     @UnsupportedAppUsage
-    public static long recordBroadcastHandleReceiver(@Nullable Intent intent) {
+    public static long recordBroadcastReceive(@Nullable Intent intent, int pendingResultId) {
         return sDebugStoreNative.beginEvent(
-                "HandleReceiver",
+                "BcRcv",
+                List.of(
+                        "tname",
+                        Thread.currentThread().getName(),
+                        "tid",
+                        String.valueOf(Thread.currentThread().getId()),
+                        "act",
+                        Objects.toString(intent != null ? intent.getAction() : null),
+                        "cmp",
+                        Objects.toString(intent != null ? intent.getComponent() : null),
+                        "pkg",
+                        Objects.toString(intent != null ? intent.getPackage() : null),
+                        "prid",
+                        Integer.toHexString(pendingResultId)));
+    }
+
+    /**
+     * Records the reception of a broadcast by a context-registered receiver.
+     *
+     * @param intent The Intent associated with the broadcast.
+     * @param pendingResultId The object ID of the PendingResult associated with the broadcast.
+     * @return A unique ID for the recorded event.
+     */
+    @UnsupportedAppUsage
+    public static long recordBroadcastReceiveReg(@Nullable Intent intent, int pendingResultId) {
+        return sDebugStoreNative.beginEvent(
+                "BcRcvReg",
+                List.of(
+                        "tname",
+                        Thread.currentThread().getName(),
+                        "tid",
+                        String.valueOf(Thread.currentThread().getId()),
+                        "act",
+                        Objects.toString(intent != null ? intent.getAction() : null),
+                        "cmp",
+                        Objects.toString(intent != null ? intent.getComponent() : null),
+                        "pkg",
+                        Objects.toString(intent != null ? intent.getPackage() : null),
+                        "prid",
+                        Integer.toHexString(pendingResultId)));
+    }
+
+    /**
+     * Records the binding of an application.
+     *
+     * @return A unique ID for the recorded event.
+     */
+    @UnsupportedAppUsage
+    public static long recordHandleBindApplication() {
+        return sDebugStoreNative.beginEvent("BindApp", List.of());
+    }
+
+    /**
+     * Records the scheduling of a receiver.
+     *
+     * @return A unique ID for the recorded event.
+     */
+    @UnsupportedAppUsage
+    public static long recordScheduleReceiver() {
+        return sDebugStoreNative.beginEvent(
+                "SchRcv",
                 List.of(
                         "tname", Thread.currentThread().getName(),
-                        "tid", String.valueOf(Thread.currentThread().getId()),
-                        "act", Objects.toString(intent != null ? intent.getAction() : null),
-                        "cmp", Objects.toString(intent != null ? intent.getComponent() : null),
-                        "pkg", Objects.toString(intent != null ? intent.getPackage() : null)));
+                        "tid", String.valueOf(Thread.currentThread().getId())));
+    }
+
+    /**
+     * Records the scheduling of a registered receiver.
+     *
+     * @return A unique ID for the recorded event.
+     */
+    @UnsupportedAppUsage
+    public static long recordScheduleRegisteredReceiver() {
+        return sDebugStoreNative.beginEvent(
+                "SchRcvReg",
+                List.of(
+                        "tname", Thread.currentThread().getName(),
+                        "tid", String.valueOf(Thread.currentThread().getId())));
     }
 
     /**
@@ -225,18 +301,48 @@
     private static class DebugStoreNativeImpl implements DebugStoreNative {
         @Override
         public long beginEvent(String eventName, List<String> attributes) {
-            return DebugStore.beginEventNative(eventName, attributes);
+            long id = DebugStore.beginEventNative(eventName, attributes);
+            if (DEBUG_EVENTS) {
+                Log.i(
+                        TAG,
+                        "beginEvent: " + id + " " + eventName + " " + attributeString(attributes));
+            }
+            return id;
         }
 
         @Override
         public void endEvent(long id, List<String> attributes) {
+            if (DEBUG_EVENTS) {
+                Log.i(TAG, "endEvent: " + id + " " + attributeString(attributes));
+            }
             DebugStore.endEventNative(id, attributes);
         }
 
         @Override
         public void recordEvent(String eventName, List<String> attributes) {
+            if (DEBUG_EVENTS) {
+                Log.i(TAG, "recordEvent: " + eventName + " " + attributeString(attributes));
+            }
             DebugStore.recordEventNative(eventName, attributes);
         }
+
+        /**
+         * Returns a string like "[key1=foo, key2=bar]"
+         */
+        private String attributeString(List<String> attributes) {
+            StringBuilder sb = new StringBuilder().append("[");
+
+            for (int i = 0; i < attributes.size(); i++) {
+                sb.append(attributes.get(i));
+
+                if (i % 2 == 0) {
+                    sb.append("=");
+                } else if (i < attributes.size() - 1) {
+                    sb.append(", ");
+                }
+            }
+            return sb.append("]").toString();
+        }
     }
 
     private static native long beginEventNative(String eventName, List<String> attributes);
diff --git a/core/java/com/android/internal/os/OWNERS b/core/java/com/android/internal/os/OWNERS
index ffd4499..a5aa9618 100644
--- a/core/java/com/android/internal/os/OWNERS
+++ b/core/java/com/android/internal/os/OWNERS
@@ -2,6 +2,7 @@
 per-file *Zygote* = file:/ZYGOTE_OWNERS
 per-file *Cpu* = file:CPU_OWNERS
 per-file *Binder* = file:BINDER_OWNERS
+per-file *DebugStore* = file:DEBUG_STORE_OWNERS
 per-file *BinaryTransparency* = file:/core/java/android/transparency/OWNERS
 
 # BatteryStats
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 2cca3db..3da1922 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -1178,6 +1178,7 @@
             }
             newGroup.setShowingAvatar(!mIsOneToOne && !mIsCollapsed);
             newGroup.setSingleLine(mIsCollapsed && TextUtils.isEmpty(mSummarizedContent));
+            newGroup.setIsCollapsed(mIsCollapsed);
             newGroup.setSender(sender, nameOverride);
             newGroup.setSending(groupIndex == (groups.size() - 1) && showSpinner);
             mGroups.add(newGroup);
diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java
index 1f90760..dd31c38 100644
--- a/core/java/com/android/internal/widget/LockPatternView.java
+++ b/core/java/com/android/internal/widget/LockPatternView.java
@@ -634,7 +634,6 @@
     }
 
     private void notifyPatternStarted() {
-        sendAccessEvent(R.string.lockscreen_access_pattern_start);
         if (mOnPatternListener != null) {
             mOnPatternListener.onPatternStart();
         }
@@ -642,14 +641,12 @@
 
     @UnsupportedAppUsage
     private void notifyPatternDetected() {
-        sendAccessEvent(R.string.lockscreen_access_pattern_detected);
         if (mOnPatternListener != null) {
             mOnPatternListener.onPatternDetected(mPattern);
         }
     }
 
     private void notifyPatternCleared() {
-        sendAccessEvent(R.string.lockscreen_access_pattern_cleared);
         if (mOnPatternListener != null) {
             mOnPatternListener.onPatternCleared();
         }
@@ -1240,10 +1237,6 @@
         }
     }
 
-    private void sendAccessEvent(int resId) {
-        announceForAccessibility(mContext.getString(resId));
-    }
-
     private void handleActionUp() {
         // report pattern detected
         if (!mPattern.isEmpty()) {
diff --git a/core/java/com/android/internal/widget/MessagingGroup.java b/core/java/com/android/internal/widget/MessagingGroup.java
index b31a200..21bb7a9 100644
--- a/core/java/com/android/internal/widget/MessagingGroup.java
+++ b/core/java/com/android/internal/widget/MessagingGroup.java
@@ -103,6 +103,7 @@
     private boolean mShowingAvatar = true;
     private CharSequence mSenderName;
     private boolean mSingleLine = false;
+    private boolean mIsCollapsed = false;
     private LinearLayout mContentContainer;
     private int mRequestedMaxDisplayedLines = Integer.MAX_VALUE;
     private int mSenderTextPaddingSingleLine;
@@ -451,7 +452,7 @@
     private void updateIconVisibility() {
         if (Flags.notificationsRedesignTemplates()) {
             // We don't show any icon (other than the app or person icon) in the collapsed form.
-            mMessagingIconContainer.setVisibility(mSingleLine ? GONE : VISIBLE);
+            mMessagingIconContainer.setVisibility(mIsCollapsed ? GONE : VISIBLE);
         }
     }
 
@@ -714,10 +715,18 @@
             updateMaxDisplayedLines();
             updateClipRect();
             updateSenderVisibility();
-            updateIconVisibility();
         }
     }
 
+    /**
+     * Sets whether this is in a collapsed layout or not. Certain elements like icons are not shown
+     * when the notification is collapsed.
+     */
+    public void setIsCollapsed(boolean isCollapsed) {
+        mIsCollapsed = isCollapsed;
+        updateIconVisibility();
+    }
+
     public boolean isSingleLine() {
         return mSingleLine;
     }
diff --git a/core/java/com/android/internal/widget/MessagingLayout.java b/core/java/com/android/internal/widget/MessagingLayout.java
index 9fe2de8..4cc4b38 100644
--- a/core/java/com/android/internal/widget/MessagingLayout.java
+++ b/core/java/com/android/internal/widget/MessagingLayout.java
@@ -551,6 +551,7 @@
             }
             newGroup.setSingleLine(mIsCollapsed && TextUtils.isEmpty(mSummarizedContent));
             newGroup.setShowingAvatar(!mIsCollapsed);
+            newGroup.setIsCollapsed(mIsCollapsed);
             newGroup.setSender(sender, nameOverride);
             newGroup.setSending(groupIndex == (groups.size() - 1) && showSpinner);
             mGroups.add(newGroup);
diff --git a/core/java/com/android/internal/widget/PeopleHelper.java b/core/java/com/android/internal/widget/PeopleHelper.java
index 3f5b4a0..3aa4c84 100644
--- a/core/java/com/android/internal/widget/PeopleHelper.java
+++ b/core/java/com/android/internal/widget/PeopleHelper.java
@@ -110,7 +110,7 @@
     @NonNull
     public Icon createAvatarSymbol(@NonNull CharSequence name, @NonNull String symbol,
             @ColorInt int layoutColor) {
-        if (symbol.isEmpty() || TextUtils.isDigitsOnly(symbol)
+        if (symbol == null || symbol.isEmpty() || TextUtils.isDigitsOnly(symbol)
                 || SPECIAL_CHAR_PATTERN.matcher(symbol).find()) {
             Icon avatarIcon = Icon.createWithResource(mContext, R.drawable.messaging_user);
             avatarIcon.setTint(findColor(name, layoutColor));
diff --git a/core/jni/android_database_SQLiteConnection.cpp b/core/jni/android_database_SQLiteConnection.cpp
index ba7e705..36c08a5 100644
--- a/core/jni/android_database_SQLiteConnection.cpp
+++ b/core/jni/android_database_SQLiteConnection.cpp
@@ -204,7 +204,7 @@
     return reinterpret_cast<jlong>(connection);
 }
 
-static void nativeClose(JNIEnv* env, jclass clazz, jlong connectionPtr) {
+static void nativeClose(JNIEnv* env, jclass clazz, jlong connectionPtr, jboolean fast) {
     SQLiteConnection* connection = reinterpret_cast<SQLiteConnection*>(connectionPtr);
 
     if (connection) {
@@ -212,6 +212,13 @@
         if (connection->tableQuery != nullptr) {
             sqlite3_finalize(connection->tableQuery);
         }
+        if (fast) {
+            // The caller requested a fast close, so do not checkpoint even if this is the last
+            // connection to the database.  Note that the change is only to this connection.
+            // Any other connections to the same database are unaffected.
+            int _unused = 0;
+            sqlite3_db_config(connection->db, SQLITE_DBCONFIG_NO_CKPT_ON_CLOSE, 1, &_unused);
+        }
         int err = sqlite3_close(connection->db);
         if (err != SQLITE_OK) {
             // This can happen if sub-objects aren't closed first.  Make sure the caller knows.
@@ -224,6 +231,12 @@
     }
 }
 
+// This method is deprecated and should be removed when it is no longer needed by the
+// robolectric tests.
+static void nativeClose(JNIEnv* env, jclass clazz, jlong connectionPtr) {
+    nativeClose(env, clazz, connectionPtr, false);
+}
+
 static void sqliteCustomScalarFunctionCallback(sqlite3_context *context,
         int argc, sqlite3_value **argv) {
     JNIEnv* env = AndroidRuntime::getJNIEnv();
@@ -959,8 +972,10 @@
     /* name, signature, funcPtr */
     { "nativeOpen", "(Ljava/lang/String;ILjava/lang/String;ZZII)J",
             (void*)nativeOpen },
+    { "nativeClose", "(JZ)V",
+      (void*) static_cast<void(*)(JNIEnv*,jclass,jlong,jboolean)>(nativeClose) },
     { "nativeClose", "(J)V",
-            (void*)nativeClose },
+      (void*) static_cast<void(*)(JNIEnv*,jclass,jlong)>(nativeClose) },
     { "nativeRegisterCustomScalarFunction", "(JLjava/lang/String;Ljava/util/function/UnaryOperator;)V",
             (void*)nativeRegisterCustomScalarFunction },
     { "nativeRegisterCustomAggregateFunction", "(JLjava/lang/String;Ljava/util/function/BinaryOperator;)V",
diff --git a/core/jni/android_media_ImageWriter.cpp b/core/jni/android_media_ImageWriter.cpp
index 1357dd8..8e58922 100644
--- a/core/jni/android_media_ImageWriter.cpp
+++ b/core/jni/android_media_ImageWriter.cpp
@@ -399,7 +399,7 @@
     }
     sp<JNIImageWriterContext> ctx(new JNIImageWriterContext(env, weakThiz, clazz));
 
-    sp<Surface> producer = new Surface(bufferProducer, /*controlledByApp*/false);
+    sp<Surface> producer = sp<Surface>::make(bufferProducer, /*controlledByApp*/ false);
     ctx->setProducer(producer);
     /**
      * NATIVE_WINDOW_API_CPU isn't a good choice here, as it makes the bufferQueue not connectable
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 312c206..783daec 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -139,7 +139,7 @@
         return NULL;
     }
 
-    sp<Surface> surface(new Surface(bufferProducer, true));
+    sp<Surface> surface = sp<Surface>::make(bufferProducer, true);
     return android_view_Surface_createFromSurface(env, surface);
 }
 
@@ -161,7 +161,7 @@
         return 0;
     }
 
-    sp<Surface> surface(new Surface(producer, true));
+    sp<Surface> surface = sp<Surface>::make(producer, true);
     if (surface == NULL) {
         jniThrowException(env, OutOfResourcesException, NULL);
         return 0;
@@ -358,8 +358,8 @@
     sp<Surface> sur;
     if (surfaceShim.graphicBufferProducer != nullptr) {
         // we have a new IGraphicBufferProducer, create a new Surface for it
-        sur = new Surface(surfaceShim.graphicBufferProducer, true,
-                          surfaceShim.surfaceControlHandle);
+        sur = sp<Surface>::make(surfaceShim.graphicBufferProducer, true,
+                                surfaceShim.surfaceControlHandle);
         // and keep a reference before passing to java
         sur->incStrong(&sRefBaseOwner);
     }
diff --git a/core/jni/android_view_SurfaceSession.cpp b/core/jni/android_view_SurfaceSession.cpp
index 6ad109e..4f2ab09 100644
--- a/core/jni/android_view_SurfaceSession.cpp
+++ b/core/jni/android_view_SurfaceSession.cpp
@@ -42,14 +42,14 @@
 
 
 static jlong nativeCreate(JNIEnv* env, jclass clazz) {
-    SurfaceComposerClient* client = new SurfaceComposerClient();
-    client->incStrong((void*)nativeCreate);
-    return reinterpret_cast<jlong>(client);
+    // Will be deleted via decStrong() in nativeDestroy.
+    auto client = sp<SurfaceComposerClient>::make();
+    return reinterpret_cast<jlong>(client.release());
 }
 
 static void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
     SurfaceComposerClient* client = reinterpret_cast<SurfaceComposerClient*>(ptr);
-    client->decStrong((void*)nativeCreate);
+    client->decStrong((void*)client);
 }
 
 static const JNINativeMethod gMethods[] = {
diff --git a/core/jni/android_view_TextureView.cpp b/core/jni/android_view_TextureView.cpp
index 21fe1f0..f71878c 100644
--- a/core/jni/android_view_TextureView.cpp
+++ b/core/jni/android_view_TextureView.cpp
@@ -85,7 +85,7 @@
         jobject surface) {
 
     sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(env, surface));
-    sp<ANativeWindow> window = new Surface(producer, true);
+    sp<ANativeWindow> window = sp<Surface>::make(producer, true);
 
     window->incStrong((void*)android_view_TextureView_createNativeWindow);
     SET_LONG(textureView, gTextureViewClassInfo.nativeWindow, jlong(window.get()));
diff --git a/core/jni/com_android_internal_os_Zygote.cpp b/core/jni/com_android_internal_os_Zygote.cpp
index 8c7b335..42f4444 100644
--- a/core/jni/com_android_internal_os_Zygote.cpp
+++ b/core/jni/com_android_internal_os_Zygote.cpp
@@ -1833,6 +1833,15 @@
   ReloadBuildJavaConstants(env);
 }
 
+static void MountInitOverride(fail_fn_t fail_fn, JNIEnv* env) {
+    const char* init_etc_dir = "/system/etc/init";
+
+    if (TEMP_FAILURE_RETRY(mount("tmpfs", init_etc_dir, "tmpfs", MS_NOSUID | MS_NODEV | MS_NOEXEC,
+                                 "uid=0,gid=0,mode=0751")) == -1) {
+        fail_fn(CREATE_ERROR("Failed to mount tmpfs %s: %s", init_etc_dir, strerror(errno)));
+    }
+}
+
 static void BindMountStorageToLowerFs(const userid_t user_id, const uid_t uid,
     const char* dir_name, const char* package, fail_fn_t fail_fn) {
     bool hasSdcardFs = IsSdcardfsUsed();
@@ -1954,6 +1963,7 @@
 
     if (mount_sysprop_overrides) {
         BindMountSyspropOverride(fail_fn, env);
+        MountInitOverride(fail_fn, env);
     }
 
     // If this zygote isn't root, it won't be able to create a process group,
diff --git a/core/jni/com_google_android_gles_jni_EGLImpl.cpp b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
index 75330be..1b3b14d 100644
--- a/core/jni/com_google_android_gles_jni_EGLImpl.cpp
+++ b/core/jni/com_google_android_gles_jni_EGLImpl.cpp
@@ -300,7 +300,7 @@
     }
 
     sp<IGraphicBufferProducer> producer(SurfaceTexture_getProducer(_env, native_window));
-    window = new Surface(producer, true);
+    window = sp<Surface>::make(producer, true);
     if (window == NULL)
         goto not_valid_surface;
 
diff --git a/core/jni/platform/host/HostRuntime.cpp b/core/jni/platform/host/HostRuntime.cpp
index 746740b..1e8da73 100644
--- a/core/jni/platform/host/HostRuntime.cpp
+++ b/core/jni/platform/host/HostRuntime.cpp
@@ -280,12 +280,18 @@
     return string(chars.c_str());
 }
 
-static void loadIcuData(string icuPath) {
+static void loadIcuData(JNIEnv* env, string icuPath) {
     void* addr = mmapFile(icuPath.c_str());
+    if (addr == nullptr) {
+        jniThrowRuntimeException(env, "Failed to map the ICU data file.");
+    }
     UErrorCode err = U_ZERO_ERROR;
     udata_setCommonData(addr, &err);
     if (err != U_ZERO_ERROR) {
-        ALOGE("Unable to load ICU data\n");
+        jniThrowRuntimeException(env,
+                                 format("udata_setCommonData failed with error code {}",
+                                        u_errorName(err))
+                                         .c_str());
     }
 }
 
@@ -296,12 +302,12 @@
     JNIEnv* env = AndroidRuntime::getJNIEnv();
     string icuPath = base::GetProperty("ro.icu.data.path", "");
     if (!icuPath.empty()) {
-        loadIcuData(icuPath);
+        loadIcuData(env, icuPath);
     } else {
         // fallback to read from java.lang.System.getProperty
         string icuPathFromJava = getJavaProperty(env, "icu.data.path");
         if (!icuPathFromJava.empty()) {
-            loadIcuData(icuPathFromJava);
+            loadIcuData(env, icuPathFromJava);
         }
     }
 
diff --git a/core/proto/android/net/OWNERS b/core/proto/android/net/OWNERS
index 509699b..a6627fe 100644
--- a/core/proto/android/net/OWNERS
+++ b/core/proto/android/net/OWNERS
@@ -1,3 +1,2 @@
-ek@google.com
 lorenzo@google.com
 satk@google.com
diff --git a/core/proto/android/providers/settings/secure.proto b/core/proto/android/providers/settings/secure.proto
index 8de7746..ac4bac6 100644
--- a/core/proto/android/providers/settings/secure.proto
+++ b/core/proto/android/providers/settings/secure.proto
@@ -295,13 +295,6 @@
 
     optional SettingProto enhanced_voice_privacy_enabled = 23 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
-    message EvenDimmer {
-        optional SettingProto even_dimmer_activated = 1 [ (android.privacy).dest = DEST_AUTOMATIC ];
-        optional SettingProto even_dimmer_min_nits = 2 [ (android.privacy).dest = DEST_AUTOMATIC ];
-    }
-
-    optional EvenDimmer even_dimmer = 98;
-
     optional SettingProto font_weight_adjustment = 85 [ (android.privacy).dest = DEST_AUTOMATIC ];
 
     message Gesture {
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index a673ad7..5820c8e 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -216,10 +216,10 @@
     optional .com.android.server.wm.IdentifierProto resumed_activity = 24;
     repeated TaskProto tasks = 25 [deprecated=true];
     optional bool display_ready = 26;
-    optional WindowStateProto input_method_target = 27;
-    optional WindowStateProto input_method_input_target = 28;
-    optional WindowStateProto input_method_control_target = 29;
-    optional WindowStateProto current_focus = 30;
+    optional WindowStateProto input_method_target = 27 [deprecated = true];
+    optional WindowStateProto input_method_input_target = 28 [deprecated = true];
+    optional WindowStateProto input_method_control_target = 29 [deprecated = true];
+    optional WindowStateProto current_focus = 30 [deprecated = true];
     optional ImeInsetsSourceProviderProto ime_insets_source_provider = 31;
     optional bool can_show_ime = 32 [deprecated=true];
 
@@ -231,6 +231,10 @@
     repeated string sleep_tokens = 37;
     repeated .android.graphics.RectProto keep_clear_areas = 38;
     optional int32 min_size_of_resizeable_task_dp = 39;
+    optional IdentifierProto input_method_layering_target_identifier = 40;
+    optional IdentifierProto input_method_input_target_identifier = 41;
+    optional IdentifierProto input_method_control_target_identifier = 42;
+    optional IdentifierProto current_focus_identifier = 43;
 }
 
 /* represents DisplayArea object */
@@ -590,9 +594,9 @@
     optional .android.graphics.RectProto frame = 2;
     optional .android.view.InsetsSourceControlProto fake_control = 3;
     optional .android.view.InsetsSourceControlProto control = 4;
-    optional WindowStateProto control_target = 5;
-    optional WindowStateProto pending_control_target = 6;
-    optional WindowStateProto fake_control_target = 7;
+    optional WindowStateProto control_target = 5 [deprecated = true];
+    optional WindowStateProto pending_control_target = 6 [deprecated = true];
+    optional WindowStateProto fake_control_target = 7 [deprecated = true];
     optional .android.view.SurfaceControlProto captured_leash = 8;
     optional .android.graphics.RectProto ime_overridden_frame = 9 [deprecated=true];
     optional bool is_leash_ready_for_dispatching = 10;
@@ -601,15 +605,21 @@
     optional bool seamless_rotating = 13;
     optional int64 finish_seamless_rotate_frame_number = 14;
     optional bool controllable = 15;
-    optional WindowStateProto source_window_state = 16;
+    optional WindowStateProto source_window_state = 16 [deprecated = true];
+
+    optional IdentifierProto control_target_identifier = 17;
+    optional IdentifierProto pending_control_target_identifier = 18;
+    optional IdentifierProto fake_control_target_identifier = 19;
+    optional IdentifierProto source_window_state_identifier = 20;
 }
 
 message ImeInsetsSourceProviderProto {
     option (.android.msg_privacy).dest = DEST_AUTOMATIC;
 
     optional InsetsSourceProviderProto insets_source_provider = 1;
-    optional WindowStateProto ime_target_from_ime = 2;
+    optional WindowStateProto ime_target_from_ime = 2 [deprecated = true];
     optional bool is_ime_layout_drawn = 3 [deprecated=true];
+    optional IdentifierProto ime_target_from_ime_identifier = 4;
 }
 
 message BackNavigationProto {
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index e16ce98..36b65ba 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -9292,6 +9292,9 @@
                 <action android:name="android.intent.action.UPDATE_PINS" />
                 <data android:scheme="content" android:host="*" android:mimeType="*/*" />
             </intent-filter>
+            <intent-filter>
+                <action android:name="android.intent.action.BOOT_COMPLETED" />
+            </intent-filter>
         </receiver>
 
         <receiver android:name="com.android.server.updates.IntentFirewallInstallReceiver"
diff --git a/core/res/res/drawable/ic_accessibility_autoclick.xml b/core/res/res/drawable/ic_accessibility_autoclick.xml
new file mode 100644
index 0000000..44d34d3
--- /dev/null
+++ b/core/res/res/drawable/ic_accessibility_autoclick.xml
@@ -0,0 +1,8 @@
+<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
+    <background android:drawable="@color/accessibility_autoclick_background" />
+    <foreground>
+        <inset
+            android:drawable="@drawable/ic_accessibility_autoclick_foreground"
+            android:inset="@dimen/accessibility_icon_foreground_padding_ratio" />
+    </foreground>
+</adaptive-icon>
diff --git a/core/res/res/drawable/ic_accessibility_autoclick_foreground.xml b/core/res/res/drawable/ic_accessibility_autoclick_foreground.xml
new file mode 100644
index 0000000..0a76a1b
--- /dev/null
+++ b/core/res/res/drawable/ic_accessibility_autoclick_foreground.xml
@@ -0,0 +1,17 @@
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="40dp"
+    android:height="41dp"
+    android:viewportWidth="40"
+    android:viewportHeight="41">
+
+    <path
+        android:fillColor="#67D4FF"
+        android:pathData="M0 20.3789C0 9.33321 8.95431 0.378906 20 0.378906C31.0457 0.378906 40 9.33321 40 20.3789C40 31.4246 31.0457 40.3789 20 40.3789C8.95431 40.3789 0 31.4246 0 20.3789Z" />
+    <path
+        android:fillColor="#04409F"
+        android:pathData="M28.9564 32.0587L24.0973 27.1996L22.6765 31.4904L19.2666 20.124L30.633 23.5339L26.3422 24.9547L31.2013 29.8138L28.9564 32.0587Z" />
+    <path
+        android:fillColor="#04409F"
+        android:fillType="evenOdd"
+        android:pathData="M8.01596 20.8918C8.10753 22.8222 8.63239 24.6433 9.60868 26.3343C10.9014 28.5733 12.8274 30.221 15.1666 31.2713C16.9169 32.0453 18.7173 32.3866 20.5679 32.2953L19.9158 30.1502C18.5615 30.1389 17.2456 29.8364 15.9682 29.2427C14.0941 28.3832 12.6373 27.0532 11.5977 25.2526C10.7841 23.8434 10.3491 22.3305 10.2925 20.7139C10.2607 19.104 10.2783 17.806 10.9916 16.3295C10.9916 16.3295 11.4971 15.2881 11.6974 14.9932C11.8978 14.6983 12.7644 13.5882 12.7644 13.5882L11.3665 11.8494C11.3665 11.8494 10.6288 12.6605 10.291 13.1593C10.1116 13.4242 9.64185 14.1332 9.64185 14.1332L9.07295 15.2304C8.24895 17.0214 7.92073 18.8842 8.01596 20.8918ZM31.9633 21.2755L29.8026 20.6995C29.8208 20.1549 29.797 19.6129 29.7312 19.0733C29.6285 18.1723 29.3858 17.2999 29.0031 16.4562L30.8819 15.3714C31.3937 16.4747 31.7295 17.6169 31.8895 18.798C32.0056 19.6202 32.0302 20.4461 31.9633 21.2755ZM18.4931 8.55776C17.312 8.71775 16.1653 9.04578 15.053 9.54184L16.1513 11.4442C16.995 11.0615 17.8674 10.8188 18.7684 10.7161C19.6851 10.6043 20.6091 10.6137 21.5403 10.7441L22.1061 8.63249C20.8942 8.41364 19.6899 8.38872 18.4931 8.55776ZM24.1807 9.18837L23.6149 11.3C24.4865 11.6526 25.2869 12.0987 26.0158 12.6382C26.7448 13.1776 27.379 13.824 27.9183 14.5773L29.7972 13.4925C29.1223 12.5043 28.3055 11.6502 27.347 10.9302C26.4042 10.2011 25.3487 9.62046 24.1807 9.18837Z" />
+</vector>
diff --git a/core/res/res/values-af/strings.xml b/core/res/res/values-af/strings.xml
index b6b5d8b..9967209 100644
--- a/core/res/res/values-af/strings.xml
+++ b/core/res/res/values-af/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Eenhandmodus"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra donker"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Gehoortoestelle"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Outoklik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ontkoppel"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Gekoppel"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktief"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Jy kan jou gehoortoestel en mikrofoon vir handvrye oproepe gebruik. Dit skakel net jou mikrofoon tydens die oproep oor."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Skakel oor"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Instellings"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g> ."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Skakel tans oor na <xliff:g id="NAME">%1$s</xliff:g> …"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Meld <xliff:g id="NAME">%1$s</xliff:g> tans af …"</string>
     <string name="owner_name" msgid="8713560351570795743">"Eienaar"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Vra ontsluitpatroon voordat jy ontspeld"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Vra wagwoord voordat jy ontspeld"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Deur jou admin geïnstalleer.\nGaan na instellings om toegestaande toestemmings te sien"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Opgedateer deur jou administrateur"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Uitgevee deur jou administrateur"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Batterybespaarder skakel Donkertema aan en beperk of skakel agtergrondaktiwiteit, sommige visuele effekte, sekere kenmerke en sommige netwerkverbindings af"</string>
diff --git a/core/res/res/values-am/strings.xml b/core/res/res/values-am/strings.xml
index 29b153b..bdaf5a1 100644
--- a/core/res/res/values-am/strings.xml
+++ b/core/res/res/values-am/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"የአንድ እጅ ሁነታ"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ተጨማሪ ደብዛዛ"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"የመስሚያ መሣሪያዎች"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ራስ-ሰር ጠቅ ማድረግ"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ግንኙነት ተቋርጧል"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"ተገናኝቷል"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"ገቢር"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"የእርስዎን መስሚያ አጋዥ መሣሪያ ማይክሮፎን ለነጻ እጅ መደወል መጠቀም ይችላሉ። ይህ በጥሪው ወቅት ማይክሮፎንዎን ብቻ ይቀይራል።"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ቀይር"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ቅንብሮች"</string>
-    <string name="user_switched" msgid="7249833311585228097">"የአሁኑ ተጠቃሚ <xliff:g id="NAME">%1$s</xliff:g>።"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"ወደ <xliff:g id="NAME">%1$s</xliff:g> በመቀየር ላይ…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> በማውጣት ላይ…"</string>
     <string name="owner_name" msgid="8713560351570795743">"ባለቤት"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ከመንቀል በፊት የማስከፈቻ ሥርዓተ-ጥለት ጠይቅ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ከመንቀል በፊት የይለፍ ቃል ጠይቅ"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"በአስተዳዳሪዎ ተጭኗል።\nየተፈቀዱ ፍቃዶችን ለማየት ወደ ቅንብሮች ይሂዱ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"በእርስዎ አስተዳዳሪ ተዘምኗል"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"በእርስዎ አስተዳዳሪ ተሰርዟል"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"እሺ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ባትሪ ቆጣቢ ጠቆር ያለ ገጽታን ያበራል እና የጀርባ እንቅስቃሴን፣ አንዳንድ ዕይታዊ ውጤቶችን፣ አንዳንድ ባህሪዎችን፣ እና አንዳንድ የአውታረ መረብ ግንኙነቶችን ይገድባል ወይም ያጠፋል።"</string>
diff --git a/core/res/res/values-ar/strings.xml b/core/res/res/values-ar/strings.xml
index 08d0af5..3b0e78d 100644
--- a/core/res/res/values-ar/strings.xml
+++ b/core/res/res/values-ar/strings.xml
@@ -1807,8 +1807,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"وضع \"التصفح بيد واحدة\""</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"زيادة تعتيم الشاشة"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"سماعات الأذن الطبية"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"النقر التلقائي"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"غير متّصل"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"متّصل"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"متّصل حاليًا"</string>
@@ -1829,7 +1828,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"يمكنك استخدام ميكروفون سماعة الأذن الطبية لإجراء مكالمات بدون لمس الجهاز. يؤدي هذا الإجراء إلى تبديل الميكروفون فقط أثناء المكالمة."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"تبديل"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"الإعدادات"</string>
-    <string name="user_switched" msgid="7249833311585228097">"المستخدم الحالي <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"جارٍ التبديل إلى <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"جارٍ الخروج <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"المالك"</string>
@@ -1971,7 +1969,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"طلب إدخال نقش فتح القفل قبل إزالة التثبيت"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"طلب إدخال كلمة المرور قبل إزالة التثبيت"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"تم التثبيت من قِبل المشرف.\nانتقِل إلى الإعدادات للاطّلاع على الأذونات الممنوحة"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"تم التحديث بواسطة المشرف"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"تم الحذف بواسطة المشرف"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"حسنًا"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"يؤدي استخدام ميزة \"توفير شحن البطارية\" إلى تفعيل وضع \"المظهر الداكن\" وتقييد أو إيقاف الأنشطة في الخلفية وبعض التأثيرات المرئية وميزات معيّنة وبعض اتصالات الشبكات."</string>
diff --git a/core/res/res/values-as/strings.xml b/core/res/res/values-as/strings.xml
index 9eab313..5d93b65 100644
--- a/core/res/res/values-as/strings.xml
+++ b/core/res/res/values-as/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"এখন হাতেৰে ব্যৱহাৰ কৰাৰ ম’ড"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"অতিৰিক্তভাৱে পোহৰ কমোৱাৰ সুবিধা"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"শুনাৰ ডিভাইচ"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"স্বয়ংক্ৰিয়ভাৱে ক্লিক কৰাৰ সুবিধা"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"সংযোগ বিচ্ছিন্ন হ’ল"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"সংযোগ কৰা হ’ল"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"সক্ৰিয় হৈ আছে"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"আপুনি হেণ্ডছ্‌-ফ্ৰী কলিঙৰ বাবে আপোনাৰ শ্ৰৱণ যন্ত্ৰৰ মাইক্ৰ’ফ’ন ব্যৱহাৰ কৰিব পাৰে। এইটোৱে কল চলি থাকোঁতে কেৱল আপোনাৰ মাইকটো সলনি কৰে।"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"সলনি কৰক"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ছেটিং"</string>
-    <string name="user_switched" msgid="7249833311585228097">"বৰ্তমানৰ ব্যৱহাৰকাৰী <xliff:g id="NAME">%1$s</xliff:g>।"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>লৈ সলনি কৰি থকা হৈছে…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>ৰ পৰা লগ আউট কৰি থকা হৈছে…"</string>
     <string name="owner_name" msgid="8713560351570795743">"গৰাকী"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"আনপিন কৰাৰ পূৰ্বে আনলক আৰ্হি দিবলৈ কওক"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"আনপিন কৰাৰ পূৰ্বে পাছৱৰ্ড দিবলৈ কওক"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"আপোনাৰ প্ৰশাসকে ইনষ্টল কৰিছে।\nপ্ৰদান কৰা অনুমতিসমূহ চাবলৈ ছেটিঙলৈ যাওক"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"আপোনাৰ প্ৰশাসকে আপেডট কৰিছে"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"আপোনাৰ প্ৰশাসকে মচিছে"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"বেটাৰী সঞ্চয়কাৰীয়ে গাঢ় ৰঙৰ থীম অন কৰে আৰু নেপথ্যৰ কাৰ্যকলাপ, কিছুমান ভিজুৱেল ইফেক্ট, নিৰ্দিষ্ট কিছুমান সুবিধা আৰু নেটৱৰ্কৰ সংযোগ সীমিত অথবা অফ কৰে।"</string>
diff --git a/core/res/res/values-az/strings.xml b/core/res/res/values-az/strings.xml
index 3aec62a..c6a0ade 100644
--- a/core/res/res/values-az/strings.xml
+++ b/core/res/res/values-az/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Birəlli rejim"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Əlavə tündləşmə"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Eşitmə cihazları"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Avtomatik klikləmə"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Bağlantı kəsildi"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Qoşuldu"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivdir"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Səsli idarəetmə ilə zəng etmək üçün eşitmə aparatı mikrofonunuzdan istifadə edə bilərsiniz. Bu, yalnız zəng zamanı mikrofonu dəyişdirir."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Dəyişin"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Ayarlar"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Cari istifadəçi <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> adına keçirilir…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> çıxır..."</string>
     <string name="owner_name" msgid="8713560351570795743">"Sahib"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Qrafik açar istənilsin"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ayırmadan öncə parol istənilsin"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Admin quraşdırıb.\nVerilən icazələrə baxmaq üçün ayarlara keçin"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Admin tərəfindən yeniləndi"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Admin tərəfindən silindi"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Enerjiyə Qənaət rejimi Tünd temanı aktivləşdirir, habelə arxa fon fəaliyyətini, bəzi vizual effektləri, müəyyən xüsusiyyətləri və bəzi şəbəkə bağlantılarını məhdudlaşdırır, yaxud söndürür."</string>
diff --git a/core/res/res/values-b+sr+Latn/strings.xml b/core/res/res/values-b+sr+Latn/strings.xml
index 47203a9..2b4dc57 100644
--- a/core/res/res/values-b+sr+Latn/strings.xml
+++ b/core/res/res/values-b+sr+Latn/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Režim jednom rukom"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatno zatamni"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušni aparati"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatski klik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Veza je prekinuta"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Povezano"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivno"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Možete da koristite mikrofon slušnog aparata za hendsfri pozivanje. Time se mikrofon menja samo tokom poziva."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Promeni"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Podešavanja"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Aktuelni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Prebacivanje na <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Odjavljuje se <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Vlasnik"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Traži šablon za otključavanje pre otkačinjanja"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Traži lozinku pre otkačinjanja"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalirao je administrator.\nIdite u podešavanja da biste videli odobrene dozvole"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je administrator"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Potvrdi"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizuelne efekte, određene funkcije i neke mrežne veze."</string>
diff --git a/core/res/res/values-be/strings.xml b/core/res/res/values-be/strings.xml
index 8230f0c..8230b1c 100644
--- a/core/res/res/values-be/strings.xml
+++ b/core/res/res/values-be/strings.xml
@@ -159,7 +159,7 @@
     <string name="cfTemplateForwardedTime" msgid="735042369233323609">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: <xliff:g id="DIALING_NUMBER">{1}</xliff:g> праз <xliff:g id="TIME_DELAY">{2}</xliff:g> с."</string>
     <string name="cfTemplateRegistered" msgid="5619930473441550596">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не пераадрасоўваецца"</string>
     <string name="cfTemplateRegisteredTime" msgid="5222794399642525045">"<xliff:g id="BEARER_SERVICE_CODE">{0}</xliff:g>: не пераадрасоўваецца"</string>
-    <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Сеткавая бяспека"</string>
+    <string name="scCellularNetworkSecurityTitle" msgid="7752521808690294384">"Бяспека мабільнай сеткі"</string>
     <string name="scCellularNetworkSecuritySummary" msgid="7042036754550545005">"Шыфраванне, апавяшчэнні для незашыфраваных сетак"</string>
     <string name="scIdentifierDisclosureIssueTitle" msgid="2898888825129970328">"Атрыманы доступ да ідэнтыфікатара прылады"</string>
     <string name="scIdentifierDisclosureIssueSummaryNotification" msgid="3699930821270580416">"У <xliff:g id="DISCLOSURE_TIME">%1$s</xliff:g> у сетцы паблізу быў запісаны ўнікальны ідэнтыфікатар вашай прылады (IMSI або IMEI) пры выкарыстанні SIM-карты <xliff:g id="DISCLOSURE_NETWORK">%2$s</xliff:g>"</string>
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Рэжым кіравання адной рукой"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дадатковае памяншэнне яркасці"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слыхавыя апараты"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Аўтанацісканне"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Адключана"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Падключана"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Актыўная"</string>
@@ -1827,7 +1826,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Вы можаце выкарыстоўваць мікрафон слыхавога апарата, каб размаўляць падчас званка без дапамогі рук. Будзе пераключаны толькі ваш мікрафон."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Пераключыцца"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Налады"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Бягучы карыстальнік <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Пераключэнне на карыстальніка \"<xliff:g id="NAME">%1$s</xliff:g>\"…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> выходзіць з сістэмы…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Уладальнік"</string>
@@ -1969,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запытваць узор разблакіроўкі перад адмацаваннем"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запытваць пароль перад адмацаваннем"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Усталявана адміністратарам.\nКаб паглядзець дадзеныя дазволы, перайдзіце ў налады"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Абноўлены вашым адміністратарам"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Выдалены вашым адміністратарам"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"У рэжыме энергазберажэння ўключаецца цёмная тэма і выключаюцца ці абмяжоўваюцца дзеянні ў фонавым рэжыме, некаторыя візуальныя эфекты, пэўныя функцыі і падключэнні да сетак."</string>
diff --git a/core/res/res/values-bg/strings.xml b/core/res/res/values-bg/strings.xml
index d9471e6..1b0477f 100644
--- a/core/res/res/values-bg/strings.xml
+++ b/core/res/res/values-bg/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Работа с една ръка"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Допълнително затъмняване"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слухови апарати"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Автоматично кликване"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Няма връзка"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Свързано"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Активно"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Можете да използвате микрофона на слуховия си апарат за обаждания в режим „свободни ръце“. Микрофонът ще бъде включен само по време на обаждането."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Превключване"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Настройки"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Текущ потребител <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Превключва се към: <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> излиза…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Собственик"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запитване за фигура за отключване преди освобождаване"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запитване за парола преди освобождаване"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Инсталирано от администратора ви.\nОтворете настройките, за да прегледате предоставените разрешения"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Актуализирано от администратора ви"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Изтрито от администратора ви"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Режимът за запазване на батерията включва тъмната тема и ограничава или изключва активността на заден план, някои визуални ефекти, определени функции и някои връзки с мрежата."</string>
diff --git a/core/res/res/values-bn/strings.xml b/core/res/res/values-bn/strings.xml
index cc05d28..2461a70 100644
--- a/core/res/res/values-bn/strings.xml
+++ b/core/res/res/values-bn/strings.xml
@@ -327,7 +327,7 @@
     <string name="permgroupdesc_contacts" msgid="9163927941244182567">"আপনার পরিচিতিগুলিতে অ্যাক্সেস"</string>
     <string name="permgrouplab_location" msgid="1858277002233964394">"লোকেশন"</string>
     <string name="permgroupdesc_location" msgid="1995955142118450685">"এই ডিভাইসের লোকেশন অ্যাক্সেস"</string>
-    <string name="permgrouplab_calendar" msgid="6426860926123033230">"ক্যালেন্ডার"</string>
+    <string name="permgrouplab_calendar" msgid="6426860926123033230">"Calendar"</string>
     <string name="permgroupdesc_calendar" msgid="6762751063361489379">"আপনার ক্যালেন্ডারে অ্যাক্সেস"</string>
     <string name="permgrouplab_sms" msgid="795737735126084874">"SMS"</string>
     <string name="permgroupdesc_sms" msgid="5726462398070064542">"এসএমএসগুলি পাঠাতে এবং দেখতে"</string>
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"এক হাতে ব্যবহার করার মোড"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"অতিরিক্ত কম উজ্জ্বলতা"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"হিয়ারিং ডিভাইস"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"অটোক্লিক"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ডিসকানেক্ট হয়ে গেছে"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"কানেক্ট করা হয়েছে"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"অ্যাক্টিভ"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"হ্যান্ডস-ফ্রি কলিংয়ের জন্য আপনার হিয়ারিং এডের মাইক্রোফোন ব্যবহার করতে পারবেন। এটি শুধুমাত্র কল চলাকালীন আপনার মাইক পরিবর্তন করে।"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"পরিবর্তন করুন"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"সেটিংস"</string>
-    <string name="user_switched" msgid="7249833311585228097">"বর্তমান ব্যবহারকারী <xliff:g id="NAME">%1$s</xliff:g>৷"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> প্রোফাইলে পাল্টানো হচ্ছে…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>কে লগ-আউট করা হচ্ছে..."</string>
     <string name="owner_name" msgid="8713560351570795743">"মালিক"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"আনপিন করার আগে আনলক প্যাটার্ন চান"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"আনপিন করার আগে পাসওয়ার্ড চান"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"আপনার অ্যাডমিন ইনস্টল করেছেন।\nঅনুমোদন করা অনুমতি দেখতে সেটিংসে যান"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"আপনার প্রশাসক আপডেট করেছেন"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"আপনার প্রশাসক মুছে দিয়েছেন"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ঠিক আছে"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ব্যাটারি সেভার ডার্ক থিম চালু করে এবং ব্যাকগ্রাউন্ড অ্যাক্টিভিটি, কিছু ভিজ্যুয়াল এফেক্ট, নির্দিষ্ট ফিচার ও কয়েকটি নেটওয়ার্ক কানেকশনের ব্যবহার সীমিত করে বা বন্ধ করে দেয়।"</string>
diff --git a/core/res/res/values-bs/strings.xml b/core/res/res/values-bs/strings.xml
index 9c553ce..b8d3283 100644
--- a/core/res/res/values-bs/strings.xml
+++ b/core/res/res/values-bs/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Način rada jednom rukom"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatno zatamnjenje"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušni aparati"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatski klik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Nije povezano"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Povezano"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivno"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Možete koristiti mikrofon slušnog aparata za pozivanje bez dodira. Ovo mijenja mikrofon samo tokom poziva."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Promijeni"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Postavke"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Trenutni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Prebacivanje na korisnika <xliff:g id="NAME">%1$s</xliff:g>..."</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Odjava korisnika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Vlasnik"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Traži uzorak za otključavanje prije poništavanja kačenja"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Traži lozinku prije nego se otkači"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalirao je vaš administrator.\nIdite u postavke da pregledate data odobrenja"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao je vaš administrator"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao je vaš administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Uredu"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ušteda baterije uključuje tamnu temu i ograničava ili isključuje aktivnost u pozadini, određene vizuelne efekte i funkcije te neke mrežne veze."</string>
diff --git a/core/res/res/values-ca/strings.xml b/core/res/res/values-ca/strings.xml
index 3fa177e..cbfa521 100644
--- a/core/res/res/values-ca/strings.xml
+++ b/core/res/res/values-ca/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode d\'una mà"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuació extra"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Audiòfons"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automàtic"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconnectat"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connectat"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Actiu"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Pots fer servir el micròfon del teu audiòfon per fer trucades amb mans lliures. Aquesta opció només canvia el micròfon durant la trucada."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Canvia"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Configuració"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Usuari actual: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"S\'està canviant a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"S\'està tancant la sessió de l\'usuari <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Propietari"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Sol·licita el patró de desbloqueig per deixar de fixar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Demana la contrasenya per deixar de fixar"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instal·lat per l\'administrador.\nVes a la configuració per veure els permisos concedits."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualitzat per l\'administrador"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Suprimit per l\'administrador"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"D\'acord"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Estalvi de bateria activa el tema fosc i limita o desactiva l\'activitat en segon pla, alguns efectes visuals, determinades funcions i algunes connexions de xarxa."</string>
diff --git a/core/res/res/values-cs/strings.xml b/core/res/res/values-cs/strings.xml
index 670ca33..356cdc7 100644
--- a/core/res/res/values-cs/strings.xml
+++ b/core/res/res/values-cs/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Režim jedné ruky"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Velmi tmavé zobrazení"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Naslouchátka"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatické kliknutí"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Odpojeno"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Připojeno"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivní"</string>
@@ -1827,7 +1826,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"K handsfree telefonování můžete použít mikrofon naslouchátka. Mikrofon se přepne jen během hovoru."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Přepnout"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Nastavení"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Aktuální uživatel je <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Přepínání na uživatele <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Odhlašování uživatele <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Vlastník"</string>
@@ -1969,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Před uvolněním požádat o bezpečnostní gesto"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Před odepnutím požádat o heslo"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Nainstalováno administrátorem.\nUdělená oprávnění si můžete prohlédnout v nastavení."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizováno administrátorem"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Smazáno administrátorem"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Spořič baterie zapíná tmavý motiv a omezuje či vypíná aktivitu na pozadí, některé vizuální efekty, některé funkce a připojení k některým sítím."</string>
diff --git a/core/res/res/values-da/strings.xml b/core/res/res/values-da/strings.xml
index 47eb357..efe3e10 100644
--- a/core/res/res/values-da/strings.xml
+++ b/core/res/res/values-da/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhåndstilstand"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra dæmpet belysning"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Høreapparater"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoklik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ikke forbundet"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Forbundet"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiv"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Du kan bruge mikrofonen i dit høreapparat til at foretage håndfrie opkald. Der skiftes kun mikrofon under opkaldet."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Skift"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Indstillinger"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Nuværende bruger <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Skifter til <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> logges ud…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Ejer"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Bed om oplåsningsmønster ved deaktivering"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Bed om adgangskode inden frigørelse"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installeret af din administrator.\nGå til Indstillinger for at se de tilladelser, der er blevet givet"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Opdateret af din administrator"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet af din administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Batterisparefunktionen aktiverer Mørkt tema og begrænser eller deaktiverer aktivitet i baggrunden og visse visuelle effekter, funktioner og netværksforbindelser."</string>
diff --git a/core/res/res/values-de/strings.xml b/core/res/res/values-de/strings.xml
index 06a35e6..fc0e9ed 100644
--- a/core/res/res/values-de/strings.xml
+++ b/core/res/res/values-de/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Einhandmodus"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extradunkel"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hörgeräte"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatischer Klick"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Nicht verbunden"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Verbunden"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiv"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Du kannst das Mikrofon deines Hörgeräts für Anrufe per Sprachbefehl verwenden. Das Mikrofon wird nur für die Dauer des Anrufs gewechselt."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Wechseln"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Einstellungen"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Aktueller Nutzer <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Wechseln zu <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> wird abgemeldet…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Eigentümer"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Vor dem Beenden nach Entsperrungsmuster fragen"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Vor dem Beenden nach Passwort fragen"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Von deinem Administrator installiert.\nRufe die Einstellungen auf, um gewährte Berechtigungen anzusehen."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Von deinem Administrator aktualisiert"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Von deinem Administrator gelöscht"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Der Energiesparmodus aktiviert das dunkle Design. Hintergrundaktivitäten, einige Funktionen und optische Effekte und manche Netzwerkverbindungen werden eingeschränkt oder deaktiviert."</string>
diff --git a/core/res/res/values-el/strings.xml b/core/res/res/values-el/strings.xml
index 8a12e0e..58f5d9d 100644
--- a/core/res/res/values-el/strings.xml
+++ b/core/res/res/values-el/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Λειτουργία ενός χεριού"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Επιπλέον μείωση φωτεινότητας"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Συσκευές ακοής"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Αυτόματο κλικ"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Αποσυνδέθηκε"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Συνδέθηκε"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Ενεργή"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Μπορείτε να χρησιμοποιήσετε το μικρόφωνο του βοηθήματος ακοής σας για κλήσεις handsfree. Με αυτή την ενέργεια, το μικρόφωνό σας αλλάζει μόνο κατά τη διάρκεια της κλήσης."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Εναλλαγή"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Ρυθμίσεις"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Τρέχων χρήστης <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Εναλλαγή σε <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Αποσύνδεση <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Κάτοχος"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Να γίνεται ερώτηση για το μοτίβο ξεκλειδώματος, πριν από το ξεκαρφίτσωμα"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Να γίνεται ερώτηση για τον κωδικό πρόσβασης, πριν από το ξεκαρφίτσωμα"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Εγκαταστάθηκε από τον διαχειριστή σας.\nΜεταβείτε στις ρυθμίσεις για να δείτε τις άδειες που έχουν εκχωρηθεί"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Ενημερώθηκε από τον διαχειριστή σας"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Διαγράφηκε από τον διαχειριστή σας"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Η Εξοικονόμηση μπαταρίας ενεργοποιεί το Σκούρο θέμα και περιορίζει ή απενεργοποιεί τη δραστηριότητα στο παρασκήνιο, ορισμένα οπτικά εφέ, συγκεκριμένες λειτουργίες και κάποιες συνδέσεις δικτύου."</string>
diff --git a/core/res/res/values-en-rAU/strings.xml b/core/res/res/values-en-rAU/strings.xml
index 3881f1d..320e639 100644
--- a/core/res/res/values-en-rAU/strings.xml
+++ b/core/res/res/values-en-rAU/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-handed mode"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoclick"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Disconnected"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connected"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Active"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"You can use your hearing aid microphone for hands-free calling. This only switches your mic during the call."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Switch"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Settings"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Switching to <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Logging out <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Owner"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installed by your admin.\nGo to Settings to view granted permissions"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, certain features and some network connections."</string>
diff --git a/core/res/res/values-en-rCA/strings.xml b/core/res/res/values-en-rCA/strings.xml
index e6c4047..85471d8 100644
--- a/core/res/res/values-en-rCA/strings.xml
+++ b/core/res/res/values-en-rCA/strings.xml
@@ -1824,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"You can use your hearing aid microphone for hands-free calling. This only switches your mic during the call."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Switch"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Settings"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Switching to <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Logging out <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Owner"</string>
@@ -1966,7 +1965,7 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installed by your admin.\nGo to settings to view granted permissions"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
+    <string name="package_updated_device_owner" msgid="7770195449213776218">"Updated by your admin.\nGo to settings to view granted permissions"</string>
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, certain features, and some network connections."</string>
diff --git a/core/res/res/values-en-rGB/strings.xml b/core/res/res/values-en-rGB/strings.xml
index 9680b83..730dd3b 100644
--- a/core/res/res/values-en-rGB/strings.xml
+++ b/core/res/res/values-en-rGB/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-handed mode"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoclick"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Disconnected"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connected"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Active"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"You can use your hearing aid microphone for hands-free calling. This only switches your mic during the call."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Switch"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Settings"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Switching to <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Logging out <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Owner"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installed by your admin.\nGo to Settings to view granted permissions"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, certain features and some network connections."</string>
diff --git a/core/res/res/values-en-rIN/strings.xml b/core/res/res/values-en-rIN/strings.xml
index fbe1c0a..a9654e5 100644
--- a/core/res/res/values-en-rIN/strings.xml
+++ b/core/res/res/values-en-rIN/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-handed mode"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hearing devices"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoclick"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Disconnected"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connected"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Active"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"You can use your hearing aid microphone for hands-free calling. This only switches your mic during the call."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Switch"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Settings"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Current user <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Switching to <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Logging out <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Owner"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ask for unlock pattern before unpinning"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Ask for password before unpinning"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installed by your admin.\nGo to Settings to view granted permissions"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Updated by your admin"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Deleted by your admin"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Battery Saver turns on Dark theme and limits or turns off background activity, some visual effects, certain features and some network connections."</string>
diff --git a/core/res/res/values-es-rUS/strings.xml b/core/res/res/values-es-rUS/strings.xml
index 54297a5..036ecfc 100644
--- a/core/res/res/values-es-rUS/strings.xml
+++ b/core/res/res/values-es-rUS/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo de una mano"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuación extra"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automático"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Activo"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Puedes usar el micrófono de tu audífono para realizar llamadas sin usar las manos. Esto solo cambia el micrófono durante la llamada."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Cambiar"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Configuración"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Cambiando a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Saliendo de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Propietario"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Solicitar desbloqueo para quitar fijación"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicitar contraseña para quitar fijación"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Tu administrador realizó la instalación.\nVe a la configuración para ver los permisos otorgados"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Tu administrador actualizó este paquete"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Tu administrador borró este paquete"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"El Ahorro de batería activa el Tema oscuro y desactiva o restringe la actividad en segundo plano, algunos efectos visuales, algunas conexiones de red y otras funciones determinadas."</string>
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index 5bd2bf5..3553aea 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo Una mano"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuación extra"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Audífonos"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automático"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Activo"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Puedes usar el micrófono de tu audífono para hacer llamadas en manos libres. Esta opción solo cambia el micrófono durante la llamada."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Cambiar"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Ajustes"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Usuario actual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Cambiando a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Cerrando la sesión de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Propietario"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir patrón de desbloqueo para dejar de fijar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicitar contraseña para desactivar"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalado por tu administrador.\nVe a Ajustes para ver los permisos concedidos."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado por el administrador"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado por el administrador"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ahorro de batería activa el tema oscuro y limita o desactiva la actividad en segundo plano, algunos efectos visuales, ciertas funciones y algunas conexiones de red."</string>
diff --git a/core/res/res/values-et/strings.xml b/core/res/res/values-et/strings.xml
index 0c928a6..abecc1a 100644
--- a/core/res/res/values-et/strings.xml
+++ b/core/res/res/values-et/strings.xml
@@ -652,7 +652,7 @@
     <string name="permdesc_imagesWrite" msgid="5195054463269193317">"Võimaldab rakendusel muuta teie fotokogu."</string>
     <string name="permlab_mediaLocation" msgid="7368098373378598066">"Lugeda teie meediakogus olevaid asukohti"</string>
     <string name="permdesc_mediaLocation" msgid="597912899423578138">"Võimaldab rakendusel lugeda teie meediakogus olevaid asukohti."</string>
-    <string name="permlab_eye_tracking_coarse" msgid="7989596289790269059">"ligikaudse pilgu jälgimine"</string>
+    <string name="permlab_eye_tracking_coarse" msgid="7989596289790269059">"pilgu ligikaudne jälgimine"</string>
     <string name="permdesc_eye_tracking_coarse" msgid="870510233930553355">"Võimaldab rakendusel teie pilku ligikaudselt jälgida."</string>
     <string name="permlab_eye_tracking_fine" msgid="6914457357027049512">"pilgu suuna jälgimine"</string>
     <string name="permdesc_eye_tracking_fine" msgid="5788889152304524730">"Võimaldab rakendusel juurde pääseda täpsetele pilguandmetele."</string>
@@ -665,9 +665,9 @@
     <string name="permlab_scene_understanding_coarse" msgid="6518646430502858641">"vahetu keskkonna mõistmine"</string>
     <string name="permdesc_scene_understanding_coarse" msgid="4508880777646198656">"Võimaldab rakendusel juurde pääseda teie vahetu keskkonna jälgimisandmetele."</string>
     <string name="permlab_scene_understanding_fine" msgid="409126403264393251">"vahetu keskkonna väga üksikasjalik mõistmine"</string>
-    <string name="permdesc_scene_understanding_fine" msgid="6223368011593524179">"Võimaldab rakendusel pääseda väga üksikasjalikult juurde teie vahetu keskkonna jälgimisandmetele."</string>
-    <string name="permlab_xr_tracking_in_background" msgid="7117098718465619023">"juurdepääs XR-i andmetele, kui see pole esiplaanil"</string>
-    <string name="permdesc_xr_tracking_in_background" msgid="939504041387836853">"Võimaldab rakendusel pääseda juurde XR-i andmetele, kui see pole esiplaanil."</string>
+    <string name="permdesc_scene_understanding_fine" msgid="6223368011593524179">"Võimaldab rakendusel pääseda juurde teie ümbruskonna üksikasjalikele jälgimisandmetele."</string>
+    <string name="permlab_xr_tracking_in_background" msgid="7117098718465619023">"juurdepääs XR-i andmetele, kui rakendus pole esiplaanil"</string>
+    <string name="permdesc_xr_tracking_in_background" msgid="939504041387836853">"Võimaldab rakendusel pääseda juurde XR-i andmetele, kui rakendus pole esiplaanil."</string>
     <string name="biometric_app_setting_name" msgid="3339209978734534457">"Biomeetria kasutamine"</string>
     <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Biomeetria või ekraaniluku kasutamine"</string>
     <string name="biometric_dialog_default_title" msgid="55026799173208210">"Kinnitage oma isik"</string>
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Ühekäerežiim"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Eriti tume"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Kuuldeseadmed"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automaatklikk"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ühendus katkestatud"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ühendatud"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiivne"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Saate kasutada oma kuuldeaparaadi mikrofon vabakäerežiimis helistamiseks. See vahetab teie mikrofoni ainult kõne ajal."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Vaheta"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Seaded"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Praegune kasutaja <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Üleminek kasutajale <xliff:g id="NAME">%1$s</xliff:g> ..."</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Kasutaja <xliff:g id="NAME">%1$s</xliff:g> väljalogimine …"</string>
     <string name="owner_name" msgid="8713560351570795743">"Omanik"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Enne vabastamist küsi avamismustrit"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Enne vabastamist küsi parooli"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installis teie administraator.\nAntud õiguste vaatamiseks avage seaded"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Administraator on seda värskendanud"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administraator on selle kustutanud"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Akusäästja lülitab sisse tumeda teema ja lülitab välja taustategevused, mõned visuaalsed efektid, teatud funktsioonid ja võrguühendused või piirab neid."</string>
diff --git a/core/res/res/values-eu/strings.xml b/core/res/res/values-eu/strings.xml
index 13f0452..64dc730 100644
--- a/core/res/res/values-eu/strings.xml
+++ b/core/res/res/values-eu/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Esku bakarreko modua"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Are ilunago"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Entzumen-gailuak"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatikoki klik egiteko eginbidea"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Deskonektatuta"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Konektatuta"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktibo"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Audifonoaren mikrofonoa erabil dezakezu esku libreko deiak egiteko. Deirako soilik aldatzen da mikrofonoa."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Aldatu"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Ezarpenak"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Erabiltzailea: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"\"<xliff:g id="NAME">%1$s</xliff:g>\" erabiltzailera aldatzen…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> erabiltzailearen saioa amaitzen…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Jabea"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Eskatu desblokeatzeko eredua aingura kendu aurretik"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Eskatu pasahitza aingura kendu aurretik"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Administratzaileak instalatu du.\nEmandako baimenak ikusteko, joan ezarpenetara."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Administratzaileak eguneratu du"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratzaileak ezabatu du"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Ados"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Bateria-aurreztaileak gai iluna aktibatzen du, eta atzeko planoko jarduerak, zenbait efektu bisual, eta eginbide jakin eta sareko konexio batzuk mugatzen edo desaktibatzen ditu."</string>
diff --git a/core/res/res/values-fa/strings.xml b/core/res/res/values-fa/strings.xml
index 2eaf4c0..13083d0 100644
--- a/core/res/res/values-fa/strings.xml
+++ b/core/res/res/values-fa/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"حالت یک‌دستی"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"بسیار کم‌نور"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"دستگاه‌های کمک‌شنوایی"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"کلیک خودکار"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"متصل نیست"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"وصل شد"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"فعال"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"برای تماس دست‌آزاد می‌توانید از میکروفون سمعک خود استفاده کنید. این کار فقط درطول تماس میکروفون شما را عوض می‌کند."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"عوض کردن"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"تنظیمات"</string>
-    <string name="user_switched" msgid="7249833311585228097">"کاربر کنونی <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"در حالت تغییر به <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"در حال خروج از سیستم <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"مالک"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"درخواست الگوی بازگشایی قفل قبل‌از برداشتن سنجاق"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"درخواست گذرواژه قبل از برداشتن سنجاق"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"سرپرست شما آن را نصب کرده است.\nبرای مشاهده اجازه‌های اعطاشده به تنظیمات بروید"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"توسط سرپرست سیستم به‌روزرسانی شد"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"توسط سرپرست سیستم حذف شد"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"تأیید"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"«بهینه‌سازی باتری» «زمینه تاریک» را روشن می‌کند و فعالیت پس‌زمینه، برخی از جلوه‌های بصری، ویژگی‌هایی خاص، و برخی از اتصال‌های شبکه را محدود یا خاموش می‌کند."</string>
diff --git a/core/res/res/values-fi/strings.xml b/core/res/res/values-fi/strings.xml
index 280658c..145c5ee 100644
--- a/core/res/res/values-fi/strings.xml
+++ b/core/res/res/values-fi/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Yhden käden moodi"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Erittäin himmeä"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Kuulolaitteet"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automaattinen klikkaus"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Yhteys katkaistu"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Yhdistetty"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiivinen"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Voit soittaa ääniohjatusti kuulolaitteen mikrofonin avulla. Tämä vaihtaa mikrofonia vain puhelun ajaksi."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Vaihda"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Asetukset"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Nykyinen käyttäjä: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Vaihdetaan käyttäjään <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> kirjautuu ulos…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Omistaja"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pyydä lukituksenpoistokuvio ennen irrotusta"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pyydä salasana ennen irrotusta"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Järjestelmänvalvojan asentama.\nTarkista myönnetyt luvat asetuksista."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Järjestelmänvalvoja päivitti tämän."</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Järjestelmänvalvoja poisti tämän."</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Virransäästö laittaa tumman teeman päälle ja rajoittaa tai laittaa pois päältä taustatoimintoja, tiettyjä ominaisuuksia sekä joitakin visuaalisia tehosteita ja verkkoyhteyksiä."</string>
diff --git a/core/res/res/values-fr-rCA/strings.xml b/core/res/res/values-fr-rCA/strings.xml
index 1740ce5..0ee4112 100644
--- a/core/res/res/values-fr-rCA/strings.xml
+++ b/core/res/res/values-fr-rCA/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode Une main"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Très sombre"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Appareils auditifs"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automatique"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Déconnecté"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connecté"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Actif"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Vous pouvez utiliser votre microphone pour prothèse auditive pour faire des appels en mode mains libres. Cette option ne change votre micro que pendant l\'appel."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Changer"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Paramètres"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Passage au profil : <xliff:g id="NAME">%1$s</xliff:g> en cours…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Déconnexion de <xliff:g id="NAME">%1$s</xliff:g> en cours..."</string>
     <string name="owner_name" msgid="8713560351570795743">"Propriétaire"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Demander le schéma de déverrouillage avant d\'annuler l\'épinglage"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Demander le mot de passe avant d\'annuler l\'épinglage"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installé par votre administrateur.\nAccédez aux paramètres pour consulter les autorisations accordées"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Mise à jour par votre administrateur"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Le mode Économiseur de pile active le thème sombre et limite ou désactive l\'activité en arrière-plan, certains effets visuels, certaines fonctionnalités et certaines connexions réseau."</string>
diff --git a/core/res/res/values-fr/strings.xml b/core/res/res/values-fr/strings.xml
index 0564661..a5b6f9a 100644
--- a/core/res/res/values-fr/strings.xml
+++ b/core/res/res/values-fr/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode une main"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Luminosité ultra-réduite"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Appareils auditifs"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automatique"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Déconnecté"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connecté"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Actif"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Vous pouvez utiliser le micro de votre appareil auditif pour passer des appels en mode mains-libres. Cette option change uniquement le micro pendant l\'appel."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Changer"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Paramètres"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Utilisateur actuel : <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Passage à <xliff:g id="NAME">%1$s</xliff:g>..."</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Déconnexion de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Propriétaire"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Demander le schéma de déverrouillage avant de retirer l\'épingle"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Demander le mot de passe avant de retirer l\'épingle"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installé par votre administrateur.\nAllez dans les paramètres pour consulter les autorisations accordées."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Mis à jour par votre administrateur"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Supprimé par votre administrateur"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"L\'économiseur de batterie active le thème sombre et limite ou désactive l\'activité en arrière-plan ainsi que certains effets visuels, fonctionnalités et connexions réseau."</string>
diff --git a/core/res/res/values-gl/strings.xml b/core/res/res/values-gl/strings.xml
index 73bed7f..332387a 100644
--- a/core/res/res/values-gl/strings.xml
+++ b/core/res/res/values-gl/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo dunha soa man"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Atenuación extra"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automático"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Activo"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Podes usar o micrófono do audiófono para facer chamadas coas mans libres. Esta acción só cambia o micrófono durante a chamada."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Cambiar"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Configuración"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Usuario actual <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Cambiando a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Pechando sesión de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Propietario"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrón de desbloqueo antes de soltar a fixación"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir contrasinal antes de soltar a fixación"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalado pola persoa administradora.\nVai á configuración para ver os permisos concedidos"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizado polo teu administrador"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado polo teu administrador"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Aceptar"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Coa función Aforro de batería, actívase o tema escuro e restrínxense ou desactívanse a actividade en segundo plano, algúns efectos visuais e determinadas funcións e conexións de rede."</string>
diff --git a/core/res/res/values-gu/strings.xml b/core/res/res/values-gu/strings.xml
index 0c99096..7a39d63 100644
--- a/core/res/res/values-gu/strings.xml
+++ b/core/res/res/values-gu/strings.xml
@@ -1825,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"તમે હાથના ઉપયોગ વિના કૉલ કરવા માટે સાંભળવામાં મદદ આપતા તમારા યંત્રના માઇક્રોફોનનો ઉપયોગ કરી શકો છો. કૉલ દરમિયાન આ ફક્ત તમારા માઇકને સ્વિચ કરે છે."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"સ્વિચ કરો"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"સેટિંગ"</string>
-    <string name="user_switched" msgid="7249833311585228097">"વર્તમાન વપરાશકર્તા <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> પર સ્વિચ કરી રહ્યાં છીએ…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> લોગ આઉટ થઈ રહ્યાં છે…"</string>
     <string name="owner_name" msgid="8713560351570795743">"માલિક"</string>
@@ -1967,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"અનપિન કરતા પહેલાં અનલૉક પૅટર્ન માટે પૂછો"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"અનપિન કરતાં પહેલાં પાસવર્ડ માટે પૂછો"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"તમારા ઍડમિન દ્વારા ઇન્સ્ટૉલ કરવામાં આવ્યું છે.\nઆપેલી પરવાનગીઓ જોવા માટે સેટિંગ પર જાઓ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"તમારા વ્યવસ્થાપક દ્વારા અપડેટ કરવામાં આવેલ છે"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"તમારા વ્યવસ્થાપક દ્વારા કાઢી નાખવામાં આવેલ છે"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ઓકે"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"બૅટરી સેવર ઘેરી થીમની સુવિધા ચાલુ કરે છે અને બૅકગ્રાઉન્ડ પ્રવૃત્તિ, અમુક વિઝ્યુઅલ ઇફેક્ટ, અમુક સુવિધાઓ અને કેટલાક નેટવર્ક કનેક્શન મર્યાદિત કે બંધ કરે છે."</string>
diff --git a/core/res/res/values-hi/strings.xml b/core/res/res/values-hi/strings.xml
index df211dc..2c43996 100644
--- a/core/res/res/values-hi/strings.xml
+++ b/core/res/res/values-hi/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"वन-हैंडेड मोड"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"स्क्रीन की रोशनी को सामान्य लेवल से और कम करने की सुविधा"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"कान की मशीन"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"अपने-आप क्लिक होने की सुविधा"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"डिसकनेक्ट हो गया"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"कनेक्ट हो गया"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"चालू है"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"बोलकर कॉल का जवाब देने के लिए, \'कान की मशीन का माइक्रोफ़ोन\' इस्तेमाल किया जा सकता है. इससे, कॉल के दौरान सिर्फ़ आपका माइक चालू या बंद होता है."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"स्विच करें"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"सेटिंग"</string>
-    <string name="user_switched" msgid="7249833311585228097">"मौजूदा उपयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> पर स्विच किया जा रहा है…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> द्वारा प्रस्‍थान किया जा रहा है…"</string>
     <string name="owner_name" msgid="8713560351570795743">"मालिक"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"अनपिन करने से पहले लॉक खोलने के पैटर्न के लिए पूछें"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"अनपिन करने से पहले पासवर्ड के लिए पूछें"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"इसे आपके एडमिन ने इंस्टॉल किया है.\nजिन अनुमतियों को मंज़ूरी मिली है उन्हें देखने के लिए, सेटिंग में जाएं"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"आपके व्यवस्थापक ने अपडेट किया है"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"आपके व्यवस्थापक ने हटा दिया है"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ठीक है"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"बैटरी सेवर, गहरे रंग वाली थीम को चालू करता है. साथ ही, इस मोड में बैकग्राउंड की गतिविधि, कुछ विज़ुअल इफ़ेक्ट, और कुछ खास सुविधाएं कम या बंद हो जाती हैं. कुछ इंटरनेट कनेक्शन भी पूरी तरह काम नहीं करते."</string>
diff --git a/core/res/res/values-hr/strings.xml b/core/res/res/values-hr/strings.xml
index f701483..d870a1d 100644
--- a/core/res/res/values-hr/strings.xml
+++ b/core/res/res/values-hr/strings.xml
@@ -354,9 +354,9 @@
     <string name="permgroupdesc_sensors" msgid="2610631290633747752">"pristupiti podacima senzora o vašim vitalnim znakovima"</string>
     <string name="permgrouplab_notifications" msgid="5472972361980668884">"Obavijesti"</string>
     <string name="permgroupdesc_notifications" msgid="4608679556801506580">"prikazati obavijesti"</string>
-    <string name="permgrouplab_xr_tracking" msgid="7418994009794287471">"XR podaci o praćenju"</string>
-    <string name="permgroupdesc_xr_tracking" msgid="6777198859446500821">"pristup XR podacima o vama i vašem okruženju"</string>
-    <string name="permgrouplab_xr_tracking_sensitive" msgid="1194833982988144536">"osjetljivi XR podaci o praćenju"</string>
+    <string name="permgrouplab_xr_tracking" msgid="7418994009794287471">"podaci o praćenju za proširenu stvarnost"</string>
+    <string name="permgroupdesc_xr_tracking" msgid="6777198859446500821">"pristup podacima proširene stvarnosti o vama i vašem okruženju"</string>
+    <string name="permgrouplab_xr_tracking_sensitive" msgid="1194833982988144536">"osjetljivi podaci o praćenju za XR"</string>
     <string name="permgroupdesc_xr_tracking_sensitive" msgid="9178027369004805829">"pristup osjetljivim podacima o praćenju, kao što je pogled"</string>
     <string name="capability_title_canRetrieveWindowContent" msgid="7554282892101587296">"Dohvaćati sadržaj prozora"</string>
     <string name="capability_desc_canRetrieveWindowContent" msgid="6195610527625237661">"Pregledat će sadržaj prozora koji upotrebljavate."</string>
@@ -655,7 +655,7 @@
     <string name="permdesc_mediaLocation" msgid="597912899423578138">"Omogućuje aplikaciji čitanje lokacija iz vaše medijske zbirke."</string>
     <string name="permlab_eye_tracking_coarse" msgid="7989596289790269059">"praćenje približnog pogleda"</string>
     <string name="permdesc_eye_tracking_coarse" msgid="870510233930553355">"Aplikaciji omogućuje praćenje približnih podataka o pogledu."</string>
-    <string name="permlab_eye_tracking_fine" msgid="6914457357027049512">"praćenje toga gdje gledate"</string>
+    <string name="permlab_eye_tracking_fine" msgid="6914457357027049512">"praćenje mjesta u koje gledate"</string>
     <string name="permdesc_eye_tracking_fine" msgid="5788889152304524730">"Aplikaciji omogućuje pristup preciznim podacima o pogledu."</string>
     <string name="permlab_face_tracking" msgid="2272048395128283324">"praćenje lica"</string>
     <string name="permdesc_face_tracking" msgid="2622783922311211866">"Aplikaciji omogućuje pristup podacima o praćenju lica."</string>
@@ -664,10 +664,10 @@
     <string name="permlab_head_tracking" msgid="1309731456372087270">"praćenje pokreta glave"</string>
     <string name="permdesc_head_tracking" msgid="231597390513699188">"Aplikaciji omogućuje pristup podacima o praćenju pokreta glave."</string>
     <string name="permlab_scene_understanding_coarse" msgid="6518646430502858641">"stjecanje uvida u neposredno okruženje"</string>
-    <string name="permdesc_scene_understanding_coarse" msgid="4508880777646198656">"Aplikaciji omogućuje pristup podacima o praćenju o vašem neposrednom okruženju."</string>
+    <string name="permdesc_scene_understanding_coarse" msgid="4508880777646198656">"Aplikaciji omogućuje pristup podacima o praćenju vašeg neposrednog okruženja."</string>
     <string name="permlab_scene_understanding_fine" msgid="409126403264393251">"stjecanje detaljnih uvida u neposredno okruženje"</string>
-    <string name="permdesc_scene_understanding_fine" msgid="6223368011593524179">"Aplikaciji omogućuje pristup detaljnim podacima o praćenju o vašem neposrednom okruženju."</string>
-    <string name="permlab_xr_tracking_in_background" msgid="7117098718465619023">"pristup XR podacima dok nije u prednjem planu"</string>
+    <string name="permdesc_scene_understanding_fine" msgid="6223368011593524179">"Aplikaciji omogućuje pristup detaljnim podacima o praćenju vašeg neposrednog okruženja."</string>
+    <string name="permlab_xr_tracking_in_background" msgid="7117098718465619023">"pristup podacima proširene stvarnosti dok nije u prednjem planu"</string>
     <string name="permdesc_xr_tracking_in_background" msgid="939504041387836853">"Aplikaciji omogućuje pristup XR podacima dok nije u prednjem planu."</string>
     <string name="biometric_app_setting_name" msgid="3339209978734534457">"Upotreba biometrije"</string>
     <string name="biometric_or_screen_lock_app_setting_name" msgid="5348462421758257752">"Upotreba biometrijske autentifikacije ili zaključavanja zaslona"</string>
@@ -1714,7 +1714,7 @@
     <string name="wireless_display_route_description" msgid="8297563323032966831">"Bežični prikaz"</string>
     <string name="media_route_button_content_description" msgid="2299223698196869956">"Emitiranje"</string>
     <string name="media_route_chooser_title" msgid="6646594924991269208">"Povezivanje s uređajem"</string>
-    <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Emitiranje zaslona na uređaj"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Emitirajte zaslon na uređaj"</string>
     <string name="media_route_chooser_searching" msgid="6119673534251329535">"Traženje uređaja…"</string>
     <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Postavke"</string>
     <string name="media_route_controller_disconnect" msgid="7362617572732576959">"Prekini vezu"</string>
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Način rada jednom rukom"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Još tamnije"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušna pomagala"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatski klik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Nije povezano"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Povezano"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivno"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Mikrofon slušnog pomagala možete koristiti za pozivanje bez upotrebe ruku. Time se mikrofon prebacuje samo tijekom poziva."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Prebaci"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Postavke"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Trenutačni korisnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Prebacivanje na korisnika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Odjavljivanje korisnika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Vlasnik"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Traži uzorak za otključavanje radi otkvačivanja"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Traži zaporku radi otkvačivanja"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalirao vaš administrator.\nOtvorite postavke da biste pregledali dodijeljena dopuštenja"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Ažurirao administrator"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisao administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"U redu"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Štednja baterije uključuje tamnu temu i ograničava ili isključuje aktivnosti u pozadini, neke vizualne efekte, određene značajke i neke mrežne veze."</string>
diff --git a/core/res/res/values-hu/strings.xml b/core/res/res/values-hu/strings.xml
index e3d261e..350d51d 100644
--- a/core/res/res/values-hu/strings.xml
+++ b/core/res/res/values-hu/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Egykezes mód"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extrasötét"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hallásjavító eszközök"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatikus kattintás"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Leválasztva"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Csatlakozva"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktív"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Használhatja hallókészüléke mikrofonját a szabadkezes hívásokhoz. Csak a mikrofont kapcsolja át hívás közben."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Váltás"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Beállítások"</string>
-    <string name="user_switched" msgid="7249833311585228097">"<xliff:g id="NAME">%1$s</xliff:g> az aktuális felhasználó."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Átváltás erre: <xliff:g id="NAME">%1$s</xliff:g>..."</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> kijelentkeztetése folyamatban van…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Tulajdonos"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Feloldási minta kérése a kitűzés feloldásához"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Jelszó kérése a rögzítés feloldásához"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"A rendszergazda által telepítve.\nLépjen a beállításokhoz a megadott engedélyek megtekintéséhez."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"A rendszergazda által frissítve"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"A rendszergazda által törölve"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Az Akkumulátorkímélő mód bekapcsolja a Sötét témát, és korlátozza vagy kikapcsolja a háttérbeli tevékenységeket, valamint bizonyos vizuális effekteket, funkciókat és hálózati kapcsolatokat."</string>
diff --git a/core/res/res/values-hy/strings.xml b/core/res/res/values-hy/strings.xml
index de62af5..655af93 100644
--- a/core/res/res/values-hy/strings.xml
+++ b/core/res/res/values-hy/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Մեկ ձեռքի ռեժիմ"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Հավելյալ խամրեցում"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Լսողական սարքեր"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Ավտոմատ սեղմում"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Անջատված է"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Միացված է"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Ակտիվ է"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Լսողական սարքի խոսափողը կարող եք օգտագործել ձայնային կառավարման համար։ Դուք կանցնեք խոսափողին միայն զանգի ընթացքում։"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Անցնել"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Կարգավորումներ"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Ներկայիս օգտատերը <xliff:g id="NAME">%1$s</xliff:g>:"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Անցում <xliff:g id="NAME">%1$s</xliff:g> պրոֆիլին..."</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Ելք <xliff:g id="NAME">%1$s</xliff:g>-ից…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Սեփականատեր"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Հարցնել ապակողպող նախշը"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Հարցնել գաղտնաբառը"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Տեղադրվել է ադմինիստրատորի կողմից։\nԱնցեք կարգավորումներ՝ տրամադրված թույլտվությունները դիտելու համար"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Թարմացվել է ձեր ադմինիստրատորի կողմից"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Ջնջվել է ձեր ադմինիստրատորի կողմից"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Եղավ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"«Մարտկոցի տնտեսում» գործառույթը միացնում է մուգ թեման և անջատում կամ սահմանափակում է աշխատանքը ֆոնային ռեժիմում, որոշ վիզուալ էֆեկտներ, ցանցային միացումներ և այլ գործառույթներ։"</string>
diff --git a/core/res/res/values-in/strings.xml b/core/res/res/values-in/strings.xml
index 18ae5e9..305d23a 100644
--- a/core/res/res/values-in/strings.xml
+++ b/core/res/res/values-in/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mode satu tangan"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra redup"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Alat bantu dengar"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Klik otomatis"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Tidak terhubung"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Terhubung"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktif"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Anda dapat menggunakan mikrofon alat bantu dengar untuk melakukan panggilan handsfree. Tindakan ini hanya akan mengalihkan mikrofon Anda selama panggilan."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Alihkan"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Setelan"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Pengguna saat ini <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Beralih ke <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Mengeluarkan <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Pemilik"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Meminta pola pembukaan kunci sebelum melepas sematan"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Meminta sandi sebelum melepas sematan"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Diinstal oleh admin Anda.\nBuka setelan untuk melihat izin yang diberikan"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Diupdate oleh admin Anda"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Dihapus oleh admin Anda"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Oke"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Penghemat Baterai akan mengaktifkan Tema gelap dan membatasi atau menonaktifkan aktivitas latar belakang, beberapa efek visual, fitur tertentu, dan beberapa koneksi jaringan."</string>
diff --git a/core/res/res/values-is/strings.xml b/core/res/res/values-is/strings.xml
index a74ff1c..cdf89ad 100644
--- a/core/res/res/values-is/strings.xml
+++ b/core/res/res/values-is/strings.xml
@@ -1713,7 +1713,7 @@
     <string name="wireless_display_route_description" msgid="8297563323032966831">"Þráðlaus skjábirting"</string>
     <string name="media_route_button_content_description" msgid="2299223698196869956">"Senda út"</string>
     <string name="media_route_chooser_title" msgid="6646594924991269208">"Tengjast tæki"</string>
-    <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Senda skjá út í tæki"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Varpa skjá í tæki"</string>
     <string name="media_route_chooser_searching" msgid="6119673534251329535">"Leitar að tækjum…"</string>
     <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Stillingar"</string>
     <string name="media_route_controller_disconnect" msgid="7362617572732576959">"Aftengja"</string>
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Einhent stilling"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mjög dökkt"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Heyrnartæki"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Sjálfvirkur smellur"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Aftengt"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Tengt"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Virkt"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Þú getur notað hljóðnema heyrnartækisins þíns til að hringja eða svara símtölum handfrjálst. Aðeins verður skipt um hljóðnema á meðan á símtali stendur."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Skipta"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Stillingar"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Núverandi notandi <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Skiptir yfir á <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Skráir <xliff:g id="NAME">%1$s</xliff:g> út…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Eigandi"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Biðja um opnunarmynstur til að losa"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Biðja um aðgangsorð til að losa"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Sett upp af stjórnanda.\nFarðu í stillingar til að sjá heimildir"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Kerfisstjóri uppfærði"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Kerfisstjóri eyddi"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Í lagi"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Rafhlöðusparnaður kveikir á dökku þema og takmarkar eða slekkur á bakgrunnsvirkni, sumum myndáhrifum, tilteknum eiginleikum og sumum nettengingum."</string>
diff --git a/core/res/res/values-it/strings.xml b/core/res/res/values-it/strings.xml
index befd2b2..3b7d1ec 100644
--- a/core/res/res/values-it/strings.xml
+++ b/core/res/res/values-it/strings.xml
@@ -277,7 +277,7 @@
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"Report completo"</string>
     <string name="bugreport_option_full_summary" msgid="1975130009258435885">"Utilizza questa opzione per ridurre al minimo l\'interferenza di sistema quando il dispositivo non risponde, è troppo lento oppure quando ti servono tutte le sezioni della segnalazione. Non puoi inserire altri dettagli o acquisire altri screenshot."</string>
     <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondo.}many{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondi.}other{Lo screenshot per la segnalazione di bug verrà acquisito tra # secondi.}}"</string>
-    <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot con segnalazione di bug effettuato correttamente"</string>
+    <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"Screenshot con segnalazione di bug effettuato"</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"Impossibile acquisire screenshot con segnalazione di bug"</string>
     <string name="global_action_toggle_silent_mode" msgid="8464352592860372188">"Modalità silenziosa"</string>
     <string name="global_action_silent_mode_on_status" msgid="2371892537738632013">"Audio non attivo"</string>
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modalità a una mano"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Attenuazione extra"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Protesi uditive"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automatico"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Disconnesso"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Connesso"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Attivo"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Puoi usare il microfono dell\'apparecchio acustico per le chiamate in vivavoce. In questo modo, il microfono viene attivato solo durante la chiamata."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Cambia"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Impostazioni"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Utente corrente <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Passaggio a <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Disconnessione di <xliff:g id="NAME">%1$s</xliff:g> in corso…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Proprietario"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Richiedi sequenza di sblocco prima di sbloccare"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Richiedi password prima di sbloccare"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installato dall\'amministratore.\nVai alle impostazioni per visualizzare le autorizzazioni concesse"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Aggiornato dall\'amministratore"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminato dall\'amministratore"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Ok"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Il risparmio energetico attiva il tema scuro e limita o disattiva l\'attività in background, nonché alcuni effetti visivi, funzionalità e connessioni di rete."</string>
@@ -2282,7 +2281,7 @@
     <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"Conversazione"</string>
     <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"Conversazione di gruppo"</string>
     <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
-    <string name="resolver_personal_tab" msgid="2051260504014442073">"Personale"</string>
+    <string name="resolver_personal_tab" msgid="2051260504014442073">"Personali"</string>
     <string name="resolver_work_tab" msgid="2690019516263167035">"Lavoro"</string>
     <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"Visualizzazione personale"</string>
     <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"Visualizzazione di lavoro"</string>
diff --git a/core/res/res/values-iw/strings.xml b/core/res/res/values-iw/strings.xml
index 0b6c80a..cf737486 100644
--- a/core/res/res/values-iw/strings.xml
+++ b/core/res/res/values-iw/strings.xml
@@ -1826,7 +1826,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"אפשר לשוחח במצב דיבורית באמצעות המיקרופון של מכשיר השמיעה. במצב הזה המיקרופון מוחלף רק במהלך השיחה."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"החלפה"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"הגדרות"</string>
-    <string name="user_switched" msgid="7249833311585228097">"המשתמש הנוכחי <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"מעבר אל <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"מתבצע ניתוק של <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"בעלים"</string>
@@ -1968,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"צריך לבקש קו ביטול נעילה לפני ביטול הצמדה"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"יש לבקש סיסמה לפני ביטול הצמדה"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"החבילה הותקנה על ידי האדמין.\nצריך לעבור להגדרות כדי לראות את ההרשאות שניתנו"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"עודכנה על ידי מנהל המערכת"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"נמחקה על ידי מנהל המערכת"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"אישור"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"התכונה \'חיסכון בסוללה\' מפעילה עיצוב כהה ומגבילה או מכבה פעילות ברקע, חלק מהאפקטים החזותיים, תכונות מסוימות וחלק מהחיבורים לרשתות."</string>
diff --git a/core/res/res/values-ja/strings.xml b/core/res/res/values-ja/strings.xml
index 2f8133a..f8bc241 100644
--- a/core/res/res/values-ja/strings.xml
+++ b/core/res/res/values-ja/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"片手モード"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"さらに輝度を下げる"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"補聴器"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"自動クリック"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"未接続"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"接続済み"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"有効"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"補聴器のマイクを使ってハンズフリー通話を行えます。通話時のみマイクが切り替わります。"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"切り替える"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"設定"</string>
-    <string name="user_switched" msgid="7249833311585228097">"現在のユーザーは<xliff:g id="NAME">%1$s</xliff:g>です。"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>に切り替えています…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> をログアウトしています…"</string>
     <string name="owner_name" msgid="8713560351570795743">"所有者"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"画面固定を解除する前にロック解除パターンの入力を求める"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"オフライン再生を解除する前にパスワードの入力を求める"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"管理者によりインストールされています。\n付与された権限を確認するには、設定に移動してください"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"管理者により更新されています"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"管理者により削除されています"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"バッテリー セーバーを ON にすると、ダークモードが ON になります。また、バックグラウンド アクティビティ、一部の視覚効果、特定の機能、一部のネットワーク接続が制限されるか OFF になります。"</string>
diff --git a/core/res/res/values-ka/strings.xml b/core/res/res/values-ka/strings.xml
index ef15405..8aa0af3 100644
--- a/core/res/res/values-ka/strings.xml
+++ b/core/res/res/values-ka/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ცალი ხელის რეჟიმი"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"დამატებითი დაბინდვა"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"სმენის აპარატები"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ავტოდაწკაპუნება"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"კავშირი გაწყვეტილია"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"დაკავშირებული"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"აქტიური"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"შეგიძლიათ სმენის მოწყობილობის მიკროფონის გამოყენება უკონტაქტოდ დასარეკად. ეს გადართავს თქვენს მიკროფონს მხოლოდ ზარის დროს."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"გადართვა"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"პარამეტრები"</string>
-    <string name="user_switched" msgid="7249833311585228097">"ამჟამინდელი მომხმარებელი <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>-ზე გადართვა…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>-ის ანგარიშიდან გასვლა…"</string>
     <string name="owner_name" msgid="8713560351570795743">"მფლობელი"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ფიქსაციის მოხსნამდე განბლოკვის ნიმუშის მოთხოვნა"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ფიქსაციის მოხსნამდე პაროლის მოთხოვნა"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"დაინსტალირებულია თქვენი ადმინისტრატორის მიერ.\nდაშვებული ნებართვების სანახავად გადადით პარამეტრებზე"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"განახლებულია თქვენი ადმინისტრატორის მიერ"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"წაიშალა თქვენი ადმინისტრატორის მიერ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"კარგი"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ბატარეის დამზოგი ჩართავს მუქ თემას და შეზღუდავს ან გამორთავს ფონურ აქტივობას, ზოგიერთ ვიზუალურ ეფექტს, გარკვეულ ფუნქციებსა და ზოგიერთ ქსელთან კავშირს."</string>
diff --git a/core/res/res/values-kk/strings.xml b/core/res/res/values-kk/strings.xml
index b575630..3908427 100644
--- a/core/res/res/values-kk/strings.xml
+++ b/core/res/res/values-kk/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Бір қолмен басқару режимі"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Экранды қарайту"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Есту аппараттары"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Автоматты басу"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ажыратылды"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Қосылды"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Белсенді"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Дауыспен басқару арқылы қоңырау шалу үшін есту аппаратының микрофонын пайдалана аласыз. Микрофонға тек қоңырау кезінде ауысады."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Ауысу"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Параметрлер"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Ағымдағы пайдаланушы <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> профиліне ауысу…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> ішінен шығу…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Құрылғы иесі"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Босату алдында бекітпесін ашу өрнегін сұрау"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Босату алдында құпия сөзді сұрау"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Әкімшіңіз орнатты.\nБерілген рұқсаттарды көру үшін параметрлерге өтіңіз."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Әкімші жаңартқан"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Әкімші жойған"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Жарайды"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Батареяны үнемдеу режимі қараңғы режимді іске қосады және фондық әрекеттерге, кейбір визуалдық әсерлерге, белгілі бір функциялар мен кейбір желі байланыстарына шектеу қояды немесе оларды өшіреді."</string>
diff --git a/core/res/res/values-km/strings.xml b/core/res/res/values-km/strings.xml
index eeae49b..dee23f6 100644
--- a/core/res/res/values-km/strings.xml
+++ b/core/res/res/values-km/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"មុខងារប្រើដៃម្ខាង"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ងងឹតខ្លាំង"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ចុចស្វ័យប្រវត្តិ"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"បាន​ផ្ដាច់"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"បានភ្ជាប់"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"សកម្ម"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"អ្នកអាចប្រើមីក្រូហ្វូនឧបករណ៍​ជំនួយការ​ស្ដាប់របស់អ្នកសម្រាប់ការហៅទូរសព្ទដោយមិន​ប្រើ​ដៃ។ ការធ្វើបែបនេះប្ដូរមីក្រូហ្វូនរបស់អ្នក ក្នុងអំឡុងការហៅទូរសព្ទតែប៉ុណ្ណោះ។"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ប្ដូរ"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ការកំណត់"</string>
-    <string name="user_switched" msgid="7249833311585228097">"អ្នក​ប្រើ​បច្ចុប្បន្ន <xliff:g id="NAME">%1$s</xliff:g> ។"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"កំពុង​ប្ដូរ​ទៅ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"កំពុងចេញ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"ម្ចាស់"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"សួរ​រក​លំនាំ​ដោះ​សោ​មុន​ពេលដោះខ្ទាស់"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"សួរ​រក​ពាក្យ​សម្ងាត់​មុន​ពេល​ផ្ដាច់"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"បានដំឡើងដោយអ្នកគ្រប់គ្រងរបស់អ្នក។\nចូលទៅកាន់ការកំណត់ ដើម្បីមើលការ​អនុញ្ញាតដែលផ្ដល់ឱ្យ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"ធ្វើ​បច្ចុប្បន្នភាព​ដោយ​អ្នកគ្រប់គ្រង​របស់​អ្នក"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"លុប​ដោយ​អ្នកគ្រប់គ្រង​របស់​អ្នក"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"យល់ព្រម"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"មុខងារ​សន្សំថ្មបើកទម្រង់រចនាងងឹត និងដាក់កំហិត ឬបិទសកម្មភាពផ្ទៃខាងក្រោយ បែបផែនរូបភាពមួយចំនួន មុខងារជាក់លាក់ និងការតភ្ជាប់បណ្ដាញមួយចំនួន។"</string>
diff --git a/core/res/res/values-kn/strings.xml b/core/res/res/values-kn/strings.xml
index fd468b4..c1a70b0 100644
--- a/core/res/res/values-kn/strings.xml
+++ b/core/res/res/values-kn/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ಒಂದು ಕೈ ಮೋಡ್‌"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ಇನ್ನಷ್ಟು ಮಬ್ಬು"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ಆಟೋಕ್ಲಿಕ್"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ಡಿಸ್‌ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"ಕನೆಕ್ಟ್ ಆಗಿದೆ"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"ಸಕ್ರಿಯವಾಗಿದೆ"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"ಹ್ಯಾಂಡ್ಸ್-ಫ್ರೀ ಕರೆ ಮಾಡುವಿಕೆಗಾಗಿ ನಿಮ್ಮ ಶ್ರವಣ ಸಾಧನದ ಮೈಕ್ರೊಫೋನ್ ಅನ್ನು ನೀವು ಬಳಸಬಹುದು. ಇದು ಕರೆಯ ಸಮಯದಲ್ಲಿ ಮಾತ್ರ ನಿಮ್ಮ ಮೈಕ್ ಅನ್ನು ಬದಲಾಯಿಸುತ್ತದೆ."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ಬದಲಿಸಿ"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ಸೆಟ್ಟಿಂಗ್‌ಗಳು"</string>
-    <string name="user_switched" msgid="7249833311585228097">"ಪ್ರಸ್ತುತ ಬಳಕೆದಾರರು <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>ಗೆ ಬದಲಾಯಿಸಲಾಗುತ್ತಿದೆ…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> ಅವರನ್ನು ಲಾಗ್‌ ಔಟ್‌ ಮಾಡಲಾಗುತ್ತಿದೆ…"</string>
     <string name="owner_name" msgid="8713560351570795743">"ಮಾಲೀಕರು"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಅನ್‌ಲಾಕ್ ಪ್ಯಾಟರ್ನ್ ಕೇಳಿ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ಅನ್‌ಪಿನ್ ಮಾಡಲು ಪಾಸ್‌ವರ್ಡ್ ಕೇಳು"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಇನ್‌ಸ್ಟಾಲ್ ಮಾಡಿದ್ದಾರೆ.\nನೀಡಲಾದ ಅನುಮತಿಗಳನ್ನು ವೀಕ್ಷಿಸಲು ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ಹೋಗಿ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರಿಂದ ಅಪ್‌ಡೇಟ್ ಮಾಡಲ್ಪಟ್ಟಿದೆ"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ನಿಮ್ಮ ನಿರ್ವಾಹಕರು ಅಳಿಸಿದ್ದಾರೆ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ಸರಿ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ಬ್ಯಾಟರಿ ಸೇವರ್, ಡಾರ್ಕ್ ಥೀಮ್ ಅನ್ನು ಆನ್ ಮಾಡುತ್ತದೆ ಮತ್ತು ಹಿನ್ನೆಲೆ ಚಟುವಟಿಕೆ, ಕೆಲವು ವಿಷುವಲ್ ಎಫೆಕ್ಟ್‌ಗಳು, ಕೆಲವು ಫೀಚರ್‌ಗಳು ಮತ್ತು ಇತರ ನೆಟ್‌ವರ್ಕ್ ಸಂಪರ್ಕಗಳನ್ನು ಮಿತಿಗೊಳಿಸುತ್ತದೆ ಅಥವಾ ಆಫ್ ಮಾಡುತ್ತದೆ."</string>
diff --git a/core/res/res/values-ko/strings.xml b/core/res/res/values-ko/strings.xml
index 0a88670..be4a284 100644
--- a/core/res/res/values-ko/strings.xml
+++ b/core/res/res/values-ko/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"한 손 모드"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"더 어둡게"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"청각 보조 기기"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"자동 클릭"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"연결 끊김"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"연결됨"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"활성"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"보청기 마이크로 핸즈프리 통화 기능을 이용할 수 있습니다. 통화 중에만 마이크가 전환됩니다."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"전환"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"설정"</string>
-    <string name="user_switched" msgid="7249833311585228097">"현재 사용자는 <xliff:g id="NAME">%1$s</xliff:g>님입니다."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>로 전환하는 중…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>님을 로그아웃하는 중…"</string>
     <string name="owner_name" msgid="8713560351570795743">"소유자"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"고정 해제 시 잠금 해제 패턴 요청"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"고정 해제 이전에 비밀번호 요청"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"관리자에 의해 설치되었습니다.\n부여된 권한을 확인하려면 설정으로 이동하세요."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"관리자에 의해 업데이트되었습니다."</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"관리자에 의해 삭제되었습니다."</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"확인"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"절전 모드는 어두운 테마를 사용하고 백그라운드 활동, 일부 시각 효과, 특정 기능 및 일부 네트워크 연결을 제한하거나 사용 중지합니다."</string>
diff --git a/core/res/res/values-ky/strings.xml b/core/res/res/values-ky/strings.xml
index 83a1c69..121908a 100644
--- a/core/res/res/values-ky/strings.xml
+++ b/core/res/res/values-ky/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Бир кол режими"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Кошумча караңгылатуу"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Угуу түзмөктөрү"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Авточыкылдатуу"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Ажыратылды"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Туташты"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Жигердүү"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Угуу аппаратыңыздын микрофонун үн режиминде чалуу үчүн колдоно аласыз. Микрофонуңуз чалуу учурунда гана которулат."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Которулуу"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Параметрлер"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Учурдагы колдонуучу <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> дегенге которулууда…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> чыгууда…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Ээси"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Бошотуудан мурун графикалык ачкыч суралсын"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Бошотуудан мурун сырсөз суралсын"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Администраторуңуз орнотту.\nБерилген уруксаттарды көрүү үчүн параметрлерге өтүңүз"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Администраторуңуз жаңыртып койгон"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Администраторуңуз жок кылып салган"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ЖАРАЙТ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Батареяны үнөмдөөчү режимде Караңгы тема күйгүзүлүп, фондогу аракеттер, айрым визуалдык эффекттер, белгилүү бир функциялар жана айрым тармакка туташуулар чектелип же өчүрүлөт."</string>
@@ -2502,8 +2501,8 @@
     <string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Күйгүзүү"</string>
     <string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Артка кайтуу"</string>
     <string name="unarchival_session_app_label" msgid="6811856981546348205">"Кезекте турат..."</string>
-    <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Спутник SOS эми жеткиликтүү"</string>
-    <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Мобилдик Интернет же Wi-Fi тармагы жок болсо, кырсыктаганда жардамга келчү кызматтарга билдирүү жөнөтө аласыз. Google Messages демейки жазышуу колдонмоңуз болушу керек."</string>
+    <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Спутник SOS кызматы иштеп баштады"</string>
+    <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Мобилдик Интернет же Wi-Fi жок болгон учурда, кырсыктаганда жардамга келчү кызматтарга билдирүү жөнөтө аласыз. Google Жазышуу демейки колдонмоңуз болушу керек."</string>
     <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Спутник SOS колдоого алынбайт"</string>
     <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Бул түзмөктө спутник SOS колдоого алынбайт"</string>
     <string name="satellite_sos_not_provisioned_notification_title" msgid="8564738683795406715">"Спутник SOS туураланган жок"</string>
diff --git a/core/res/res/values-lo/strings.xml b/core/res/res/values-lo/strings.xml
index f32ede6..ad62671 100644
--- a/core/res/res/values-lo/strings.xml
+++ b/core/res/res/values-lo/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ໂໝດມືດຽວ"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ຫຼຸດແສງເປັນພິເສດ"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ອຸປະກອນຊ່ວຍຟັງ"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ການຄລິກອັດຕະໂນມັດ"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ຕັດການເຊື່ອມຕໍ່ແລ້ວ"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"ເຊື່ອມຕໍ່ແລ້ວ"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"ນຳໃຊ້ຢູ່"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"ທ່ານສາມາດໃຊ້ໄມໂຄຣໂຟນຂອງເຄື່ອງຊ່ວຍຟັງເພື່ອການໂທແບບແຮນຟຣີໄດ້. ການດຳເນີນການນີ້ພຽງແຕ່ປ່ຽນໄມໂຄຣໂຟນຂອງທ່ານໃນລະຫວ່າງການໂທເທົ່ານັ້ນ."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ປ່ຽນ"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ການຕັ້ງຄ່າ"</string>
-    <string name="user_switched" msgid="7249833311585228097">"ຜູ່ໃຊ້ປັດຈຸບັນ <xliff:g id="NAME">%1$s</xliff:g> ."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"ກຳລັງສະຫຼັບໄປຫາ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"ກຳລັງອອກຈາກລະບົບ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"ເຈົ້າຂອງ"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"​ຖາມ​ຫາ​ຮູບ​ແບບ​ປົດ​ລັອກ​ກ່ອນ​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"​ຖາມ​ຫາ​ລະ​ຫັດ​ຜ່ານ​ກ່ອນ​ຍົກ​ເລີກ​ການ​ປັກ​ໝຸດ"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"ຕິດຕັ້ງໂດຍຜູ້ເບິ່ງແຍງຂອງທ່ານ.\nເຂົ້າໄປການຕັ້ງຄ່າເພື່ອເບິ່ງສິດທີ່ໄດ້ຮັບອະນຸຍາດ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"ຖືກອັບໂຫລດໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ຖືກລຶບອອກໂດຍຜູ້ເບິ່ງແຍງລະບົບຂອງທ່ານ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ຕົກລົງ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ຕົວປະຢັດແບັດເຕີຣີຈະເປີດໃຊ້ຮູບແບບສີສັນມືດ ແລະ ຈຳກັດ ຫຼື ປິດການເຄື່ອນໄຫວໃນພື້ນຫຼັງ, ເອັບເຟັກທາງພາບຈຳນວນໜຶ່ງ, ຄຸນສົມບັດບາງຢ່າງ ແລະ ການເຊື່ອມຕໍ່ເຄືອຂ່າຍບາງອັນ."</string>
diff --git a/core/res/res/values-lt/strings.xml b/core/res/res/values-lt/strings.xml
index 51311b37..27a08c2 100644
--- a/core/res/res/values-lt/strings.xml
+++ b/core/res/res/values-lt/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Vienos rankos režimas"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Itin blanku"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Klausos įrenginiai"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatinis paspaudimas"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Atjungta"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Prisijungta"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktyvus"</string>
@@ -1827,7 +1826,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Galite naudoti klausos aparato mikrofoną skambučiams laisvų rankų režimu. Mikrofonas įjungiamas tik per skambutį."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Perjungti"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Nustatymai"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Dabartinis naudotojas: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Perjungiama į <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Atsijungiama (<xliff:g id="NAME">%1$s</xliff:g>)…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Savininkas"</string>
@@ -1969,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Prašyti atrakinimo piešinio prieš atsegant"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Prašyti slaptažodžio prieš atsegant"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Įdiegė administratorius.\nEikite į nustatymus ir peržiūrėkite suteiktus leidimus"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Atnaujino administratorius"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Ištrynė administratorius"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Gerai"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Akumuliatoriaus tausojimo priemonė įjungia tamsiąją temą ir apriboja arba išjungia veiklą fone, kai kuriuos vaizdinius efektus, tam tikras funkcijas bei kai kuriuos tinklo ryšius."</string>
diff --git a/core/res/res/values-lv/strings.xml b/core/res/res/values-lv/strings.xml
index 3b3609e..78c7ebd 100644
--- a/core/res/res/values-lv/strings.xml
+++ b/core/res/res/values-lv/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Vienas rokas režīms"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Papildu aptumšošana"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dzirdes aparāti"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automātiskā klikšķināšana"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Atvienota"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Pievienota"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktīva"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Varat izmantot dzirdes aparāta mikrofonu zvaniem brīvroku režīmā. Mikrofons tiek pārslēgts tikai zvana laikā."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Pārslēgt"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Iestatījumi"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Pašreizējais lietotājs: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Notiek pāriešana uz: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Notiek lietotāja <xliff:g id="NAME">%1$s</xliff:g> atteikšanās…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Īpašnieks"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pirms atspraušanas pieprasīt atbloķēšanas kombināciju"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pirms atspraušanas pieprasīt paroli"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalēja jūsu administrators.\nPārejiet uz iestatījumiem, lai skatītu piešķirtās atļaujas."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Atjaunināja administrators"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Dzēsa administrators"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Labi"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Akumulatora enerģijas taupīšanas režīmā tiek ieslēgts tumšais motīvs un tiek ierobežotas vai izslēgtas darbības fonā, daži vizuālie efekti, noteiktas funkcijas un noteikti tīkla savienojumi."</string>
diff --git a/core/res/res/values-mk/strings.xml b/core/res/res/values-mk/strings.xml
index 0c92fd5..146de01 100644
--- a/core/res/res/values-mk/strings.xml
+++ b/core/res/res/values-mk/strings.xml
@@ -1531,7 +1531,7 @@
     <string name="ext_media_status_unmounted" msgid="8145812017295835941">"Исфрлено"</string>
     <string name="ext_media_status_checking" msgid="159013362442090347">"Се проверува..."</string>
     <string name="ext_media_status_mounted" msgid="3459448555811203459">"Подготвено"</string>
-    <string name="ext_media_status_mounted_ro" msgid="1974809199760086956">"Само за читање"</string>
+    <string name="ext_media_status_mounted_ro" msgid="1974809199760086956">"Само за преглед"</string>
     <string name="ext_media_status_bad_removal" msgid="508448566481406245">"Отстранет небезбедно"</string>
     <string name="ext_media_status_unmountable" msgid="7043574843541087748">"Оштетено"</string>
     <string name="ext_media_status_unsupported" msgid="5460509911660539317">"Неподдржано"</string>
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим со една рака"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дополнително затемнување"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слушни помагала"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Автоматско кликнување"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Не е поврзано"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Поврзано"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Активно"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Може да го користите вашиот микрофон на слушното помагало за повикување без користење раце. Ова го префрла вашиот микрофон само за време на повикот."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Префрли"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Поставки"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Тековен корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Се префрла на <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> се одјавува…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Сопственик"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Побарај шема за откл. пред откачување"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Побарај лозинка пред откачување"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Инсталирано од администраторот.\nОдете во „Поставки“ за да ги прегледате доделените дозволи"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирано од администраторот"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Избришано од администраторот"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Во ред"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"„Штедачот на батерија“ вклучува „Темна тема“ и ограничува или исклучува активност во заднина, некои визуелни ефекти, одредени функции и некои мрежни врски."</string>
diff --git a/core/res/res/values-ml/strings.xml b/core/res/res/values-ml/strings.xml
index cbdbd2d..3bb425e 100644
--- a/core/res/res/values-ml/strings.xml
+++ b/core/res/res/values-ml/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ഒറ്റക്കൈ മോഡ്"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"കൂടുതൽ ഡിം ചെയ്യൽ"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ശ്രവണ ഉപകരണങ്ങൾ"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ഓട്ടോക്ലിക്ക്"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"വിച്‌ഛേദിച്ചു"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"കണക്റ്റ് ചെയ്‌തു"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"സജീവം"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"ഹാൻഡ്‌സ്‌-ഫ്രീ ആയി കോൾ ചെയ്യാൻ നിങ്ങളുടെ ശ്രവണ സഹായി മൈക്രോഫോൺ ഉപയോഗിക്കാം. ഇത് കോൾ സമയത്ത് മാത്രം നിങ്ങളുടെ മൈക്ക് മാറ്റുന്നു."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"മാറുക"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ക്രമീകരണം"</string>
-    <string name="user_switched" msgid="7249833311585228097">"നിലവിലെ ഉപയോക്താവ് <xliff:g id="NAME">%1$s</xliff:g> ആണ്."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> എന്ന ഉപയോക്താവിലേക്ക് മാറുന്നു…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> ലോഗൌട്ട് ചെയ്യുന്നു…"</string>
     <string name="owner_name" msgid="8713560351570795743">"ഉടമ"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"അൺപിന്നിനുമുമ്പ് അൺലോക്ക് പാറ്റേൺ ആവശ്യപ്പെടൂ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"അൺപിന്നിനുമുമ്പ് പാസ്‌വേഡ് ആവശ്യപ്പെടൂ"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"നിങ്ങളുടെ അഡ്‌മിൻ ഇൻസ്‌റ്റാൾ ചെയ്തത്.\nനൽകിയ അനുമതികൾ കാണാൻ ക്രമീകരണത്തിലേക്ക് പോകുക"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"നിങ്ങളുടെ അഡ്‌മിൻ അപ്‌ഡേറ്റ് ചെയ്യുന്നത്"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"നിങ്ങളുടെ അഡ്‌മിൻ ഇല്ലാതാക്കുന്നത്"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ശരി"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"\'ബാറ്ററി സേവർ\' ഡാർക്ക് തീം ഓണാക്കുന്നു, ഒപ്പം പശ്ചാത്തല ആക്‌റ്റിവിറ്റിയും ചില വിഷ്വൽ ഇഫക്റ്റുകളും ചില ഫീച്ചറുകളും ചില നെറ്റ്‌വർക്ക് കണക്ഷനുകളും പരിമിതപ്പെടുത്തുകയോ ഓഫാക്കുകയോ ചെയ്യുന്നു."</string>
diff --git a/core/res/res/values-mn/strings.xml b/core/res/res/values-mn/strings.xml
index 4c72a86..1ad9685 100644
--- a/core/res/res/values-mn/strings.xml
+++ b/core/res/res/values-mn/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Нэг гарын горим"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Хэт бүүдгэр"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Сонсголын төхөөрөмжүүд"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Автомат товшилт"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Салсан"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Холбогдсон"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Идэвхтэй"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Та гараас хамаарахгүй дуудлагад сонсголын төхөөрөмжийнхөө микрофоныг ашиглаж болно. Энэ нь зөвхөн дуудлагын үеэр таны микрофоныг сэлгэнэ."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Сэлгэх"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Тохиргоо"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Одоогийн хэрэглэгч <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> руу сэлгэж байна…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>-с гарч байна…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Өмчлөгч"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Бэхэлснийг болиулахаас өмнө түгжээ тайлах хээ асуух"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Тогтоосныг суллахаас өмнө нууц үг асуух"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Танай админ суулгасан.\nОлгосон зөвшөөрлүүдийг харахын тулд тохиргоо руу очно уу"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Таны админ шинэчилсэн"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Таны админ устгасан"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Батарей хэмнэгч нь Бараан загварыг асааж, дэвсгэрийн үйл ажиллагаа, зарим визуал эффект, тодорхой онцлогууд болон зарим сүлжээний холболтыг хязгаарлах эсвэл унтраана."</string>
@@ -2502,7 +2501,7 @@
     <string name="satellite_manual_selection_state_popup_ok" msgid="2459664752624985095">"Асаах"</string>
     <string name="satellite_manual_selection_state_popup_cancel" msgid="973605633339469252">"Буцах"</string>
     <string name="unarchival_session_app_label" msgid="6811856981546348205">"Хүлээгдэж буй..."</string>
-    <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Хиймэл дагуул SOS одоо боломжтой боллоо"</string>
+    <string name="satellite_sos_available_notification_title" msgid="5396708154268096124">"Хиймэл дагуулын SOS одоо боломжтой боллоо"</string>
     <string name="satellite_sos_available_notification_summary" msgid="1727088812951848330">"Та хөдөлгөөнт холбооны эсвэл Wi-Fi сүлжээ байхгүй бол яаралтай тусламжийн үйлчилгээ рүү мессеж бичих боломжтой. Google Мессеж таны өгөгдмөл мессеж апп байх ёстой."</string>
     <string name="satellite_sos_not_supported_notification_title" msgid="2659100983227637285">"Хиймэл дагуул SOS-г дэмждэггүй"</string>
     <string name="satellite_sos_not_supported_notification_summary" msgid="1071762454665310549">"Хиймэл дагуул SOS-г энэ төхөөрөмж дээр дэмждэггүй"</string>
diff --git a/core/res/res/values-mr/strings.xml b/core/res/res/values-mr/strings.xml
index ea1e92b..82f217f 100644
--- a/core/res/res/values-mr/strings.xml
+++ b/core/res/res/values-mr/strings.xml
@@ -115,8 +115,8 @@
     <string name="roamingText2" msgid="2834048284153110598">"रोमिंग दर्शक फ्लॅशिंग"</string>
     <string name="roamingText3" msgid="831690234035748988">"अतिपरिचित क्षेत्राबाहेर"</string>
     <string name="roamingText4" msgid="2171252529065590728">"इमारती बाहेर"</string>
-    <string name="roamingText5" msgid="4294671587635796641">"रोमिंग - प्राधान्यीकृत सिस्टम"</string>
-    <string name="roamingText6" msgid="5536156746637992029">"रोमिंग - उपलब्ध सिस्टम"</string>
+    <string name="roamingText5" msgid="4294671587635796641">"रोमिंग - प्राधान्य दिलेली सिस्टीम"</string>
+    <string name="roamingText6" msgid="5536156746637992029">"रोमिंग - उपलब्ध सिस्टीम"</string>
     <string name="roamingText7" msgid="1783303085512907706">"रोमिंग - युती भागीदार"</string>
     <string name="roamingText8" msgid="7774800704373721973">"रोमिंग - प्रीमियम भागीदार"</string>
     <string name="roamingText9" msgid="1933460020190244004">"रोमिंग - पूर्ण सेवा कार्यक्षमता"</string>
@@ -242,7 +242,7 @@
     <string name="silent_mode_silent" msgid="5079789070221150912">"रिंगर बंद"</string>
     <string name="silent_mode_vibrate" msgid="8821830448369552678">"रिंगर व्हायब्रेट"</string>
     <string name="silent_mode_ring" msgid="6039011004781526678">"रिंगर सुरू"</string>
-    <string name="reboot_to_update_title" msgid="2125818841916373708">"Android सिस्टम अपडेट"</string>
+    <string name="reboot_to_update_title" msgid="2125818841916373708">"Android सिस्टीम अपडेट"</string>
     <string name="reboot_to_update_prepare" msgid="6978842143587422365">"अपडेट करण्याची तयारी करत आहे…"</string>
     <string name="reboot_to_update_package" msgid="4644104795527534811">"अपडेट पॅकेज प्रक्रिया करत आहे…"</string>
     <string name="reboot_to_update_reboot" msgid="4474726009984452312">"रीस्टार्ट करत आहे..."</string>
@@ -274,7 +274,7 @@
     <string name="bugreport_option_interactive_title" msgid="7968287837902871289">"परस्परसंवादी अहवाल"</string>
     <string name="bugreport_option_interactive_summary" msgid="8493795476325339542">"बहुतांश प्रसंगांमध्ये याचा वापर करा. ते तुम्हाला अहवालाच्या प्रगतीचा मागोवा घेण्याची, समस्येविषयी आणखी तपाशील एंटर करण्याची आणि स्क्रीनशॉट घेण्याची अनुमती देते. ते कदाचित अहवाल देण्यासाठी बराच वेळ घेणारे कमी-वापरलेले विभाग वगळू शकते."</string>
     <string name="bugreport_option_full_title" msgid="7681035745950045690">"संपूर्ण अहवाल"</string>
-    <string name="bugreport_option_full_summary" msgid="1975130009258435885">"तुमचे डिव्हाइस प्रतिसाद देत नाही किंवा खूप धीमे असते अथवा तुम्हाला सर्व अहवाल विभागांची आवश्यकता असते तेव्हा कमीतकमी सिस्टम हस्तक्षेपासाठी या पर्यायाचा वापर करा. तुम्हाला आणखी तपशील एंटर करण्याची किंवा अतिरिक्त स्क्रीनशॉट घेण्याची अनुमती देत नाही."</string>
+    <string name="bugreport_option_full_summary" msgid="1975130009258435885">"तुमचे डिव्हाइस प्रतिसाद देत नाही किंवा खूप धीमे असते अथवा तुम्हाला सर्व अहवाल विभागांची आवश्यकता असते तेव्हा कमीतकमी सिस्टीम हस्तक्षेपासाठी या पर्यायाचा वापर करा. तुम्हाला आणखी तपशील एंटर करण्याची किंवा अतिरिक्त स्क्रीनशॉट घेण्याची अनुमती देत नाही."</string>
     <string name="bugreport_countdown" msgid="6418620521782120755">"{count,plural, =1{बग रिपोर्टसाठी # सेकंदामध्ये स्क्रीनशॉट घेत आहे.}other{बग रिपोर्टसाठी # सेकंदांमध्ये स्क्रीनशॉट घेत आहे.}}"</string>
     <string name="bugreport_screenshot_success_toast" msgid="7986095104151473745">"बग रिपोर्टसह घेतलेला स्क्रीनशॉट"</string>
     <string name="bugreport_screenshot_failure_toast" msgid="6736320861311294294">"बग रिपोर्टसह स्क्रीनशॉट घेता आला नाही"</string>
@@ -374,7 +374,7 @@
     <string name="dream_preview_title" msgid="5570751491996100804">"पूर्वावलोकन, <xliff:g id="DREAM_NAME">%1$s</xliff:g>"</string>
     <string name="dream_accessibility_action_click" msgid="7392398629967797805">"डिसमिस करा"</string>
     <string name="permlab_statusBar" msgid="8798267849526214017">"स्टेटस बार अक्षम करा किंवा सुधारित करा"</string>
-    <string name="permdesc_statusBar" msgid="5809162768651019642">"स्टेटस बार अक्षम करण्यासाठी किंवा सिस्टम चिन्हे जोडण्यासाठी आणि काढण्यासाठी अ‍ॅप ला अनुमती देते."</string>
+    <string name="permdesc_statusBar" msgid="5809162768651019642">"स्टेटस बार बंद करण्यासाठी किंवा सिस्टीम आयकन जोडण्यासाठी आणि काढण्यासाठी ॲपला परवानगी देते."</string>
     <string name="permlab_statusBarService" msgid="2523421018081437981">"स्टेटस बार होऊ द्या"</string>
     <string name="permdesc_statusBarService" msgid="6652917399085712557">"स्टेटस बार होण्यासाठी अ‍ॅप ला अनुमती देते."</string>
     <string name="permlab_expandStatusBar" msgid="1184232794782141698">"स्‍टेटस बार विस्तृत करा/संकुचित करा"</string>
@@ -472,9 +472,9 @@
     <string name="permlab_writeSettings" msgid="8057285063719277394">"सिस्टीम सेटिंग्ज सुधारित करा"</string>
     <string name="permdesc_writeSettings" msgid="8293047411196067188">"सिस्टीमचा सेटिंग्ज डेटा सुधारित करण्यासाठी अ‍ॅपला अनुमती देते. दुर्भावनापूर्ण अ‍ॅप्स तुमच्या सिस्टीमचे कॉन्फिगरेशन दूषित करू शकतात."</string>
     <string name="permlab_receiveBootCompleted" msgid="6643339400247325379">"सुरूवातीस चालवा"</string>
-    <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"जसे सिस्टम बूट करणे समाप्त करते तसे अ‍ॅप ला स्वतः सुरू करण्यास अनुमती देते. यामुळे टॅबलेट सुरू करण्यास वेळ लागू शकतो आणि नेहमी सुरू राहून एकंदर टॅबलेटला धीमे करण्यास अ‍ॅप ला अनुमती देते."</string>
-    <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"सिस्टम बूट होणे संपल्यावर ॲपला स्वतः सुरू होण्याची अनुमती देते. यामुळे तुमच्या Android TV डिव्हाइसला सुरू होण्यास वेळ लागू शकतो आणि नेहमी सुरू राहून एकंदर डिव्हाइसलाच धीमे करण्याची अनुमती ॲपला देते."</string>
-    <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"जसे सिस्टम बूट करणे समाप्त करते तसे अ‍ॅप ला स्वतः सुरू करण्यास अनुमती देते. यामुळे फोन सुरू करण्यास वेळ लागू शकतो आणि नेहमी सुरू राहून एकंदर फोनला धीमे करण्यास अ‍ॅप ला अनुमती देते."</string>
+    <string name="permdesc_receiveBootCompleted" product="tablet" msgid="5565659082718177484">"जसे सिस्टीम बूट करणे समाप्त करते तसे ॲपला स्वतः सुरू करण्यास अनुमती देते. यामुळे टॅबलेट सुरू करण्यास वेळ लागू शकतो आणि नेहमी सुरू राहून एकंदर टॅबलेटला धीमे करण्यास ॲपला अनुमती देते."</string>
+    <string name="permdesc_receiveBootCompleted" product="tv" msgid="4900842256047614307">"सिस्टीम बूट होणे संपल्यावर ॲपला स्वतः सुरू होण्याची अनुमती देते. यामुळे तुमच्या Android TV डिव्हाइसला सुरू होण्यास वेळ लागू शकतो आणि नेहमी सुरू राहून एकंदर डिव्हाइसलाच धीमे करण्याची अनुमती ॲपला देते."</string>
+    <string name="permdesc_receiveBootCompleted" product="default" msgid="7912677044558690092">"जसे सिस्टीम बूट करणे समाप्त करते तसे ॲपला स्वतः सुरू करण्यास अनुमती देते. यामुळे फोन सुरू करण्यास वेळ लागू शकतो आणि नेहमी सुरू राहून एकंदर फोनला धीमे करण्यास ॲपला अनुमती देते."</string>
     <string name="permlab_broadcastSticky" msgid="4552241916400572230">"रोचक प्रसारण पाठवा"</string>
     <string name="permdesc_broadcastSticky" product="tablet" msgid="5058486069846384013">"रोचक प्रसारणे पाठविण्यासाठी अ‍ॅप ला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो टॅब्लेटला धीमा किंवा अस्थिर करू शकतो."</string>
     <string name="permdesc_broadcastSticky" product="tv" msgid="2338185920171000650">"रोचक प्रसारणे पाठविण्यासाठी अ‍ॅपला अनुमती देते, जे प्रसारण समाप्त झाल्यानंतर देखील तसेच राहते. अत्याधिक वापरामुळे बरीच मेमरी वापरली जाऊन तो तुमच्या Android TV डिव्हाइसला धिमा किंवा अस्थिर करू शकतो."</string>
@@ -529,8 +529,8 @@
     <string name="permdesc_camera" msgid="5240801376168647151">"ॲप वापरात असताना, हे ॲप कॅमेरा वापरून फोटो काढू शकते आणि व्हिडिओ रेकॉर्ड करू शकते."</string>
     <string name="permlab_backgroundCamera" msgid="7549917926079731681">"बॅकग्राउंडमध्ये फोटो काढा आणि व्हिडिओ रेकॉर्ड करा"</string>
     <string name="permdesc_backgroundCamera" msgid="1615291686191138250">"हे ॲप कॅमेरा वापरून कधीही फोटो काढू शकते आणि व्हिडिओ रेकॉर्ड करू शकते."</string>
-    <string name="permlab_systemCamera" msgid="3642917457796210580">"फोटो आणि व्हिडिओ काढण्यासाठी ॲप्लिकेशन किंवा सेवेला सिस्टम कॅमेरे ॲक्सेस करण्याची अनुमती द्या"</string>
-    <string name="permdesc_systemCamera" msgid="5938360914419175986">"हे विशेषाधिकृत किंवा सिस्टम ॲप कधीही सिस्टम कॅमेरा वापरून फोटो आणि व्हिडिओ रेकॉर्ड करू शकते. ॲपकडे android.permission.CAMERA परवानगी असण्याचीदेखील आवश्यकता आहे"</string>
+    <string name="permlab_systemCamera" msgid="3642917457796210580">"फोटो आणि व्हिडिओ काढण्यासाठी ॲप्लिकेशन किंवा सेवेला सिस्टीम कॅमेरे ॲक्सेस करण्याची अनुमती द्या"</string>
+    <string name="permdesc_systemCamera" msgid="5938360914419175986">"हे विशेष महत्त्वाचे किंवा सिस्टीम ॲप कधीही सिस्टीम कॅमेरा वापरून फोटो आणि व्हिडिओ रेकॉर्ड करू शकते. ॲपकडे android.permission.CAMERA परवानगी असण्याचीदेखील आवश्यकता आहे"</string>
     <string name="permlab_cameraOpenCloseListener" msgid="5548732769068109315">"एखाद्या अ‍ॅप्लिकेशन किंवा सेवेला कॅमेरा डिव्हाइस सुरू किंवा बंद केल्याची कॉलबॅक मिळवण्याची अनुमती द्या."</string>
     <string name="permdesc_cameraOpenCloseListener" msgid="2002636131008772908">"कोणतेही कॅमेरा डिव्हाइस (कोणत्या अ‍ॅप्लिकेशनने) सुरू किंवा बंद केले जाते तेव्हा हे ॲप कॉलबॅक मिळवू शकते."</string>
     <string name="permlab_cameraHeadlessSystemUser" msgid="680194666834500050">"अ‍ॅप्लिकेशन किंवा सेवेला हेडलेस सिस्टीम वापरकर्ता म्हणून कॅमेरा अ‍ॅक्सेस करण्याची अनुमती द्या."</string>
@@ -548,7 +548,7 @@
     <string name="permdesc_readBasicPhoneState" msgid="828185691675460520">"यामुळे ॲपला डिव्हाइसची मूलभूत टेलिफोनी वैशिष्ट्ये अ‍ॅक्सेस करण्याची अनुमती मिळते."</string>
     <string name="permlab_manageOwnCalls" msgid="9033349060307561370">"प्रणालीच्या माध्यमातून कॉल रूट करा"</string>
     <string name="permdesc_manageOwnCalls" msgid="4431178362202142574">"कॉल करण्याचा अनुभव सुधारण्यासाठी ॲपला त्याचे कॉल प्रणालीच्या माध्यमातून रूट करू देते."</string>
-    <string name="permlab_callCompanionApp" msgid="3654373653014126884">"सिस्टम वापरून कॉल पहा आणि नियंत्रण ठेवा."</string>
+    <string name="permlab_callCompanionApp" msgid="3654373653014126884">"सिस्टीम वापरून कॉल पहा आणि नियंत्रण ठेवा."</string>
     <string name="permdesc_callCompanionApp" msgid="8474168926184156261">"डिव्हाइसवर येणार कॉल पाहण्यासाठी आणि नियंत्रित करण्यासाठी ॲपला अनुमती देते. यामध्ये कॉल करण्यासाठी कॉलचा नंबर आणि कॉलची स्थिती यासारख्या माहितीचा समावेश असतो."</string>
     <string name="permlab_exemptFromAudioRecordRestrictions" msgid="1164725468350759486">"ऑडिओ रेकॉर्ड प्रतिबंधांपासून मुक्त"</string>
     <string name="permdesc_exemptFromAudioRecordRestrictions" msgid="2425117015896871976">"ऑडिओ रेकॉर्ड करण्यासाठी प्रतिबंधांपासून ॲपला मुक्त करा."</string>
@@ -569,11 +569,11 @@
     <string name="permdesc_transmitIr" product="tv" msgid="3278506969529173281">"ॲपला Android TV डिव्हाइसचा इन्‍फ्रारेड ट्रान्‍समीटर वापरण्‍याची अनुमती देते."</string>
     <string name="permdesc_transmitIr" product="default" msgid="8484193849295581808">"अ‍ॅप ला फोनच्‍या इन्‍फ्रारेड ट्रान्‍समीटरचा वापर करण्‍याची अनुमती देते."</string>
     <string name="permlab_setWallpaper" msgid="6959514622698794511">"वॉलपेपर सेट करा"</string>
-    <string name="permdesc_setWallpaper" msgid="2973996714129021397">"सिस्टम वॉलपेपर सेट करण्यासाठी अ‍ॅप ला अनुमती देते."</string>
+    <string name="permdesc_setWallpaper" msgid="2973996714129021397">"सिस्टीम वॉलपेपर सेट करण्यासाठी ॲपला परवानगी देते."</string>
     <string name="permlab_accessHiddenProfile" msgid="8607094418491556823">"लपवलेल्या प्रोफाइल अ‍ॅक्सेस करा"</string>
     <string name="permdesc_accessHiddenProfile" msgid="1543153202481009676">"अ‍ॅपला लपवलेल्या प्रोफाइल अ‍ॅक्सेस करण्याची अनुमती देते."</string>
     <string name="permlab_setWallpaperHints" msgid="1153485176642032714">"तुमचा वॉलपेपर आकार समायोजित करा"</string>
-    <string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"सिस्टम वॉलपेपर आकार सूचना सेट करण्यासाठी अ‍ॅप ला अनुमती देते."</string>
+    <string name="permdesc_setWallpaperHints" msgid="6257053376990044668">"सिस्टीम वॉलपेपर आकार सूचना सेट करण्याची ॲपला परवानगी देते."</string>
     <string name="permlab_setTimeZone" msgid="7922618798611542432">"टाइम झोन सेट करा"</string>
     <string name="permdesc_setTimeZone" product="tablet" msgid="1788868809638682503">"टॅब्लेटचा टाइम झोन बदलण्यासाठी अ‍ॅप ला अनुमती देते."</string>
     <string name="permdesc_setTimeZone" product="tv" msgid="9069045914174455938">"तुमच्या Android TV डिव्हाइसचा टाइम झोन बदलण्यासाठी ॲपला अनुमती देते."</string>
@@ -1241,7 +1241,7 @@
     <string name="input_method_ime_switch_long_click_action_desc" msgid="3161942124116646998">"इनपुट पद्धत पिकर उघडा"</string>
     <string name="input_method_switcher_settings_button" msgid="5609835654697108485">"सेटिंग्ज"</string>
     <string name="low_internal_storage_view_title" msgid="9024241779284783414">"संचयन स्थान संपत आहे"</string>
-    <string name="low_internal_storage_view_text" msgid="8172166728369697835">"काही सिस्टम कार्ये कार्य करू शकत नाहीत"</string>
+    <string name="low_internal_storage_view_text" msgid="8172166728369697835">"काही सिस्टीम फंक्शन कार्य करू शकत नाहीत"</string>
     <string name="low_internal_storage_view_text_no_boot" msgid="7368968163411251788">"सिस्टीमसाठी पुरेसे संचयन नाही. आपल्याकडे 250MB मोकळे स्थान असल्याचे सुनिश्चित करा आणि रीस्टार्ट करा."</string>
     <string name="app_running_notification_title" msgid="8985999749231486569">"<xliff:g id="APP_NAME">%1$s</xliff:g> चालत आहे"</string>
     <string name="app_running_notification_text" msgid="5120815883400228566">"अधिक माहितीसाठी किंवा अ‍ॅप थांबविण्यासाठी टॅप करा."</string>
@@ -1287,7 +1287,7 @@
     <string name="whichImageCaptureApplicationLabel" msgid="6505433734824988277">"इमेज कॅप्चर करा"</string>
     <string name="alwaysUse" msgid="3153558199076112903">"या क्रियेसाठी डीफॉल्‍टनुसार वापरा."</string>
     <string name="use_a_different_app" msgid="4987790276170972776">"एक भिन्न अ‍ॅप वापरा"</string>
-    <string name="clearDefaultHintMsg" msgid="1325866337702524936">"डाउनलोड केलेल्या सिस्टम सेटिंग्ज &gt; Apps &gt; मधील डीफॉल्ट साफ करा."</string>
+    <string name="clearDefaultHintMsg" msgid="1325866337702524936">"डाउनलोड केलेल्या सिस्टीम सेटिंग्ज &gt; Apps &gt; मधील डीफॉल्ट साफ करा."</string>
     <string name="chooseActivity" msgid="8563390197659779956">"क्रिया निवडा"</string>
     <string name="chooseUsbActivity" msgid="2096269989990986612">"USB डिव्हाइससाठी अ‍ॅप निवडा"</string>
     <string name="noApplications" msgid="1186909265235544019">"कोणतेही अ‍ॅप्स ही क्रिया करू शकत नाहीत."</string>
@@ -1315,7 +1315,7 @@
     <string name="launch_warning_original" msgid="3332206576800169626">"<xliff:g id="APP_NAME">%1$s</xliff:g> मूळतः लाँच केले."</string>
     <string name="screen_compat_mode_scale" msgid="8627359598437527726">"स्केल"</string>
     <string name="screen_compat_mode_show" msgid="5080361367584709857">"नेहमी दर्शवा"</string>
-    <string name="screen_compat_mode_hint" msgid="4032272159093750908">"सिस्टम सेटिंग्ज &gt; Apps &gt; डाउनलोड केलेले मध्ये हे पुन्हा-सुरू करा."</string>
+    <string name="screen_compat_mode_hint" msgid="4032272159093750908">"सिस्टीम सेटिंग्ज &gt; Apps &gt; डाउनलोड केलेले मध्ये हे पुन्हा-सुरू करा."</string>
     <string name="unsupported_display_size_message" msgid="7265211375269394699">"<xliff:g id="APP_NAME">%1$s</xliff:g> वर्तमान डिस्प्ले आकार सेटिंगला समर्थन देत नाही आणि अनपेक्षित वर्तन करू शकते."</string>
     <string name="unsupported_display_size_show" msgid="980129850974919375">"नेहमी दर्शवा"</string>
     <string name="unsupported_compile_sdk_message" msgid="7326293500707890537">"<xliff:g id="APP_NAME">%1$s</xliff:g> हे Android OS च्या विसंगत आवृत्तीसाठी तयार केले होते आणि ते अनपेक्षित पद्धतीने काम करू शकते. ॲपची अपडेट केलेली आवृत्ती उपलब्ध असू शकते."</string>
@@ -1330,7 +1330,7 @@
     <string name="android_start_title" product="automotive" msgid="7917984412828168079">"Android सुरू करत आहे…"</string>
     <string name="android_start_title" product="tablet" msgid="4429767260263190344">"टॅबलेट सुरू होत आहे…"</string>
     <string name="android_start_title" product="device" msgid="6967413819673299309">"डिव्‍हाइस सुरू होत आहे…"</string>
-    <string name="android_upgrading_notification_title" product="default" msgid="3509927005342279257">"सिस्‍टम अपडेट संपत आहे…"</string>
+    <string name="android_upgrading_notification_title" product="default" msgid="3509927005342279257">"सिस्टीम अपडेट संपत आहे…"</string>
     <string name="app_upgrading_toast" msgid="1016267296049455585">"<xliff:g id="APPLICATION">%1$s</xliff:g> श्रेणीसुधारित करत आहे…"</string>
     <string name="android_preparing_apk" msgid="589736917792300956">"<xliff:g id="APPNAME">%1$s</xliff:g> तयार करत आहे."</string>
     <string name="android_upgrading_starting_apps" msgid="6206161195076057075">"अ‍ॅप्स सुरू करत आहे."</string>
@@ -1708,7 +1708,7 @@
     <string name="default_audio_route_name_external_device" msgid="8124229858618975">"बाह्य डिव्हाइस"</string>
     <string name="default_audio_route_name_headphones" msgid="6954070994792640762">"हेडफोन"</string>
     <string name="default_audio_route_name_usb" msgid="895668743163316932">"USB"</string>
-    <string name="default_audio_route_category_name" msgid="5241740395748134483">"सिस्टम"</string>
+    <string name="default_audio_route_category_name" msgid="5241740395748134483">"सिस्टीम"</string>
     <string name="bluetooth_a2dp_audio_route_name" msgid="4214648773120426288">"ब्लूटूथ ऑडिओ"</string>
     <string name="wireless_display_route_description" msgid="8297563323032966831">"वायरलेस डिस्प्ले"</string>
     <string name="media_route_button_content_description" msgid="2299223698196869956">"कास्‍ट करा"</string>
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"एकहाती मोड"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"आणखी डिम"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"श्रवणयंत्रे"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ऑटोक्लिक"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"डिस्कनेक्ट केले आहे"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"कनेक्ट केले आहे"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"अ‍ॅक्टिव्ह"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"हँड्स-फ्री कॉलिंगसाठी तुम्ही तुमच्या श्रवणयंत्राचा मायक्रोफोन वापरू शकता. यामुळे कॉलदरम्यान फक्त तुमचा माइक स्विच केला जातो."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"स्विच करा"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"सेटिंग्ज"</string>
-    <string name="user_switched" msgid="7249833311585228097">"वर्तमान वापरकर्ता <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> वर स्विच करत आहे…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> लॉग आउट करत आहे…"</string>
     <string name="owner_name" msgid="8713560351570795743">"मालक"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"अनपिन करण्‍यापूर्वी अनलॉक नमुन्यासाठी विचारा"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"अनपिन करण्‍यापूर्वी संकेतशब्दासाठी विचारा"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"तुमच्या ॲडमिनने इंस्टॉल केले आहे.\nदिलेल्या परवानग्या पाहण्यासाठी सेटिंग्जवर जा"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"आपल्या प्रशासकाने अपडेट केले"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"आपल्या प्रशासकाने हटवले"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ओके"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"बॅटरी सेव्हर गडद थीम सुरू करते आणि बॅकग्राउंड ॲक्टिव्हिटी, काही व्हिज्युअल इफेक्ट, ठरावीक वैशिष्ट्ये व काही नेटवर्क कनेक्शन मर्यादित किंवा बंद करते."</string>
@@ -2192,12 +2191,12 @@
     <string name="screenshot_edit" msgid="7408934887203689207">"संपादित करा"</string>
     <string name="volume_dialog_ringer_guidance_vibrate" msgid="2055927873175228519">"कॉल आणि सूचनांवर व्हायब्रेट होईल"</string>
     <string name="volume_dialog_ringer_guidance_silent" msgid="1011246774949993783">"कॉल आणि सूचना म्यूट केल्या जातील"</string>
-    <string name="notification_channel_system_changes" msgid="2462010596920209678">"सिस्टम बदल"</string>
+    <string name="notification_channel_system_changes" msgid="2462010596920209678">"सिस्टीम बदल"</string>
     <string name="review_notification_settings_title" msgid="5102557424459810820">"सूचना सेटिंग्जचे पुनरावलोकन करा"</string>
     <string name="review_notification_settings_text" msgid="5916244866751849279">"Android 13 पासून, तुम्ही त्यामध्ये इंस्टॉल केलेल्या अ‍ॅप्सना सूचना पाठवण्यासाठी तुमच्या परवानगीची आवश्यकता आहे. सध्याच्या अ‍ॅप्ससाठी ही परवानगी बदलण्याकरिता टॅप करा."</string>
     <string name="review_notification_settings_remind_me_action" msgid="1081081018678480907">"मला आठवण करून द्या"</string>
     <string name="review_notification_settings_dismiss" msgid="4160916504616428294">"डिसमिस करा"</string>
-    <string name="notification_app_name_system" msgid="3045196791746735601">"सिस्टम"</string>
+    <string name="notification_app_name_system" msgid="3045196791746735601">"सिस्टीम"</string>
     <string name="notification_app_name_settings" msgid="9088548800899952531">"सेटिंग्ज"</string>
     <string name="notification_appops_camera_active" msgid="8177643089272352083">"कॅमेरा"</string>
     <string name="notification_appops_microphone_active" msgid="581333393214739332">"मायक्रोफोन"</string>
diff --git a/core/res/res/values-ms/strings.xml b/core/res/res/values-ms/strings.xml
index 43acbac..bda439a 100644
--- a/core/res/res/values-ms/strings.xml
+++ b/core/res/res/values-ms/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Mod sebelah tangan"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Amat malap"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Peranti pendengaran"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoklik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Diputuskan sambungan"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Disambungkan"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktif"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Anda boleh menggunakan mikrofon alat bantu pendengaran anda untuk membuat panggilan bebas tangan. Tindakan ini hanya menukar mikrofon anda semasa panggilan."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Tukar"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Tetapan"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Pengguna semasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Beralih kepada <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Log keluar daripada <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Pemilik"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Minta corak buka kunci sebelum menyahsemat"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Minta kata laluan sebelum menyahsemat"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Dipasang oleh pentadbir anda.\nAkses tetapan untuk melihat kebenaran yang diberikan"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Dikemas kini oleh pentadbir anda"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Dipadamkan oleh pentadbir anda"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Penjimat Bateri menghidupkan tema Gelap dan mengehadkan atau mematikan aktiviti latar, sesetengah kesan visual, ciri tertentu dan sesetengah sambungan rangkaian."</string>
diff --git a/core/res/res/values-my/strings.xml b/core/res/res/values-my/strings.xml
index 2333539..9a80416 100644
--- a/core/res/res/values-my/strings.xml
+++ b/core/res/res/values-my/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"လက်တစ်ဖက်သုံးမုဒ်"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ပိုမှိန်ခြင်း"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"နားကြားကိရိယာ"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"အော်တိုနှိပ်ခြင်း"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ချိတ်ဆက်မထားပါ"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"ချိတ်ဆက်ထားသည်"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"သုံးနေသည်"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"လက်လွတ်ခေါ်ဆိုခြင်းအတွက် နားကြားကိရိယာ၏ မိုက်ခရိုဖုန်းကို သုံးနိုင်သည်။ ခေါ်ဆိုနေစဉ်သာ သင့်မိုက်ကို ပြောင်းပေးသည်။"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ပြောင်းရန်"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ဆက်တင်များ"</string>
-    <string name="user_switched" msgid="7249833311585228097">"လက်ရှိအသုံးပြုနေသူ <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>သို့ ပြောင်းနေသည်…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>ကို ထွက်ပစ်ပါတော့မည်..."</string>
     <string name="owner_name" msgid="8713560351570795743">"ပိုင်ရှင်"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ပင်မဖြုတ်မီ လော့ခ်ဖွင့်ပုံစံကို မေးရန်"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ပင်မဖြုတ်မီမှာ စကားဝှက်ကို မေးကြည့်ရန်"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"သင့်စီမံခန့်ခွဲသူက ထည့်သွင်းထားသည်။\nပေးထားသည့် ခွင့်ပြုချက်များကို ကြည့်ရန် ဆက်တင်များသို့ သွားပါ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"သင်၏ စီမံခန့်ခွဲသူက အပ်ဒိတ်လုပ်ထားသည်"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"သင်၏ စီမံခန့်ခွဲသူက ဖျက်လိုက်ပါပြီ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"‘ဘက်ထရီ အားထိန်း’ က ‘အမှောင်နောက်ခံ’ ကို ဖွင့်ပြီး နောက်ခံလုပ်ဆောင်ချက်၊ ဖန်တီးပြသချက်အချို့၊ ဝန်ဆောင်မှုအချို့နှင့် ကွန်ရက်ချိတ်ဆက်မှုအချို့တို့ကို ကန့်သတ်သည် သို့မဟုတ် ပိတ်သည်။"</string>
diff --git a/core/res/res/values-nb/strings.xml b/core/res/res/values-nb/strings.xml
index 3a337f6..d8e785f 100644
--- a/core/res/res/values-nb/strings.xml
+++ b/core/res/res/values-nb/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhåndsmodus"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra dimmet"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Høreapparater"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoklikk"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Frakoblet"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Tilkoblet"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiv"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Du kan bruke mikrofonen i høreapparatet til å ringe håndfritt. Dette fører bare til at mikrofonen byttes under samtalen."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Bytt"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Innstillinger"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Gjeldende bruker: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Bytter til <xliff:g id="NAME">%1$s</xliff:g> …"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Logger av <xliff:g id="NAME">%1$s</xliff:g> …"</string>
     <string name="owner_name" msgid="8713560351570795743">"Eier"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Krev opplåsingsmønster for å løsne apper"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Krev passord for å løsne apper"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Installert av administratoren din.\nGå til innstillingene for å se hvilke tillatelser som er gitt"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Oppdatert av administratoren din"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Slettet av administratoren din"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Batterisparing slår på mørkt tema og begrenser eller slår av bakgrunnsaktivitet, enkelte visuelle effekter, noen funksjoner og noen nettverkstilkoblinger."</string>
diff --git a/core/res/res/values-ne/strings.xml b/core/res/res/values-ne/strings.xml
index ce64589..88e9370 100644
--- a/core/res/res/values-ne/strings.xml
+++ b/core/res/res/values-ne/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"एक हाते मोड"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"अझै मधुरो"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"हियरिङ डिभाइसहरू"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"अटोक्लिक"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"डिस्कनेक्ट गरिएको"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"कनेक्ट गरिएको"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"सक्रिय"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"तपाईं ह्यान्ड्सफ्री तरिकाले कल गर्न आफ्नो श्रवण यन्त्रको माइक्रोफोन प्रयोग गर्न सक्नुहुन्छ। यसले कल भइरहेका बेला मात्र तपाईंको माइक बदल्छ।"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"बदल्नुहोस्"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"सेटिङ"</string>
-    <string name="user_switched" msgid="7249833311585228097">"अहिलेको प्रयोगकर्ता <xliff:g id="NAME">%1$s</xliff:g>।"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> मा स्विच गरिँदै छ…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"लग आउट गर्दै <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"मालिक"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"अनपिन गर्नअघि अनलक प्याटर्न माग्नुहोस्"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"पिन निकाल्नुअघि पासवर्ड सोध्नुहोस्"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"यो प्याकेज तपाईंका एड्मिनले इन्स्टल गर्नुभएको हो।\nप्रदान गरिएका अनुमतिसम्बन्धी जानकारी हेर्न सेटिङमा जानुहोस्"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"तपाईंका प्रशासकले अद्यावधिक गर्नुभएको"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"तपाईंका प्रशासकले मेट्नुभएको"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ठिक छ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ब्याट्री सेभरले अँध्यारो थिम अन गर्छ र ब्याकग्राउन्डमा हुने क्रियाकलाप, केही भिजुअल इफेक्ट, निश्चित सुविधा र केही नेटवर्क कनेक्सनहरू अफ गर्छ वा सीमित रूपमा मात्र चल्न दिन्छ।"</string>
diff --git a/core/res/res/values-nl/strings.xml b/core/res/res/values-nl/strings.xml
index f7b6cc8..a43c0c4 100644
--- a/core/res/res/values-nl/strings.xml
+++ b/core/res/res/values-nl/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Bediening met 1 hand"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dimmen"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hoortoestellen"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatisch klikken"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Verbinding verbroken"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Verbonden"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Actief"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Je kunt de microfoon van je hoortoestel gebruiken om handsfree te bellen. Hiermee wordt de microfoon alleen gewisseld tijdens het gesprek."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Wisselen"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Instellingen"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Huidige gebruiker <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Overschakelen naar <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> uitloggen…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Eigenaar"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Ontgrendelingspatroon vragen om app los te maken"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Vraag wachtwoord voor losmaken"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Geïnstalleerd door je beheerder.\nGa naar instellingen om verleende rechten te bekijken."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Geüpdatet door je beheerder"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Verwijderd door je beheerder"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Met Batterijbesparing wordt het donkere thema aangezet en worden achtergrondactiviteit, bepaalde visuele effecten, bepaalde functies en sommige netwerkverbindingen beperkt of uitgezet."</string>
diff --git a/core/res/res/values-or/strings.xml b/core/res/res/values-or/strings.xml
index ef567e5..f61e109 100644
--- a/core/res/res/values-or/strings.xml
+++ b/core/res/res/values-or/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ଏକ-ହାତ ମୋଡ୍"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ଅତ୍ୟଧିକ ଡିମ"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ଶ୍ରବଣ ଡିଭାଇସଗୁଡ଼ିକ"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ଅଟୋକ୍ଲିକ"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ଡିସକନେକ୍ଟ କରାଯାଇଛି"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"କନେକ୍ଟ କରାଯାଇଛି"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"ସକ୍ରିୟ"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"ହେଣ୍ଡସ-ଫ୍ରି କଲିଂ ପାଇଁ ଆପଣ ଆପଣଙ୍କର ଶ୍ରବଣ ଯନ୍ତ୍ର ମାଇକ୍ରୋଫୋନ ବ୍ୟବହାର କରିପାରିବେ। କଲ ସମୟରେ ଏହା କେବଳ ଆପଣଙ୍କର ମାଇକକୁ ସୁଇଚ କରିଥାଏ।"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ସୁଇଚ କରନ୍ତୁ"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ସେଟିଂସ"</string>
-    <string name="user_switched" msgid="7249833311585228097">"ବର୍ତ୍ତମାନର ୟୁଜର୍‌ ହେଉଛନ୍ତି <xliff:g id="NAME">%1$s</xliff:g>।"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>ରେ ସୁଇଚ ହେଉଛି…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>ଙ୍କୁ ଲଗଆଉଟ୍‍ କରାଯାଉଛି…"</string>
     <string name="owner_name" msgid="8713560351570795743">"ମାଲିକ"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ଅନପିନ୍‌ କରିବା ପୂର୍ବରୁ ଲକ୍‌ ଖୋଲିବା ପାଟର୍ନ ପଚାରନ୍ତୁ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ଅନପିନ୍‌ କରିବା ପୂର୍ବରୁ ପାସ୍‌ୱର୍ଡ ପଚାରନ୍ତୁ"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"ଆପଣଙ୍କ ଆଡମିନଙ୍କ ଦ୍ୱାରା ଇନଷ୍ଟଲ କରାଯାଇଛି।\nଅନୁମୋଦିତ ଅମୁମତିଗୁଡ଼ିକ ଭ୍ୟୁ କରିବା ପାଇଁ ସେଟିଂସକୁ ଯାଆନ୍ତୁ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"ଆପଣଙ୍କ ଆଡମିନ୍‌‌ ଅପଡେଟ୍‍ କରିଛନ୍ତି"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ଆପଣଙ୍କ ଆଡମିନ୍‌‌ ଡିଲିଟ୍‍ କରିଛନ୍ତି"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ଠିକ ଅଛି"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ବେଟେରୀ ସେଭର ଗାଢ଼ା ଥିମକୁ ଚାଲୁ କରେ ଏବଂ ପୃଷ୍ଠପଟ କାର୍ଯ୍ୟକଳାପ, କିଛି ଭିଜୁଆଲ ଇଫେକ୍ଟ, କିଛି ଫିଚର ଏବଂ କିଛି ନେଟୱାର୍କ ସଂଯୋଗକୁ ସୀମିତ କିମ୍ବା ବନ୍ଦ କରେ।"</string>
diff --git a/core/res/res/values-pa/strings.xml b/core/res/res/values-pa/strings.xml
index 7f06227..5d2cc7b 100644
--- a/core/res/res/values-pa/strings.xml
+++ b/core/res/res/values-pa/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ਇੱਕ ਹੱਥ ਮੋਡ"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ਜ਼ਿਆਦਾ ਘੱਟ ਚਮਕ"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ਸੁਣਨ ਵਾਲੇ ਡੀਵਾਈਸ"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ਸਵੈ-ਕਲਿੱਕ"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"ਡਿਸਕਨੈਕਟ ਹੋ ਗਿਆ"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"ਕਨੈਕਟ ਹੈ"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"ਕਿਰਿਆਸ਼ੀਲ"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"ਤੁਸੀਂ ਹੱਥ-ਰਹਿਤ ਕਾਲਿੰਗ ਲਈ ਆਪਣੇ ਸੁਣਨ ਦੇ ਸਾਧਨ ਦੇ ਮਾਈਕ੍ਰੋਫ਼ੋਨ ਦੀ ਵਰਤੋਂ ਕਰ ਸਕਦੇ ਹੋ। ਇਹ ਸਿਰਫ਼ ਕਾਲ ਦੌਰਾਨ ਹੀ ਤੁਹਾਡੇ ਮਾਈਕ ਨੂੰ ਸਵਿੱਚ ਕਰਦਾ ਹੈ।"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"ਸਵਿੱਚ ਕਰੋ"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ਸੈਟਿੰਗਾਂ"</string>
-    <string name="user_switched" msgid="7249833311585228097">"ਮੌਜੂਦਾ ਉਪਭੋਗਤਾ <xliff:g id="NAME">%1$s</xliff:g>।"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> \'ਤੇ ਸਵਿੱਚ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> ਨੂੰ ਲਾਗ-ਆਉਟ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ …"</string>
     <string name="owner_name" msgid="8713560351570795743">"ਮਾਲਕ"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ਅਨਪਿੰਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਅਣਲਾਕ ਪੈਟਰਨ ਵਾਸਤੇ ਪੁੱਛੋ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ਅਣਪਿੰਨ ਕਰਨ ਤੋਂ ਪਹਿਲਾਂ ਪਾਸਵਰਡ ਮੰਗੋ"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਸਥਾਪਤ ਕੀਤਾ ਗਿਆ।\nਦਿੱਤੀਆਂ ਗਈਆਂ ਇਜਾਜ਼ਤਾਂ ਨੂੰ ਦੇਖਣ ਲਈ ਸੈਟਿੰਗਾਂ \'ਤੇ ਜਾਓ"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਅੱਪਡੇਟ ਕੀਤਾ ਗਿਆ"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ਤੁਹਾਡੇ ਪ੍ਰਸ਼ਾਸਕ ਵੱਲੋਂ ਮਿਟਾਇਆ ਗਿਆ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ਠੀਕ ਹੈ"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"ਬੈਟਰੀ ਸੇਵਰ ਗੂੜ੍ਹੇ ਥੀਮ ਨੂੰ ਚਾਲੂ ਕਰਦਾ ਹੈ ਅਤੇ ਬੈਕਗ੍ਰਾਊਂਡ ਸਰਗਰਮੀ, ਕੁਝ ਦ੍ਰਿਸ਼ਟੀਗਤ ਪ੍ਰਭਾਵਾਂ, ਕੁਝ ਖਾਸ ਵਿਸ਼ੇਸ਼ਤਾਵਾਂ ਅਤੇ ਕੁਝ ਨੈੱਟਵਰਕ ਕਨੈਕਸ਼ਨਾਂ ਨੂੰ ਸੀਮਤ ਜਾਂ ਬੰਦ ਕਰਦਾ ਹੈ।"</string>
diff --git a/core/res/res/values-pl/strings.xml b/core/res/res/values-pl/strings.xml
index 73e4d24..bb7edb8 100644
--- a/core/res/res/values-pl/strings.xml
+++ b/core/res/res/values-pl/strings.xml
@@ -1715,7 +1715,7 @@
     <string name="wireless_display_route_description" msgid="8297563323032966831">"Wyświetlacz bezprzewodowy"</string>
     <string name="media_route_button_content_description" msgid="2299223698196869956">"Przesyłaj"</string>
     <string name="media_route_chooser_title" msgid="6646594924991269208">"Połącz z urządzeniem"</string>
-    <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Prześlij ekran na urządzenie"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Prześlij treści z ekranu na urządzenie"</string>
     <string name="media_route_chooser_searching" msgid="6119673534251329535">"Szukam urządzeń…"</string>
     <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Ustawienia"</string>
     <string name="media_route_controller_disconnect" msgid="7362617572732576959">"Rozłącz"</string>
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Tryb jednej ręki"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Dodatkowe przyciemnienie"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Urządzenia słuchowe"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatyczne kliknięcie"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Rozłączone"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Połączone"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktywne"</string>
@@ -1827,7 +1826,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Możesz używać mikrofonu w aparacie słuchowym, aby dzwonić bez użycia rąk. Mikrofon zostanie przełączony tylko na czas połączenia."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Przełącz"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Ustawienia"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Bieżący użytkownik: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Przełączam na użytkownika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Wylogowuję użytkownika <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Właściciel"</string>
@@ -1969,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Aby odpiąć, poproś o wzór odblokowania"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Aby odpiąć, poproś o hasło"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Zainstalowany przez administratora.\nOtwórz ustawienia, aby wyświetlić przyznane uprawnienia"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Zaktualizowany przez administratora"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Usunięty przez administratora"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Oszczędzanie baterii uruchamia ciemny motyw oraz wyłącza lub ogranicza aktywność w tle, niektóre efekty wizualne, pewne funkcje oraz wybrane połączenia sieciowe."</string>
diff --git a/core/res/res/values-pt-rBR/strings.xml b/core/res/res/values-pt-rBR/strings.xml
index f15ab35..0440e39 100644
--- a/core/res/res/values-pt-rBR/strings.xml
+++ b/core/res/res/values-pt-rBR/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Tela ainda mais escura"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparelhos auditivos"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clique automático"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Ativo"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Você pode usar o microfone do aparelho auditivo para fazer ligações sem usar as mãos. A troca do microfone só será feita durante a ligação."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Trocar"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Configurações"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Mudando para <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Desconectando <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Proprietário"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrão de desbloqueio antes de liberar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir senha antes de liberar"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalado pelo administrador.\nAcesse as configurações para conferir as permissões concedidas"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"A Economia de bateria ativa o tema escuro e limita ou desativa atividades em segundo plano, alguns efeitos visuais, recursos específicos e algumas conexões de rede."</string>
diff --git a/core/res/res/values-pt-rPT/strings.xml b/core/res/res/values-pt-rPT/strings.xml
index e80b780..745e17b 100644
--- a/core/res/res/values-pt-rPT/strings.xml
+++ b/core/res/res/values-pt-rPT/strings.xml
@@ -1714,7 +1714,7 @@
     <string name="wireless_display_route_description" msgid="8297563323032966831">"Visualização sem fios"</string>
     <string name="media_route_button_content_description" msgid="2299223698196869956">"Transmitir"</string>
     <string name="media_route_chooser_title" msgid="6646594924991269208">"Ligar ao dispositivo"</string>
-    <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Transmitir ecrã para dispositivo"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"Transmita o ecrã para o dispositivo"</string>
     <string name="media_route_chooser_searching" msgid="6119673534251329535">"A pesquisar dispositivos…"</string>
     <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"Definições"</string>
     <string name="media_route_controller_disconnect" msgid="7362617572732576959">"Desligar"</string>
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mais escuro"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Dispositivos auditivos"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clique automático"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desligado"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ligado"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Ativo"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Pode usar o microfone do aparelho auditivo para chamadas mãos-livres. Esta ação apenas muda o microfone durante a chamada."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Mudar"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Definições"</string>
-    <string name="user_switched" msgid="7249833311585228097">"<xliff:g id="NAME">%1$s</xliff:g> do utilizador atual."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"A mudar para <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"A terminar a sessão de <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Proprietário"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrão de desbloqueio antes de soltar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir palavra-passe antes de soltar"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalado pelo seu administrador.\nAceda às definições para ver as autorizações concedidas"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu gestor"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Eliminado pelo seu gestor"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"A Poupança de bateria ativa o tema escuro e limita ou desativa a atividade em segundo plano, alguns efeitos visuais, determinadas funcionalidades e algumas ligações de rede."</string>
diff --git a/core/res/res/values-pt/strings.xml b/core/res/res/values-pt/strings.xml
index f15ab35..0440e39 100644
--- a/core/res/res/values-pt/strings.xml
+++ b/core/res/res/values-pt/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modo para uma mão"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Tela ainda mais escura"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparelhos auditivos"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clique automático"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Desconectado"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectado"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Ativo"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Você pode usar o microfone do aparelho auditivo para fazer ligações sem usar as mãos. A troca do microfone só será feita durante a ligação."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Trocar"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Configurações"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Usuário atual <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Mudando para <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Desconectando <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Proprietário"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pedir padrão de desbloqueio antes de liberar"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pedir senha antes de liberar"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalado pelo administrador.\nAcesse as configurações para conferir as permissões concedidas"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Atualizado pelo seu administrador"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Excluído pelo seu administrador"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"A Economia de bateria ativa o tema escuro e limita ou desativa atividades em segundo plano, alguns efeitos visuais, recursos específicos e algumas conexões de rede."</string>
diff --git a/core/res/res/values-ro/strings.xml b/core/res/res/values-ro/strings.xml
index f02923b..4ef0423 100644
--- a/core/res/res/values-ro/strings.xml
+++ b/core/res/res/values-ro/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modul cu o mână"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Luminozitate redusă suplimentar"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Aparate auditive"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Clic automat"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Deconectat"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Conectat"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Activ"</string>
@@ -1826,8 +1825,7 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Poți folosi microfonul aparatului auditiv pentru apelarea hands-free. Astfel, microfonul pornește numai în timpul apelului."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Schimbă"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Setări"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Utilizator curent: <xliff:g id="NAME">%1$s</xliff:g>."</string>
-    <string name="user_switching_message" msgid="1912993630661332336">"Se comută la <xliff:g id="NAME">%1$s</xliff:g>…"</string>
+    <string name="user_switching_message" msgid="1912993630661332336">"Se trece la <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Se deconectează utilizatorul <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Proprietar"</string>
     <string name="guest_name" msgid="8502103277839834324">"Invitat"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Solicită mai întâi modelul pentru deblocare"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Solicită parola înainte de a anula fixarea"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instalat de administrator.\nAccesează setările ca să vezi permisiunile acordate."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Actualizat de administrator"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Șters de administrator"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Economisirea bateriei activează tema întunecată și restricționează sau dezactivează activitatea în fundal, unele efecte vizuale, alte funcții și câteva conexiuni la rețea."</string>
diff --git a/core/res/res/values-ru/strings.xml b/core/res/res/values-ru/strings.xml
index e32ec41..a03963e 100644
--- a/core/res/res/values-ru/strings.xml
+++ b/core/res/res/values-ru/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим управления одной рукой"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Дополнительное уменьшение яркости"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слуховые аппараты"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Автонажатие"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Отключено"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Подключено"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Активно"</string>
@@ -1827,7 +1826,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Вы можете использовать микрофон слухового аппарата, когда разговариваете по телефону. Микрофон будет переключен только на время звонка."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Переключиться"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Настройки"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Выбран аккаунт пользователя <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Смена профиля на \"<xliff:g id="NAME">%1$s</xliff:g>\"…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Выход из аккаунта <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Владелец"</string>
@@ -1969,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запрашивать графический ключ"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запрашивать пароль"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Установлено администратором.\nЧтобы посмотреть предоставленные разрешения, перейдите в настройки."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Обновлено администратором"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Удалено администратором"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"В режиме энергосбережения включается тёмная тема, ограничиваются или отключаются фоновые процессы, а также некоторые визуальные эффекты, часть функций и сетевых подключений."</string>
diff --git a/core/res/res/values-si/strings.xml b/core/res/res/values-si/strings.xml
index 35251bc..571706e 100644
--- a/core/res/res/values-si/strings.xml
+++ b/core/res/res/values-si/strings.xml
@@ -1713,7 +1713,7 @@
     <string name="wireless_display_route_description" msgid="8297563323032966831">"නොරැහැන් සංදර්ශකය"</string>
     <string name="media_route_button_content_description" msgid="2299223698196869956">"Cast"</string>
     <string name="media_route_chooser_title" msgid="6646594924991269208">"උපාංගයට සම්බන්ධ වන්න"</string>
-    <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"තිරය උපාංගයට යොමු කරන්න"</string>
+    <string name="media_route_chooser_title_for_remote_display" msgid="3105906508794326446">"තිරය උපාංගයට විකාශය කරන්න"</string>
     <string name="media_route_chooser_searching" msgid="6119673534251329535">"උපාංග සඳහා සොයමින්…"</string>
     <string name="media_route_chooser_extended_settings" msgid="2506352159381327741">"සැකසීම්"</string>
     <string name="media_route_controller_disconnect" msgid="7362617572732576959">"විසන්ධි කරන්න"</string>
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"තනි අත් ප්‍රකාරය"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"තවත් අඳුරු"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"ශ්‍රවණ උපාංග"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ස්වයං ක්ලික් කිරීම"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"විසන්ධි විය"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"සම්බන්ධිතයි"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"සක්‍රිය"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"දෑත් නොයොදන ඇමතුම් සඳහා ඔබට ඔබේ ශ්‍රවණාධාර මයික්‍රෆෝනය භාවිතා කළ හැක. මෙය ඇමතුම අතරතුර පමණක් ඔබේ මයික්‍රෆෝනය මාරු කරයි."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"මාරු කරන්න"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"සැකසීම්"</string>
-    <string name="user_switched" msgid="7249833311585228097">"දැනට සිටින පරිශීලකයා <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> වෙත මාරු කරමින්…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> වරමින්…"</string>
     <string name="owner_name" msgid="8713560351570795743">"හිමිකරු"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ගැලවීමට පෙර අගුළු අරින රටාව සඳහා අසන්න"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ගැලවීමට පෙර මුරපදය විමසන්න"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"ඔබේ පරිපාලකයා විසින් ස්ථාපන කරනු ලබයි.\nදෙන ලද අවසර බැලීමට සැකසීම් වෙත යන්න"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"ඔබගේ පරිපාලක මඟින් යාවත්කාලීන කර ඇත"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ඔබගේ පරිපාලක මඟින් මකා දමා ඇත"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"හරි"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"බැටරි සුරැකුම අඳුරු තේමාව ක්‍රියාත්මක කර පසුබිම් ක්‍රියාකාරකම්, සමහර දෘශ්‍ය ප්‍රයෝග, යම් විශේෂාංග සහ සමහර ජාල සම්බන්ධතා සීමා හෝ ක්‍රියාවිරහිත කරයි."</string>
diff --git a/core/res/res/values-sk/strings.xml b/core/res/res/values-sk/strings.xml
index 391b0d7..bcbd66f 100644
--- a/core/res/res/values-sk/strings.xml
+++ b/core/res/res/values-sk/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Režim jednej ruky"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Mimoriadne stmavenie"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Načúvacie zariadenia"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatické kliknutie"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Odpojené"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Pripojené"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktívne"</string>
@@ -1827,7 +1826,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Volať handsfree môžete pomocou mikrofónu načúvadla. Týmto iba prepnete mikrofón počas hovoru."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Prepnúť"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Nastavenia"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Aktuálny používateľ je <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Prepína sa na účet <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Prebieha odhlásenie používateľa <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Vlastník"</string>
@@ -1969,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pred uvoľnením požiadať o bezpečnostný vzor"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pred odopnutím požiadať o heslo"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Nainštaloval správca.\nAk si chcete zobraziť udelené povolenia, prejdite do nastavení."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Aktualizoval správca"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Odstránil správca"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Šetrič batérie zapne tmavý motív a obmedzí alebo vypne aktivitu na pozadí, niektoré vizuálne efekty, určité funkcie a niektoré pripojenia k sieti."</string>
diff --git a/core/res/res/values-sl/strings.xml b/core/res/res/values-sl/strings.xml
index c84fd17..c0d18ed 100644
--- a/core/res/res/values-sl/strings.xml
+++ b/core/res/res/values-sl/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enoročni način"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Zelo zatemnjen zaslon"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Slušni pripomočki"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Samodejni klik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Brez povezave"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Povezano"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktivno"</string>
@@ -1827,7 +1826,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Mikrofon za slušni aparat lahko uporabljate za prostoročno klicanje. S tem preklopite mikrofon samo med klicem."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Preklopi"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Nastavitve"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Trenutni uporabnik <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Preklapljanje na uporabnika <xliff:g id="NAME">%1$s</xliff:g> …"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Odjavljanje uporabnika <xliff:g id="NAME">%1$s</xliff:g> …"</string>
     <string name="owner_name" msgid="8713560351570795743">"Lastnik"</string>
@@ -1969,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Pred odpenjanjem vprašaj za vzorec za odklepanje"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Pred odpenjanjem vprašaj za geslo"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Namestil skrbnik.\nV nastavitvah si oglejte odobrena dovoljenja."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Posodobil skrbnik"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Izbrisal skrbnik"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"V redu"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Funkcija varčevanja z energijo baterije vklopi temno temo ter omeji ali izklopi dejavnost v ozadju, nekatere vizualne učinke, določene funkcije in nekatere omrežne povezave."</string>
diff --git a/core/res/res/values-sq/strings.xml b/core/res/res/values-sq/strings.xml
index 25d51a3..ddccede 100644
--- a/core/res/res/values-sq/strings.xml
+++ b/core/res/res/values-sq/strings.xml
@@ -653,18 +653,18 @@
     <string name="permlab_mediaLocation" msgid="7368098373378598066">"lexo vendndodhjet nga koleksioni yt i medias"</string>
     <string name="permdesc_mediaLocation" msgid="597912899423578138">"Lejon aplikacionin të lexojë vendndodhjet nga koleksioni yt i medias."</string>
     <string name="permlab_eye_tracking_coarse" msgid="7989596289790269059">"të gjurmojë vështrimin e përafërt të syve"</string>
-    <string name="permdesc_eye_tracking_coarse" msgid="870510233930553355">"Lejon që aplikacioni të gjurmojë vështrimin e përafërt të syve"</string>
+    <string name="permdesc_eye_tracking_coarse" msgid="870510233930553355">"Lejon që aplikacioni të gjurmojë vështrimin e përafërt të syve."</string>
     <string name="permlab_eye_tracking_fine" msgid="6914457357027049512">"të gjurmojë se ku po shikon ti"</string>
     <string name="permdesc_eye_tracking_fine" msgid="5788889152304524730">"Lejon që aplikacioni të qaset në të dhënat e vështrimit të saktë të syve."</string>
     <string name="permlab_face_tracking" msgid="2272048395128283324">"të gjurmojë fytyrën tënde"</string>
-    <string name="permdesc_face_tracking" msgid="2622783922311211866">"Lejo që aplikacioni të qaset në të dhënat e gjurmimit të fytyrës."</string>
+    <string name="permdesc_face_tracking" msgid="2622783922311211866">"Lejon që aplikacioni të qaset në të dhënat e gjurmimit të fytyrës."</string>
     <string name="permlab_hand_tracking" msgid="6478233866595566940">"të gjurmojë duart e tua"</string>
     <string name="permdesc_hand_tracking" msgid="8639715900104966456">"Lejon që aplikacioni të qaset në të dhënat e gjurmimit të duarve."</string>
     <string name="permlab_head_tracking" msgid="1309731456372087270">"të gjurmojë kokën tënde"</string>
-    <string name="permdesc_head_tracking" msgid="231597390513699188">"Lejo që aplikacioni të qaset në të dhënat e gjurmimit të kokës."</string>
+    <string name="permdesc_head_tracking" msgid="231597390513699188">"Lejon që aplikacioni të qaset në të dhënat e gjurmimit të kokës."</string>
     <string name="permlab_scene_understanding_coarse" msgid="6518646430502858641">"të kuptojë mjedisin tënd"</string>
     <string name="permdesc_scene_understanding_coarse" msgid="4508880777646198656">"Lejon që aplikacioni të qaset në të dhënat e gjurmimit për mjedisin drejtpërdrejt rreth teje."</string>
-    <string name="permlab_scene_understanding_fine" msgid="409126403264393251">"të kuptojë mjedisin tënd të drejtpërdrejtë me nivel të lartë të detajeve"</string>
+    <string name="permlab_scene_understanding_fine" msgid="409126403264393251">"të kuptojë mjedisin drejtpërdrejtë rreth teje me nivel të lartë të detajeve"</string>
     <string name="permdesc_scene_understanding_fine" msgid="6223368011593524179">"Lejon që aplikacioni të qaset në të dhënat e gjurmimit për mjedisin drejtpërdrejt rreth teje me nivel shumë të lartë të detajeve."</string>
     <string name="permlab_xr_tracking_in_background" msgid="7117098718465619023">"të qaset në të dhënat për XR kur nuk është në plan të parë"</string>
     <string name="permdesc_xr_tracking_in_background" msgid="939504041387836853">"Lejon që aplikacioni të qaset në të dhënat për XR kur nuk është në plan të parë."</string>
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Modaliteti i përdorimit me një dorë"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Shumë më i zbehtë"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Pajisjet e dëgjimit"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Klikimi automatik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Shkëputur"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Lidhur"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktive"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Mund ta përdorësh mikrofonin e aparatit të dëgjimit për telefonata pa përdorur duart. Kjo vetëm ndërron mikrofonin gjatë telefonatës."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Ndërro"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Cilësimet"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Emri i përdoruesit aktual: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Po kalon në \"<xliff:g id="NAME">%1$s</xliff:g>\"…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> po del…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Zotëruesi"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Kërko motivin e shkyçjes para heqjes së gozhdimit"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Kërko fjalëkalim para heqjes nga gozhdimi."</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Instaluar nga administratori.\nShko te cilësimet për të shikuar lejet e dhëna"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Përditësuar nga administratori"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Fshirë nga administratori"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Në rregull"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"\"Kursyesi i baterisë\" aktivizon \"Temën e errët\" dhe kufizon ose çaktivizon aktivitetin në sfond, disa efekte vizuale, veçori të caktuara dhe disa lidhje të rrjetit."</string>
diff --git a/core/res/res/values-sr/strings.xml b/core/res/res/values-sr/strings.xml
index 77ceff2..397a394 100644
--- a/core/res/res/values-sr/strings.xml
+++ b/core/res/res/values-sr/strings.xml
@@ -1804,8 +1804,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим једном руком"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Додатно затамни"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слушни апарати"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Аутоматски клик"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Веза је прекинута"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Повезано"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Активно"</string>
@@ -1826,7 +1825,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Можете да користите микрофон слушног апарата за хендсфри позивање. Тиме се микрофон мења само током позива."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Промени"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Подешавања"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Актуелни корисник <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Пребацивање на <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Одјављује се <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Власник"</string>
@@ -1968,7 +1966,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Тражи шаблон за откључавање пре откачињања"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Тражи лозинку пре откачињања"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Инсталирао је администратор.\nИдите у подешавања да бисте видели одобрене дозволе"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Ажурирао је администратор"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Избрисао је администратор"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Потврди"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Уштеда батерије укључује тамну тему и ограничава или искључује активности у позадини, неке визуелне ефекте, одређене функције и неке мрежне везе."</string>
diff --git a/core/res/res/values-sv/strings.xml b/core/res/res/values-sv/strings.xml
index 1ee2564..71062ad 100644
--- a/core/res/res/values-sv/strings.xml
+++ b/core/res/res/values-sv/strings.xml
@@ -661,7 +661,7 @@
     <string name="permlab_hand_tracking" msgid="6478233866595566940">"spåra dina händer"</string>
     <string name="permdesc_hand_tracking" msgid="8639715900104966456">"Tillåter att appen får åtkomst till data om handspårning."</string>
     <string name="permlab_head_tracking" msgid="1309731456372087270">"spåra ditt huvud"</string>
-    <string name="permdesc_head_tracking" msgid="231597390513699188">"Tillåter att appen får åtkomst till data om huvudföljning."</string>
+    <string name="permdesc_head_tracking" msgid="231597390513699188">"Tillåter att appen får åtkomst till data om huvudspårning."</string>
     <string name="permlab_scene_understanding_coarse" msgid="6518646430502858641">"förstå din omgivning"</string>
     <string name="permdesc_scene_understanding_coarse" msgid="4508880777646198656">"Tillåter att appen får åtkomst till spårningsdata om omgivningen runtomkring dig."</string>
     <string name="permlab_scene_understanding_fine" msgid="409126403264393251">"förstå din omgivning i detalj"</string>
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Enhandsläge"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extradimmat"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Hörhjälpmedel"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Automatiskt klick"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Frånkopplad"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ansluten"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktiv"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Du kan använda hörapparatens mikrofon för handsfree-samtal. Detta byter bara mikrofon under samtalet."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Byt"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Inställningar"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Nuvarande användare: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Byter till <xliff:g id="NAME">%1$s</xliff:g> …"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Loggar ut <xliff:g id="NAME">%1$s</xliff:g> …"</string>
     <string name="owner_name" msgid="8713560351570795743">"Ägare"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Be om upplåsningsmönster innan skärmen slutar fästas"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Be om lösenord innan skärmen slutar fästas"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Har installerats av administratören.\nÖppna inställningarna för att se behörigheter som beviljats"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Administratören uppdaterade paketet"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administratören raderade paketet"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"I batterisparläget aktiveras mörkt tema medan bakgrundsaktivitet, vissa visuella effekter och funktioner samt vissa nätverksanslutningar begränsas eller inaktiveras."</string>
diff --git a/core/res/res/values-sw/strings.xml b/core/res/res/values-sw/strings.xml
index 36bf76d..e74ac18 100644
--- a/core/res/res/values-sw/strings.xml
+++ b/core/res/res/values-sw/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Hali ya kutumia kwa mkono mmoja"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Kipunguza mwangaza zaidi"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Vifaa vya kusaidia kusikia"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Kubofya kiotomatiki"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Haijaunganishwa"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Imeunganishwa"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Inatumika"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Unaweza kutumia maikrofoni ya visaidizi vyako vya kusikia ili kupiga simu bila kugusa. Hali hii hubadilisha maikrofoni yako tu wakati unapiga simu."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Badilisha"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Mipangilio"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Mtumiaji wa sasa <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Inaenda kwa <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Inamwondoa <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Mmiliki"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Omba mchoro wa kufungua kabla hujabandua"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Omba nenosiri kabla hujabandua"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Kimewekwa na msimamizi wako.\nNenda kwenye mipangilio ili uone ruhusa zilizotolewa"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Imesasishwa na msimamizi wako"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Imefutwa na msimamizi wako"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Sawa"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Kiokoa Betri huwasha Mandhari meusi na kudhibiti au kuzima shughuli za chinichini, baadhi ya madoido yanayoonekana, vipengele fulani na baadhi ya miunganisho ya mtandao."</string>
diff --git a/core/res/res/values-ta/strings.xml b/core/res/res/values-ta/strings.xml
index 3fa3827..7737d8f 100644
--- a/core/res/res/values-ta/strings.xml
+++ b/core/res/res/values-ta/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ஒற்றைக் கைப் பயன்முறை"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"மிகக் குறைவான வெளிச்சம்"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"செவித்துணைக் கருவிகள்"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ஆட்டோ கிளிக்"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"இணைப்புநீக்கப்பட்டது"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"இணைக்கப்பட்டுள்ளது"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"செயலில் உள்ளது"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"கைகளைப் பயன்படுத்தாமல் அழைக்க உங்கள் செவித்துணைக் கருவியின் மைக்ரோஃபோனைப் பயன்படுத்தலாம். அழைப்பின்போது உங்கள் மைக்கை மட்டுமே இது மாற்றுகிறது."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"மாற்று"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"அமைப்புகள்"</string>
-    <string name="user_switched" msgid="7249833311585228097">"நடப்பு பயனர் <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g>க்கு மாறுகிறது…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> வெளியேறுகிறார்…"</string>
     <string name="owner_name" msgid="8713560351570795743">"உரிமையாளர்"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"அகற்றும் முன் அன்லாக் பேட்டர்னைக் கேள்"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"அகற்றும் முன் கடவுச்சொல்லைக் கேள்"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"உங்கள் நிர்வாகி நிறுவியுள்ளார்.\nவழங்கப்பட்டுள்ள அனுமதிகளை பார்க்க அமைப்புகளுக்குச் செல்லவும்"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"உங்கள் நிர்வாகி புதுப்பித்துள்ளார்"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"உங்கள் நிர்வாகி நீக்கியுள்ளார்"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"சரி"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"பேட்டரி சேமிப்பான் அம்சம் டார்க் தீமை இயக்குவதோடு பின்னணிச் செயல்பாடு, சில விஷுவல் எஃபக்ட்கள், குறிப்பிட்ட அம்சங்கள், சில நெட்வொர்க் இணைப்புகள் ஆகியவற்றைக் கட்டுப்படுத்தும் அல்லது முடக்கும்."</string>
diff --git a/core/res/res/values-te/strings.xml b/core/res/res/values-te/strings.xml
index 027161e..265fb8c 100644
--- a/core/res/res/values-te/strings.xml
+++ b/core/res/res/values-te/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"వన్-హ్యాండెడ్ మోడ్"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"ఎక్స్‌ట్రా డిమ్"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"వినికిడి పరికరాలు"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"ఆటో-క్లిక్"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"డిస్‌కనెక్ట్ అయింది"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"కనెక్ట్ చేయబడింది"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"యాక్టివ్"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"హ్యాండ్స్-ఫ్రీ కాలింగ్ కోసం మీరు మీ వినికిడి పరికరాన్ని ఉపయోగించవచ్చు. ఇది కాల్ సమయంలో మాత్రమే మీ మైక్‌ను మారుస్తుంది."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"మారండి"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"సెట్టింగ్‌లు"</string>
-    <string name="user_switched" msgid="7249833311585228097">"ప్రస్తుత వినియోగదారు <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> యూజర్‌కు స్విచ్ అవుతోంది…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g>ని లాగ్ అవుట్ చేస్తోంది…"</string>
     <string name="owner_name" msgid="8713560351570795743">"ఓనర్"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"అన్‌పిన్ చేయడానికి ముందు అన్‌లాక్ ఆకృతి కోసం అడుగు"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"అన్‌పిన్ చేయడానికి ముందు పాస్‌వర్డ్ కోసం అడుగు"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"మీ అడ్మిన్ ఇన్‌స్టాల్ చేశారు.\nసెట్టింగ్‌లకు వెళ్లి, మంజూరు చేసిన అనుమతులు చూడండి"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"మీ నిర్వాహకులు అప్‌డేట్ చేశారు"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"మీ నిర్వాహకులు తొలగించారు"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"సరే"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"బ్యాటరీ సేవర్ ముదురు రంగు రూపాన్ని ఆన్ చేసి, బ్యాక్‌గ్రౌండ్ యాక్టివిటీ, కొన్ని విజువల్ ఎఫెక్ట్‌లు, నిర్దిష్ట ఫీచర్‌లు, ఇంకా కొన్ని నెట్‌వర్క్ కనెక్షన్‌లను పరిమితం చేస్తుంది లేదా ఆఫ్ చేస్తుంది."</string>
diff --git a/core/res/res/values-th/strings.xml b/core/res/res/values-th/strings.xml
index f82adc6..a922943 100644
--- a/core/res/res/values-th/strings.xml
+++ b/core/res/res/values-th/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"โหมดมือเดียว"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"หรี่แสงเพิ่มเติม"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"เครื่องช่วยฟัง"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"การคลิกอัตโนมัติ"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"เลิกเชื่อมต่อแล้ว"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"เชื่อมต่อแล้ว"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"ใช้งานอยู่"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"คุณใช้ไมโครโฟนของเครื่องช่วยฟังเพื่อโทรแบบแฮนด์ฟรีได้ การดำเนินการนี้เพียงแค่เปลี่ยนไมโครโฟนระหว่างการโทรเท่านั้น"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"เปลี่ยน"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"การตั้งค่า"</string>
-    <string name="user_switched" msgid="7249833311585228097">"ผู้ใช้ปัจจุบัน <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"กำลังเปลี่ยนเป็น<xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"กำลังออกจากระบบ <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"เจ้าของ"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"ขอรูปแบบการปลดล็อกก่อนเลิกปักหมุด"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"ขอรหัสผ่านก่อนเลิกปักหมุด"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"ติดตั้งโดยผู้ดูแลระบบของคุณ\nไปที่การตั้งค่าเพื่อดูสิทธิ์ที่ได้รับอนุญาต"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"อัปเดตโดยผู้ดูแลระบบ"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"ลบโดยผู้ดูแลระบบ"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ตกลง"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"โหมดประหยัดแบตเตอรี่จะเปิดธีมมืดและจำกัดหรือปิดกิจกรรมในเบื้องหลัง เอฟเฟกต์ภาพบางอย่าง ฟีเจอร์บางส่วน และการเชื่อมต่อบางเครือข่าย"</string>
@@ -2281,7 +2280,7 @@
     <string name="conversation_title_fallback_one_to_one" msgid="1980753619726908614">"การสนทนา"</string>
     <string name="conversation_title_fallback_group_chat" msgid="456073374993104303">"บทสนทนากลุ่ม"</string>
     <string name="unread_convo_overflow" msgid="920517615597353833">"<xliff:g id="MAX_UNREAD_COUNT">%1$d</xliff:g>+"</string>
-    <string name="resolver_personal_tab" msgid="2051260504014442073">"ส่วนบุคคล"</string>
+    <string name="resolver_personal_tab" msgid="2051260504014442073">"ส่วนตัว"</string>
     <string name="resolver_work_tab" msgid="2690019516263167035">"งาน"</string>
     <string name="resolver_personal_tab_accessibility" msgid="5739524949153091224">"มุมมองส่วนตัว"</string>
     <string name="resolver_work_tab_accessibility" msgid="4753168230363802734">"ดูงาน"</string>
diff --git a/core/res/res/values-tl/strings.xml b/core/res/res/values-tl/strings.xml
index 328997d..5e3e1e8 100644
--- a/core/res/res/values-tl/strings.xml
+++ b/core/res/res/values-tl/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"One-Hand mode"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Extra dim"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Mga hearing device"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Autoclick"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Nadiskonekta"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Nakakonekta"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Aktibo"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Puwede mong gamitin ang mikropono ng iyong hearing aid para sa hands-free na pagtawag. Inililipat lang nito ang iyong mikropono habang nasa tawag ka."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Lumipat"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Mga Setting"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Kasalukuyang user <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Lumilipat kay <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Nila-log out si <xliff:g id="NAME">%1$s</xliff:g>..."</string>
     <string name="owner_name" msgid="8713560351570795743">"May-ari"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Humingi ng pattern sa pag-unlock bago mag-unpin"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Humingi ng password bago mag-unpin"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Na-install ng iyong admin.\nPumunta sa mga setting para makita ang mga ibinigay na pahintulot"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Na-update ng iyong admin"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Na-delete ng iyong admin"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Ino-on ng Pantipid ng Baterya ang Madilim na tema at nililimitahan o ino-off nito ang aktibidad sa background, ilang visual effect, ilang partikular na feature, at ilang koneksyon sa network."</string>
diff --git a/core/res/res/values-tr/strings.xml b/core/res/res/values-tr/strings.xml
index 5106e1a..72d62d5 100644
--- a/core/res/res/values-tr/strings.xml
+++ b/core/res/res/values-tr/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Tek El modu"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ekstra loş"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"İşitme cihazları"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Otomatik tıklama"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Bağlı değil"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Bağlı"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Etkin"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Eller serbest modunda arama yapmak için işitme cihazı mikrofonunu kullanabilirsiniz. Bu işlem yalnızca görüşme sırasında mikrofonunuzu değiştirir."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Geçiş yap"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Ayarlar"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Geçerli kullanıcı: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"<xliff:g id="NAME">%1$s</xliff:g> adlı kullanıcıya geçiliyor…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> hesabından çıkış yapılıyor…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Sahip"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Sabitlemeyi kaldırmadan önce kilit açma desenini sor"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Sabitlemeyi kaldırmadan önce şifre sor"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Yöneticiniz tarafından yüklendi.\nVerilen izinleri görüntülemek için ayarlara gidin"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Yöneticiniz tarafından güncellendi"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Yöneticiniz tarafından silindi"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"Tamam"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Pil Tasarrufu, Koyu temayı açıp arka plan etkinliğini, bazı görsel efektleri, belirli özellikleri ve bazı ağ bağlantılarını sınırlandırır veya kapatır."</string>
diff --git a/core/res/res/values-uk/strings.xml b/core/res/res/values-uk/strings.xml
index 203cdfa..e4e1e99 100644
--- a/core/res/res/values-uk/strings.xml
+++ b/core/res/res/values-uk/strings.xml
@@ -1805,8 +1805,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Режим керування однією рукою"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Додаткове зменшення яскравості"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Слухові апарати"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Автоматичне натискання"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Від’єднано"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Під’єднано"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Активний"</string>
@@ -1827,7 +1826,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Ви можете використовувати мікрофон слухового апарата для голосового керування викликами. Мікрофон перемикатиметься лише на час дзвінка."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Перемкнути"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Налаштування"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Поточний користувач: <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Перехід в обліковий запис \"<xliff:g id="NAME">%1$s</xliff:g>\"…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Вихід з облікового запису користувача <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Власник"</string>
@@ -1969,7 +1967,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Запитувати ключ розблокування перед відкріпленням"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Запитувати пароль перед відкріпленням"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Установлено адміністратором.\nПерейдіть у налаштування, щоб переглянути надані дозволи."</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Оновлено адміністратором"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Видалено адміністратором"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ОК"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"У режимі енергозбереження вмикається темна тема й обмежуються чи вимикаються дії у фоновому режимі, а також деякі візуальні ефекти, функції та з’єднання з мережами."</string>
diff --git a/core/res/res/values-ur/strings.xml b/core/res/res/values-ur/strings.xml
index 376efd1..a98179a 100644
--- a/core/res/res/values-ur/strings.xml
+++ b/core/res/res/values-ur/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"ایک ہاتھ کی وضع"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"اضافی مدھم"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"سماعتی آلات"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"خودکار کلک"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"غیر منسلک ہے"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"منسلک ہے"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"فعال"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"آپ ہینڈز فری کالنگ کے لیے اپنا سماعتی آلہ مائیکروفون استعمال کر سکتے ہیں۔ یہ صرف کال کے دوران آپ کا مائیک سوئچ کرتا ہے۔"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"سوئچ کریں"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"ترتیبات"</string>
-    <string name="user_switched" msgid="7249833311585228097">"موجودہ صارف <xliff:g id="NAME">%1$s</xliff:g>۔"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"‫<xliff:g id="NAME">%1$s</xliff:g> پر سوئچ کیا جا رہا ہے…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> لاگ آؤٹ ہو رہا ہے…"</string>
     <string name="owner_name" msgid="8713560351570795743">"مالک"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"پن ہٹانے سے پہلے غیر مقفل کرنے کا پیٹرن طلب کریں"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"پن ہٹانے سے پہلے پاس ورڈ طلب کریں"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"آپ کے منتظم نے انسٹال کیا ہے۔\nدی گئی اجازتیں دیکھنے کیلئے ترتیبات پر جائیں"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"آپ کے منتظم کے ذریعے اپ ڈیٹ کیا گیا"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"آپ کے منتظم کے ذریعے حذف کیا گیا"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"ٹھیک ہے"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"بیٹری سیور گہری تھیم کو آن کرتی ہے اور پس منظر کی سرگرمی، کچھ بصری اثرات، مخصوص خصوصیات اور کچھ نیٹ ورک کنکشنز کو محدود یا آف کرتی ہے۔"</string>
diff --git a/core/res/res/values-uz/strings.xml b/core/res/res/values-uz/strings.xml
index a1b9e5d..81ebe5f 100644
--- a/core/res/res/values-uz/strings.xml
+++ b/core/res/res/values-uz/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Ixcham rejim"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Juda xira"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Eshitish qurilmalari"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Avtoklik"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Uzildi"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ulandi"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Faol"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Garniturali chaqiruv uchun eshitish moslamasi mikrofonidan foydalanish mumkin. Bu faqat chaqiruv paytida mikrofonni almashtiradi."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Almashtirish"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Sozlamalar"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Joriy foydalanuvchi <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Bunga almashilmoqda: <xliff:g id="NAME">%1$s</xliff:g>"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"<xliff:g id="NAME">%1$s</xliff:g> hisobidan chiqilmoqda…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Egasi"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Yechishdan oldin grafik kalit so‘ralsin"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Bo‘shatishdan oldin parol so‘ralsin"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Administrator oʻrnatgan.\nBerilgan ruxsatlarni koʻrish uchun sozlamalarni oching"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Administrator tomonidan yangilangan"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Administrator tomonidan o‘chirilgan"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Quvvat tejash funksiyasi Tungi mavzuni va cheklovlarni yoqadi hamda fondagi harakatlar, vizual effektlar, ayrim funksiyalar va tarmoq aloqalari kabi boshqa funksiyalarni faolsizlantiradi yoki cheklaydi."</string>
diff --git a/core/res/res/values-vi/strings.xml b/core/res/res/values-vi/strings.xml
index 473568d..4dda8cc 100644
--- a/core/res/res/values-vi/strings.xml
+++ b/core/res/res/values-vi/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Chế độ một tay"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Siêu tối"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Thiết bị trợ thính"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Tự động nhấp"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Đã ngắt kết nối"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Đã kết nối"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Đang hoạt động"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Bạn có thể sử dụng micrô của thiết bị trợ thính để gọi điện mà không cần dùng tay. Thao tác này chỉ chuyển micrô của bạn trong cuộc gọi."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Chuyển"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Cài đặt"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Người dùng hiện tại <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Đang chuyển sang <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Đang đăng xuất <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Chủ sở hữu"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Hỏi hình mở khóa trước khi bỏ ghim"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Hỏi mật khẩu trước khi bỏ ghim"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Do quản trị viên của bạn cài đặt.\nChuyển đến phần cài đặt để xem các quyền được cấp"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Do quản trị viên của bạn cập nhật"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Do quản trị viên của bạn xóa"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"OK"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Trình tiết kiệm pin sẽ bật Giao diện tối, đồng thời hạn chế hoặc tắt hoạt động chạy trong nền, một số hiệu ứng hình ảnh, các tính năng nhất định và một số đường kết nối mạng."</string>
diff --git a/core/res/res/values-zh-rCN/strings.xml b/core/res/res/values-zh-rCN/strings.xml
index f91f457..851195a 100644
--- a/core/res/res/values-zh-rCN/strings.xml
+++ b/core/res/res/values-zh-rCN/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"单手模式"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"极暗"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"助听装置"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"自动点击"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"已断开连接"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"已连接"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"活跃"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"您可以使用助听器麦克风进行免提通话。此操作只会切换通话期间的麦克风。"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"切换"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"设置"</string>
-    <string name="user_switched" msgid="7249833311585228097">"当前用户是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"正在切换为<xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"正在将<xliff:g id="NAME">%1$s</xliff:g>退出账号…"</string>
     <string name="owner_name" msgid="8713560351570795743">"机主"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"取消固定前要求绘制解锁图案"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"取消时要求输入密码"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"由您的管理员安装。\n前往设置可查看已授予的权限"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"已由您的管理员更新"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"已由您的管理员删除"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"确定"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"在省电模式下,系统会启用深色主题,并限制或关闭后台活动、某些视觉效果、特定功能和部分网络连接。"</string>
diff --git a/core/res/res/values-zh-rHK/strings.xml b/core/res/res/values-zh-rHK/strings.xml
index 9bcb173..87b403d 100644
--- a/core/res/res/values-zh-rHK/strings.xml
+++ b/core/res/res/values-zh-rHK/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"單手模式"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"超暗"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"助聽器"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"自動點擊"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"已中斷連線"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"已連線"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"運作中"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"你可使用助聽器麥克風進行免提通話。此操作只會切換通話期間的麥克風。"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"切換"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"設定"</string>
-    <string name="user_switched" msgid="7249833311585228097">"目前的使用者是<xliff:g id="NAME">%1$s</xliff:g>。"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"正在切換至<xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"正在登出 <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"擁有者"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"取消固定時必須提供解鎖圖案"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"取消固定時必須輸入密碼"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"已由你的管理員安裝。\n請前往設定查看已授予的權限"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"已由你的管理員更新"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"已由你的管理員刪除"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"好"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"「慳電模式」會開啟深色主題背景,並限制或關閉背景活動、部分視覺效果、特定功能和部分網絡連線。"</string>
diff --git a/core/res/res/values-zh-rTW/strings.xml b/core/res/res/values-zh-rTW/strings.xml
index 9f8fd67..72d2e7c 100644
--- a/core/res/res/values-zh-rTW/strings.xml
+++ b/core/res/res/values-zh-rTW/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"單手模式"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"超暗"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"助聽器"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"自動點選"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"連線中斷"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"已連線"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"運作中"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"免持通話時,可以使用助聽器麥克風。麥克風只會在通話期間切換。"</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"切換"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"設定"</string>
-    <string name="user_switched" msgid="7249833311585228097">"目前的使用者是 <xliff:g id="NAME">%1$s</xliff:g>。"</string>
     <string name="user_switching_message" msgid="1912993630661332336">"正在切換至<xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"正在將<xliff:g id="NAME">%1$s</xliff:g>登出帳戶…"</string>
     <string name="owner_name" msgid="8713560351570795743">"擁有者"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"取消固定時必須畫出解鎖圖案"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"取消固定時必須輸入密碼"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"這是管理員安裝的套件。\n你可以前往設定查看授予的權限"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"已由你的管理員更新"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"已由你的管理員刪除"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"確定"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"省電模式會開啟深色主題,並限制或關閉背景活動、某些視覺效果、特定功能和部分網路連線。"</string>
diff --git a/core/res/res/values-zu/strings.xml b/core/res/res/values-zu/strings.xml
index a0df4a1..13356cb 100644
--- a/core/res/res/values-zu/strings.xml
+++ b/core/res/res/values-zu/strings.xml
@@ -1803,8 +1803,7 @@
     <string name="one_handed_mode_feature_name" msgid="2334330034828094891">"Imodi yesandla esisodwa"</string>
     <string name="reduce_bright_colors_feature_name" msgid="3222994553174604132">"Ukufiphaza okwengeziwe"</string>
     <string name="hearing_aids_feature_name" msgid="1125892105105852542">"Amadivayizi okuzwa"</string>
-    <!-- no translation found for autoclick_feature_name (8149248738736949630) -->
-    <skip />
+    <string name="autoclick_feature_name" msgid="8149248738736949630">"Chofoza ngokuzenzekelayo"</string>
     <string name="hearing_device_status_disconnected" msgid="497547752953543832">"Inqamukile"</string>
     <string name="hearing_device_status_connected" msgid="2149385149669918764">"Ixhunyiwe"</string>
     <string name="hearing_device_status_active" msgid="4770378695482566032">"Kuyasebenza"</string>
@@ -1825,7 +1824,6 @@
     <string name="hearing_device_switch_hearing_mic_notification_text" msgid="8288368365767284208">"Ungasebenzisa imakrofoni yakho yomshini wendlebe ekufoneni ngehands-free. Lokhu kushintsha kuphela imakrofoni yakho ngesikhathi sekholi."</string>
     <string name="hearing_device_notification_switch_button" msgid="3619524619430941300">"Shintsha"</string>
     <string name="hearing_device_notification_settings_button" msgid="6673651052880279178">"Amasethingi"</string>
-    <string name="user_switched" msgid="7249833311585228097">"Umsebenzisi wamanje <xliff:g id="NAME">%1$s</xliff:g>."</string>
     <string name="user_switching_message" msgid="1912993630661332336">"Ishintshela ku-<xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="user_logging_out_message" msgid="7216437629179710359">"Iyaphuma <xliff:g id="NAME">%1$s</xliff:g>…"</string>
     <string name="owner_name" msgid="8713560351570795743">"Umnikazi"</string>
@@ -1967,7 +1965,8 @@
     <string name="lock_to_app_unlock_pattern" msgid="2694204070499712503">"Cela iphethini yokuvula ngaphambi kokususa ukuphina"</string>
     <string name="lock_to_app_unlock_password" msgid="9126722403506560473">"Cela iphasiwedi ngaphambi kokususa ukuphina"</string>
     <string name="package_installed_device_owner" msgid="8684974629306529138">"Kufakwe ngumphathi wakho.\nIya kumasethingi ukuze ubuke izimvume ezinikeziwe"</string>
-    <string name="package_updated_device_owner" msgid="7560272363805506941">"Kubuyekezwe umlawuli wakho"</string>
+    <!-- no translation found for package_updated_device_owner (7770195449213776218) -->
+    <skip />
     <string name="package_deleted_device_owner" msgid="2292335928930293023">"Kususwe umlawuli wakho"</string>
     <string name="confirm_battery_saver" msgid="5247976246208245754">"KULUNGILE"</string>
     <string name="battery_saver_description_with_learn_more" msgid="5444908404021316250">"Isilondolozi Sebhethri sivula ingqikithi emnyama futhi sibeke umkhawulo noma sivale umsebenzi ongemuva, imiphumela ethile yokubuka, izici ezithile, nokuxhumeka okuthile kwenethiwekhi."</string>
diff --git a/core/res/res/values/colors.xml b/core/res/res/values/colors.xml
index 4e93c44..bf1423b 100644
--- a/core/res/res/values/colors.xml
+++ b/core/res/res/values/colors.xml
@@ -557,6 +557,7 @@
     <color name="accessibility_magnification_background">#F50D60</color>
     <color name="accessibility_daltonizer_background">#00BCD4</color>
     <color name="accessibility_color_inversion_background">#546E7A</color>
+    <color name="accessibility_autoclick_background">#67D4FF</color>
 
     <!-- Fullscreen magnification thumbnail color -->
     <color name="accessibility_magnification_thumbnail_stroke_color">#0C0C0C</color>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 1cb38be..9773f55 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3072,6 +3072,43 @@
          {@link MotionEvent#ACTION_SCROLL} event. -->
     <dimen name="config_scrollFactor">64dp</dimen>
 
+    <!-- Duration in milliseconds of the pressed state in child components. -->
+    <integer name="config_pressedStateDurationMillis">64</integer>
+
+    <!-- Duration in milliseconds we will wait to see if a touch event is a tap or a scroll.
+         If the user does not move within this interval, it is considered to be a tap. -->
+    <integer name="config_tapTimeoutMillis">100</integer>
+
+    <!-- Duration in milliseconds we will wait to see if a touch event is a jump tap.
+         If the user does not move within this interval, it is considered to be a tap. -->
+    <integer name="config_jumpTapTimeoutMillis">500</integer>
+
+    <!-- Duration in milliseconds between the first tap's up event and the second tap's down
+         event for an interaction to be considered a double-tap. -->
+    <integer name="config_doubleTapTimeoutMillis">300</integer>
+
+    <!-- Minimum duration in milliseconds between the first tap's up event and the second tap's
+         down event for an interaction to be considered a double-tap. -->
+    <integer name="config_doubleTapMinTimeMillis">40</integer>
+
+    <!-- Maximum duration in milliseconds between a touch pad touch and release for a given touch
+         to be considered a tap (click) as opposed to a hover movement gesture. -->
+    <integer name="config_hoverTapTimeoutMillis">150</integer>
+
+    <!-- The amount of time in milliseconds that the zoom controls should be displayed on the
+         screen. -->
+    <integer name="config_zoomControlsTimeoutMillis">3000</integer>
+
+    <!-- Default duration in milliseconds for {@link ActionMode#hide(long)}. -->
+    <integer name="config_defaultActionModeHideDurationMillis">2000</integer>
+
+    <!-- Maximum distance in pixels that a touch pad touch can move before being released
+         for it to be considered a tap (click) as opposed to a hover movement gesture. -->
+    <dimen name="config_hoverTapSlop">20px</dimen>
+
+    <!-- The amount of friction applied to scrolls and flings. -->
+    <item name="config_scrollFriction" format="float" type="dimen">0.015</item>
+
     <!-- Maximum number of grid columns permitted in the ResolverActivity
          used for picking activities to handle an intent. -->
     <integer name="config_maxResolverActivityColumns">3</integer>
@@ -4422,6 +4459,10 @@
          etc. dialogs. -->
     <string translatable="false" name="config_appsNotReportingCrashes"></string>
 
+    <!-- Specifies the delay in milliseconds for JobScheduler to postpone the running
+         of regular jobs when coming out of doze -->
+    <integer name="config_jobSchedulerBackgroundJobsDelay">3000</integer>
+
     <!-- Inactivity threshold (in milliseconds) used in JobScheduler. JobScheduler will consider
          the device to be "idle" after being inactive for this long. -->
     <integer name="config_jobSchedulerInactivityIdleThreshold">1860000</integer>
diff --git a/core/res/res/values/config_telephony.xml b/core/res/res/values/config_telephony.xml
index 59ed25a..ef6b918 100644
--- a/core/res/res/values/config_telephony.xml
+++ b/core/res/res/values/config_telephony.xml
@@ -80,11 +80,6 @@
     <bool name="auto_data_switch_ping_test_before_switch">true</bool>
     <java-symbol type="bool" name="auto_data_switch_ping_test_before_switch" />
 
-    <!-- TODO: remove after V -->
-    <!-- Boolean indicating whether allow to use a roaming nonDDS if user enabled its roaming. -->
-    <bool name="auto_data_switch_allow_roaming">true</bool>
-    <java-symbol type="bool" name="auto_data_switch_allow_roaming" />
-
     <!-- Define the tolerated gap of score for auto data switch decision, larger than which the
          device will switch to the SIM with higher score. The score is used in conjunction with the
          score table defined in
@@ -524,4 +519,9 @@
          capabilities. -->
     <string-array name="config_unsupported_network_capabilities" translatable="false"></string-array>
     <java-symbol type="array" name="config_unsupported_network_capabilities" />
+
+    <!-- Whether to enable APDU sender optimization i.e. a logical channel is opened and
+         kept open for multiple APDU commands within one session.-->
+    <bool name="euicc_optimize_apdu_sender">false</bool>
+    <java-symbol type="bool" name="euicc_optimize_apdu_sender" />
 </resources>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index cb3dfc7..b3cc883 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -5412,7 +5412,7 @@
     <!-- Notification shown when device owner silently installs a package [CHAR LIMIT=NONE] -->
     <string name="package_installed_device_owner">Installed by your admin.\nGo to settings to view granted permissions</string>
     <!-- Notification shown when device owner silently updates a package [CHAR LIMIT=NONE] -->
-    <string name="package_updated_device_owner">Updated by your admin</string>
+    <string name="package_updated_device_owner">Updated by your admin.\nGo to settings to view granted permissions</string>
     <!-- Notification shown when device owner silently deletes a package [CHAR LIMIT=NONE] -->
     <string name="package_deleted_device_owner">Deleted by your admin</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c8c1e73..2b7261b 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -3016,6 +3016,7 @@
 
   <java-symbol type="integer" name="config_defaultNightMode" />
 
+  <java-symbol type="integer" name="config_jobSchedulerBackgroundJobsDelay" />
   <java-symbol type="integer" name="config_jobSchedulerInactivityIdleThreshold" />
   <java-symbol type="integer" name="config_jobSchedulerInactivityIdleThresholdOnStablePower" />
   <java-symbol type="integer" name="config_jobSchedulerIdleWindowSlop" />
@@ -4159,6 +4160,17 @@
   <java-symbol type="string" name="config_headlineFontFamily" />
   <java-symbol type="string" name="config_headlineFontFamilyMedium" />
 
+  <java-symbol type="integer" name="config_pressedStateDurationMillis" />
+  <java-symbol type="integer" name="config_tapTimeoutMillis" />
+  <java-symbol type="integer" name="config_jumpTapTimeoutMillis" />
+  <java-symbol type="integer" name="config_doubleTapTimeoutMillis" />
+  <java-symbol type="integer" name="config_doubleTapMinTimeMillis" />
+  <java-symbol type="integer" name="config_hoverTapTimeoutMillis" />
+  <java-symbol type="integer" name="config_zoomControlsTimeoutMillis" />
+  <java-symbol type="integer" name="config_defaultActionModeHideDurationMillis" />
+  <java-symbol type="dimen" name="config_hoverTapSlop" />
+  <java-symbol type="dimen" name="config_scrollFriction" />
+
   <java-symbol type="drawable" name="stat_sys_vitals" />
 
   <java-symbol type="color" name="text_color_primary" />
@@ -5652,6 +5664,7 @@
   <java-symbol type="id" name="accessibility_autoclick_position_button" />
   <java-symbol type="drawable" name="accessibility_autoclick_pause" />
   <java-symbol type="drawable" name="accessibility_autoclick_resume" />
+  <java-symbol type="drawable" name="ic_accessibility_autoclick" />
 
   <!-- For HapticFeedbackConstants configurability defined at HapticFeedbackCustomization -->
   <java-symbol type="string" name="config_hapticFeedbackCustomizationFile" />
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index f89e441..157c74a 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -371,16 +371,6 @@
 
     @Test
     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
-    public void testHasPromotableStyle_bigPicture() {
-        Notification n = new Notification.Builder(mContext, "test")
-                .setSmallIcon(android.R.drawable.sym_def_app_icon)
-                .setStyle(new Notification.BigPictureStyle())
-                .build();
-        assertThat(n.hasPromotableStyle()).isTrue();
-    }
-
-    @Test
-    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
     public void testHasPromotableStyle_bigText() {
         Notification n = new Notification.Builder(mContext, "test")
                 .setSmallIcon(android.R.drawable.sym_def_app_icon)
@@ -391,6 +381,16 @@
 
     @Test
     @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
+    public void testHasPromotableStyle_no_bigPictureStyle() {
+        Notification n = new Notification.Builder(mContext, "test")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setStyle(new Notification.BigPictureStyle())
+                .build();
+        assertThat(n.hasPromotableStyle()).isFalse();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_UI_RICH_ONGOING)
     public void testHasPromotableStyle_no_messagingStyle() {
         Notification.MessagingStyle style = new Notification.MessagingStyle("self name")
                 .setGroupConversation(true)
diff --git a/core/tests/coretests/src/com/android/internal/os/DebugStoreTest.java b/core/tests/coretests/src/com/android/internal/os/DebugStoreTest.java
index 786c2fc..bc452e7 100644
--- a/core/tests/coretests/src/com/android/internal/os/DebugStoreTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/DebugStoreTest.java
@@ -47,21 +47,17 @@
 /**
  * Test class for {@link DebugStore}.
  *
- * To run it:
- * atest FrameworksCoreTests:com.android.internal.os.DebugStoreTest
+ * <p>To run it: atest FrameworksCoreTests:com.android.internal.os.DebugStoreTest
  */
 @RunWith(AndroidJUnit4.class)
 @DisabledOnRavenwood(blockedBy = DebugStore.class)
 @SmallTest
 public class DebugStoreTest {
-    @Rule
-    public final RavenwoodRule mRavenwood = new RavenwoodRule();
+    @Rule public final RavenwoodRule mRavenwood = new RavenwoodRule();
 
-    @Mock
-    private DebugStore.DebugStoreNative mDebugStoreNativeMock;
+    @Mock private DebugStore.DebugStoreNative mDebugStoreNativeMock;
 
-    @Captor
-    private ArgumentCaptor<List<String>> mListCaptor;
+    @Captor private ArgumentCaptor<List<String>> mListCaptor;
 
     @Before
     public void setUp() {
@@ -79,16 +75,14 @@
         when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(1L);
 
         long eventId = DebugStore.recordServiceOnStart(1, 0, intent);
-
-        verify(mDebugStoreNativeMock).beginEvent(eq("SvcStart"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "stId", "1",
-                "flg", "0",
-                "act", "com.android.ACTION",
-                "comp", "ComponentInfo{com.android/androidService}",
-                "pkg", "com.android"
-        ).inOrder();
+        assertThat(paramsForBeginEvent("SvcStart"))
+                .containsExactly(
+                        "stId", "1",
+                        "flg", "0",
+                        "act", "com.android.ACTION",
+                        "comp", "ComponentInfo{com.android/androidService}",
+                        "pkg", "com.android")
+                .inOrder();
         assertThat(eventId).isEqualTo(1L);
     }
 
@@ -101,13 +95,11 @@
         when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(2L);
 
         long eventId = DebugStore.recordServiceCreate(serviceInfo);
-
-        verify(mDebugStoreNativeMock).beginEvent(eq("SvcCreate"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "name", "androidService",
-                "pkg", "com.android"
-        ).inOrder();
+        assertThat(paramsForBeginEvent("SvcCreate"))
+                .containsExactly(
+                        "name", "androidService",
+                        "pkg", "com.android")
+                .inOrder();
         assertThat(eventId).isEqualTo(2L);
     }
 
@@ -121,59 +113,60 @@
         when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(3L);
 
         long eventId = DebugStore.recordServiceBind(true, intent);
-
-        verify(mDebugStoreNativeMock).beginEvent(eq("SvcBind"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "rebind", "true",
-                "act", "com.android.ACTION",
-                "cmp", "ComponentInfo{com.android/androidService}",
-                "pkg", "com.android"
-        ).inOrder();
+        assertThat(paramsForBeginEvent("SvcBind"))
+                .containsExactly(
+                        "rebind", "true",
+                        "act", "com.android.ACTION",
+                        "cmp", "ComponentInfo{com.android/androidService}",
+                        "pkg", "com.android")
+                .inOrder();
         assertThat(eventId).isEqualTo(3L);
     }
 
     @Test
     public void testRecordGoAsync() {
-        DebugStore.recordGoAsync("androidReceiver");
+        DebugStore.recordGoAsync(3840 /* 0xf00 */);
 
-        verify(mDebugStoreNativeMock).recordEvent(eq("GoAsync"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "tname", Thread.currentThread().getName(),
-                "tid", String.valueOf(Thread.currentThread().getId()),
-                "rcv", "androidReceiver"
-        ).inOrder();
+        assertThat(paramsForRecordEvent("GoAsync"))
+                .containsExactly(
+                        "tname",
+                        Thread.currentThread().getName(),
+                        "tid",
+                        String.valueOf(Thread.currentThread().getId()),
+                        "prid",
+                        "f00")
+                .inOrder();
     }
 
     @Test
     public void testRecordFinish() {
-        DebugStore.recordFinish("androidReceiver");
+        DebugStore.recordFinish(3840 /* 0xf00 */);
 
-        verify(mDebugStoreNativeMock).recordEvent(eq("Finish"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "tname", Thread.currentThread().getName(),
-                "tid", String.valueOf(Thread.currentThread().getId()),
-                "rcv", "androidReceiver"
-        ).inOrder();
+        assertThat(paramsForRecordEvent("Finish"))
+                .containsExactly(
+                        "tname",
+                        Thread.currentThread().getName(),
+                        "tid",
+                        String.valueOf(Thread.currentThread().getId()),
+                        "prid",
+                        "f00")
+                .inOrder();
     }
 
     @Test
     public void testRecordLongLooperMessage() {
         DebugStore.recordLongLooperMessage(100, "androidHandler", 500L);
 
-        verify(mDebugStoreNativeMock).recordEvent(eq("LooperMsg"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "code", "100",
-                "trgt", "androidHandler",
-                "elapsed", "500"
-        ).inOrder();
+        assertThat(paramsForRecordEvent("LooperMsg"))
+                .containsExactly(
+                        "code", "100",
+                        "trgt", "androidHandler",
+                        "elapsed", "500")
+                .inOrder();
     }
 
     @Test
-    public void testRecordBroadcastHandleReceiver() {
+    public void testRecordBroadcastReceive() {
         Intent intent = new Intent();
         intent.setAction("com.android.ACTION");
         intent.setComponent(new ComponentName("com.android", "androidReceiver"));
@@ -181,21 +174,87 @@
 
         when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(4L);
 
-        long eventId = DebugStore.recordBroadcastHandleReceiver(intent);
-
-        verify(mDebugStoreNativeMock).beginEvent(eq("HandleReceiver"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "tname", Thread.currentThread().getName(),
-                "tid", String.valueOf(Thread.currentThread().getId()),
-                "act", "com.android.ACTION",
-                "cmp", "ComponentInfo{com.android/androidReceiver}",
-                "pkg", "com.android"
-        ).inOrder();
+        long eventId = DebugStore.recordBroadcastReceive(intent, 3840 /* 0xf00 */);
+        assertThat(paramsForBeginEvent("BcRcv"))
+                .containsExactly(
+                        "tname", Thread.currentThread().getName(),
+                        "tid", String.valueOf(Thread.currentThread().getId()),
+                        "act", "com.android.ACTION",
+                        "cmp", "ComponentInfo{com.android/androidReceiver}",
+                        "pkg", "com.android",
+                        "prid", "f00")
+                .inOrder();
         assertThat(eventId).isEqualTo(4L);
     }
 
     @Test
+    public void testRecordBroadcastReceiveReg() {
+        Intent intent = new Intent();
+        intent.setAction("com.android.ACTION");
+        intent.setComponent(new ComponentName("com.android", "androidReceiver"));
+        intent.setPackage("com.android");
+
+        when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(5L);
+
+        long eventId = DebugStore.recordBroadcastReceiveReg(intent, 3840 /* 0xf00 */);
+        assertThat(paramsForBeginEvent("BcRcvReg"))
+                .containsExactly(
+                        "tname",
+                        Thread.currentThread().getName(),
+                        "tid",
+                        String.valueOf(Thread.currentThread().getId()),
+                        "act",
+                        "com.android.ACTION",
+                        "cmp",
+                        "ComponentInfo{com.android/androidReceiver}",
+                        "pkg",
+                        "com.android",
+                        "prid",
+                        "f00")
+                .inOrder();
+        assertThat(eventId).isEqualTo(5L);
+    }
+
+    @Test
+    public void testRecordHandleBindApplication() {
+        when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(6L);
+        long eventId = DebugStore.recordHandleBindApplication();
+
+        assertThat(paramsForBeginEvent("BindApp")).isEmpty();
+        assertThat(eventId).isEqualTo(6L);
+    }
+
+      @Test
+    public void testRecordScheduleReceiver() {
+        when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(7L);
+        long eventId = DebugStore.recordScheduleReceiver();
+
+        assertThat(paramsForBeginEvent("SchRcv"))
+                .containsExactly(
+                        "tname",
+                        Thread.currentThread().getName(),
+                        "tid",
+                        String.valueOf(Thread.currentThread().getId()))
+                .inOrder();
+        assertThat(eventId).isEqualTo(7L);
+    }
+
+        @Test
+    public void testRecordScheduleRegisteredReceiver() {
+        when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(8L);
+        long eventId = DebugStore.recordScheduleRegisteredReceiver();
+
+        assertThat(paramsForBeginEvent("SchRcvReg"))
+                .containsExactly(
+                        "tname",
+                        Thread.currentThread().getName(),
+                        "tid",
+                        String.valueOf(Thread.currentThread().getId()))
+                .inOrder();
+        assertThat(eventId).isEqualTo(8L);
+    }
+
+    @Test
     public void testRecordEventEnd() {
         DebugStore.recordEventEnd(1L);
 
@@ -203,109 +262,124 @@
     }
 
     @Test
-    public void testRecordServiceOnStartWithNullIntent() {
+    public void testRecordServiceOnStart_withNullIntent() {
         when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(5L);
 
         long eventId = DebugStore.recordServiceOnStart(1, 0, null);
-
-        verify(mDebugStoreNativeMock).beginEvent(eq("SvcStart"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "stId", "1",
-                "flg", "0",
-                "act", "null",
-                "comp", "null",
-                "pkg", "null"
-        ).inOrder();
+        assertThat(paramsForBeginEvent("SvcStart"))
+                .containsExactly(
+                        "stId", "1",
+                        "flg", "0",
+                        "act", "null",
+                        "comp", "null",
+                        "pkg", "null")
+                .inOrder();
         assertThat(eventId).isEqualTo(5L);
     }
 
     @Test
-    public void testRecordServiceCreateWithNullServiceInfo() {
+    public void testRecordServiceCreate_withNullServiceInfo() {
         when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(6L);
 
         long eventId = DebugStore.recordServiceCreate(null);
-
-        verify(mDebugStoreNativeMock).beginEvent(eq("SvcCreate"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "name", "null",
-                "pkg", "null"
-        ).inOrder();
+        assertThat(paramsForBeginEvent("SvcCreate"))
+                .containsExactly(
+                        "name", "null",
+                        "pkg", "null")
+                .inOrder();
         assertThat(eventId).isEqualTo(6L);
     }
 
     @Test
-    public void testRecordServiceBindWithNullIntent() {
+    public void testRecordServiceBind_withNullIntent() {
         when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(7L);
 
         long eventId = DebugStore.recordServiceBind(false, null);
-
-        verify(mDebugStoreNativeMock).beginEvent(eq("SvcBind"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "rebind", "false",
-                "act", "null",
-                "cmp", "null",
-                "pkg", "null"
-        ).inOrder();
+        assertThat(paramsForBeginEvent("SvcBind"))
+                .containsExactly(
+                        "rebind", "false",
+                        "act", "null",
+                        "cmp", "null",
+                        "pkg", "null")
+                .inOrder();
         assertThat(eventId).isEqualTo(7L);
     }
 
     @Test
-    public void testRecordBroadcastHandleReceiverWithNullIntent() {
+    public void testRecordBroadcastReceive_withNullIntent() {
         when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(8L);
 
-        long eventId = DebugStore.recordBroadcastHandleReceiver(null);
-
-        verify(mDebugStoreNativeMock).beginEvent(eq("HandleReceiver"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "tname", Thread.currentThread().getName(),
-                "tid", String.valueOf(Thread.currentThread().getId()),
-                "act", "null",
-                "cmp", "null",
-                "pkg", "null"
-        ).inOrder();
+        long eventId = DebugStore.recordBroadcastReceive(null, 3840 /* 0xf00 */);
+        assertThat(paramsForBeginEvent("BcRcv"))
+                .containsExactly(
+                        "tname", Thread.currentThread().getName(),
+                        "tid", String.valueOf(Thread.currentThread().getId()),
+                        "act", "null",
+                        "cmp", "null",
+                        "pkg", "null",
+                        "prid", "f00")
+                .inOrder();
         assertThat(eventId).isEqualTo(8L);
     }
 
     @Test
-    public void testRecordGoAsyncWithNullReceiverClassName() {
-        DebugStore.recordGoAsync(null);
+    public void testRecordBroadcastReceiveReg_withNullIntent() {
+        when(mDebugStoreNativeMock.beginEvent(anyString(), anyList())).thenReturn(8L);
 
-        verify(mDebugStoreNativeMock).recordEvent(eq("GoAsync"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "tname", Thread.currentThread().getName(),
-                "tid", String.valueOf(Thread.currentThread().getId()),
-                "rcv", "null"
-        ).inOrder();
+        long eventId = DebugStore.recordBroadcastReceiveReg(null, 3840 /* 0xf00 */);
+        assertThat(paramsForBeginEvent("BcRcvReg"))
+                .containsExactly(
+                        "tname",
+                        Thread.currentThread().getName(),
+                        "tid",
+                        String.valueOf(Thread.currentThread().getId()),
+                        "act",
+                        "null",
+                        "cmp",
+                        "null",
+                        "pkg",
+                        "null",
+                        "prid",
+                        "f00")
+                .inOrder();
+        assertThat(eventId).isEqualTo(8L);
     }
 
     @Test
-    public void testRecordFinishWithNullReceiverClassName() {
-        DebugStore.recordFinish(null);
+    public void testRecordFinish_withNullReceiverClassName() {
+        DebugStore.recordFinish(3840 /* 0xf00 */);
 
-        verify(mDebugStoreNativeMock).recordEvent(eq("Finish"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "tname", Thread.currentThread().getName(),
-                "tid", String.valueOf(Thread.currentThread().getId()),
-                "rcv", "null"
-        ).inOrder();
+        assertThat(paramsForRecordEvent("Finish"))
+                .containsExactly(
+                        "tname",
+                        Thread.currentThread().getName(),
+                        "tid",
+                        String.valueOf(Thread.currentThread().getId()),
+                        "prid",
+                        "f00")
+                .inOrder();
     }
 
     @Test
-    public void testRecordLongLooperMessageWithNullTargetClass() {
+    public void testRecordLongLooperMessage_withNullTargetClass() {
         DebugStore.recordLongLooperMessage(200, null, 1000L);
 
-        verify(mDebugStoreNativeMock).recordEvent(eq("LooperMsg"), mListCaptor.capture());
-        List<String> capturedList = mListCaptor.getValue();
-        assertThat(capturedList).containsExactly(
-                "code", "200",
-                "trgt", "null",
-                "elapsed", "1000"
-        ).inOrder();
+        assertThat(paramsForRecordEvent("LooperMsg"))
+                .containsExactly(
+                        "code", "200",
+                        "trgt", "null",
+                        "elapsed", "1000")
+                .inOrder();
     }
+
+    private List<String> paramsForBeginEvent(String eventName) {
+        verify(mDebugStoreNativeMock).beginEvent(eq(eventName), mListCaptor.capture());
+        return mListCaptor.getValue();
+    }
+
+    private List<String> paramsForRecordEvent(String eventName) {
+        verify(mDebugStoreNativeMock).recordEvent(eq(eventName), mListCaptor.capture());
+        return mListCaptor.getValue();
+    }
+
 }
diff --git a/core/tests/coretests/src/com/android/internal/os/OWNERS b/core/tests/coretests/src/com/android/internal/os/OWNERS
index 3f8f9e2..ec236ca 100644
--- a/core/tests/coretests/src/com/android/internal/os/OWNERS
+++ b/core/tests/coretests/src/com/android/internal/os/OWNERS
@@ -2,3 +2,4 @@
 
 # CPU
 per-file *Cpu* = file:/core/java/com/android/internal/os/CPU_OWNERS
+per-file *DebugStore* = file:/core/java/com/android/internal/os/DEBUG_STORE_OWNERS
diff --git a/core/tests/vibrator/src/android/os/ExternalVibrationTest.java b/core/tests/vibrator/src/android/os/ExternalVibrationTest.java
index 8741907..9c9d502 100644
--- a/core/tests/vibrator/src/android/os/ExternalVibrationTest.java
+++ b/core/tests/vibrator/src/android/os/ExternalVibrationTest.java
@@ -49,4 +49,22 @@
         assertThat(restored.getAudioAttributes()).isEqualTo(original.getAudioAttributes());
         assertThat(restored.getToken()).isEqualTo(original.getToken());
     }
+
+    @Test
+    public void testSerialization_systemUsage() {
+        ExternalVibration original =
+                new ExternalVibration(
+                        123,
+                        "pkg",
+                        new AudioAttributes.Builder()
+                                .setSystemUsage(AudioAttributes.USAGE_SPEAKER_CLEANUP)
+                                .build(),
+                        IExternalVibrationController.Stub.asInterface(new Binder()));
+        Parcel p = Parcel.obtain();
+        original.writeToParcel(p, 0);
+        p.setDataPosition(0);
+        ExternalVibration restored = ExternalVibration.CREATOR.createFromParcel(p);
+
+        assertThat(restored.getAudioAttributes()).isEqualTo(original.getAudioAttributes());
+    }
 }
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
index 477d207..16e098b 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu.xml
@@ -53,15 +53,12 @@
 
         <com.android.wm.shell.windowdecor.HandleMenuImageButton
             android:id="@+id/collapse_menu_button"
-            android:layout_width="16dp"
-            android:layout_height="16dp"
-            android:layout_marginEnd="16dp"
-            android:layout_marginStart="14dp"
+            android:padding="16dp"
             android:contentDescription="@string/collapse_menu_text"
-            android:src="@drawable/ic_baseline_expand_more_24"
+            android:src="@drawable/ic_baseline_expand_more_16"
             android:rotation="180"
             android:tint="@androidprv:color/materialColorOnSurface"
-            android:background="?android:selectableItemBackgroundBorderless"/>
+            style="@style/DesktopModeHandleMenuWindowingButton"/>
     </LinearLayout>
 
     <LinearLayout
@@ -145,6 +142,7 @@
             android:contentDescription="@string/screenshot_text"
             android:text="@string/screenshot_text"
             android:src="@drawable/desktop_mode_ic_handle_menu_screenshot"
+            android:importantForAccessibility="no"
             style="@style/DesktopModeHandleMenuActionButton"/>
 
         <com.android.wm.shell.windowdecor.HandleMenuActionButton
@@ -152,6 +150,7 @@
             android:contentDescription="@string/new_window_text"
             android:text="@string/new_window_text"
             android:src="@drawable/desktop_mode_ic_handle_menu_new_window"
+            android:importantForAccessibility="no"
             style="@style/DesktopModeHandleMenuActionButton"/>
 
         <com.android.wm.shell.windowdecor.HandleMenuActionButton
@@ -159,6 +158,7 @@
             android:contentDescription="@string/manage_windows_text"
             android:text="@string/manage_windows_text"
             android:src="@drawable/desktop_mode_ic_handle_menu_manage_windows"
+            android:importantForAccessibility="no"
             style="@style/DesktopModeHandleMenuActionButton"/>
 
         <com.android.wm.shell.windowdecor.HandleMenuActionButton
@@ -166,6 +166,7 @@
             android:contentDescription="@string/change_aspect_ratio_text"
             android:text="@string/change_aspect_ratio_text"
             android:src="@drawable/desktop_mode_ic_handle_menu_change_aspect_ratio"
+            android:importantForAccessibility="no"
             style="@style/DesktopModeHandleMenuActionButton"/>
     </LinearLayout>
 
@@ -185,6 +186,7 @@
             android:text="@string/open_in_browser_text"
             android:src="@drawable/desktop_mode_ic_handle_menu_open_in_browser"
             style="@style/DesktopModeHandleMenuActionButton"
+            android:importantForAccessibility="no"
             android:layout_width="0dp"
             android:layout_weight="1"/>
 
diff --git a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml
index 0163c01..de38e6f 100644
--- a/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml
+++ b/libs/WindowManager/Shell/res/layout/desktop_mode_window_decor_handle_menu_action_button.xml
@@ -34,5 +34,6 @@
 
     <com.android.wm.shell.windowdecor.MarqueedTextView
         android:id="@+id/label"
+        android:importantForAccessibility="no"
         style="@style/DesktopModeHandleMenuActionButtonTextView"/>
 </LinearLayout>
diff --git a/libs/WindowManager/Shell/res/values-af/strings.xml b/libs/WindowManager/Shell/res/values-af/strings.xml
index 4dffce5..61dbb69 100644
--- a/libs/WindowManager/Shell/res/values-af/strings.xml
+++ b/libs/WindowManager/Shell/res/values-af/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Links 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Links 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Volskerm regs"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Ruil boonste app met onderste een"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Ruil linkerapp met regterapp"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Volskerm bo"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Bo 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bo 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Herbegin"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Moenie weer wys nie"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dubbeltik om\nhierdie app te skuif"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimeer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Stel <xliff:g id="APP_NAME">%1$s</xliff:g> terug"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimeer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Maak <xliff:g id="APP_NAME">%1$s</xliff:g> toe"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Terug"</string>
     <string name="handle_text" msgid="4419667835599523257">"Apphandvatsel"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Appikoon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Verander grootte van linkerkantse venster"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Verander grootte van regterkantse venster"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimeer of stel venstergrootte terug"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimeer appvenstergrootte"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Stel venstergrootte terug"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimeer appvenster"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Maak appvenster toe"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Maak By Verstek Oop-instellings"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Kies hoe om webskakels vir hierdie app oop te maak"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In die app"</string>
diff --git a/libs/WindowManager/Shell/res/values-am/strings.xml b/libs/WindowManager/Shell/res/values-am/strings.xml
index 0881e77..52008a6 100644
--- a/libs/WindowManager/Shell/res/values-am/strings.xml
+++ b/libs/WindowManager/Shell/res/values-am/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ግራ 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ግራ 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"የቀኝ ሙሉ ማያ ገፅ"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ከላይ ያለውን መተግበሪያ ከታች ባለው ቀይር"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"በግራ ያለውን መተግበሪያን በቀኝ ባለው ቀይር"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"የላይ ሙሉ ማያ ገፅ"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ከላይ 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ከላይ 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"እንደገና ያስጀምሩ"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ዳግም አታሳይ"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ይህን መተግበሪያ\nለማንቀሳቀስ ሁለቴ መታ ያድርጉ"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን አሳድግ"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን ወደነበረበት መልስ"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን አሳንስ"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g>ን ዝጋ"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ተመለስ"</string>
     <string name="handle_text" msgid="4419667835599523257">"የመተግበሪያ መያዣ"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"የመተግበሪያ አዶ"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"መስኮትን ወደ ግራ መጠን ቀይር"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"መስኮትን ወደ ቀኝ መጠን ቀይር"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"የመስኮት መጠንን አሳድግ ወይም ወደነበረበት መልስ"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"የመተግበሪያ መስኮት መጠንን አሳድግ"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"የመስኮት መጠንን ወደነበረበት መልስ"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"የመተግበሪያ መስኮትን አሳንስ"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"የመተግበሪያ መስኮትን ዝጋ"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"በነባሪ ቅንብሮች ክፈት"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ለዚህ የድር መተግበሪያ አገናኙን እንዴት እንደሚከፍቱ ይምረጡ"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"በመተግበሪያው ውስጥ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ar/strings.xml b/libs/WindowManager/Shell/res/values-ar/strings.xml
index 9cc49aa..65dd965 100644
--- a/libs/WindowManager/Shell/res/values-ar/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ar/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ضبط حجم النافذة اليسرى ليكون ٥٠%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ضبط حجم النافذة اليسرى ليكون ٣٠%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"عرض النافذة اليمنى بملء الشاشة"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"تبديل التطبيق العلوي بالسفلي"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"تبديل التطبيق الأيسر بالأيمن"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"عرض النافذة العلوية بملء الشاشة"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ضبط حجم النافذة العلوية ليكون ٧٠%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ضبط حجم النافذة العلوية ليكون ٥٠%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"إعادة التشغيل"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"عدم عرض مربّع حوار التأكيد مجددًا"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"انقر مرّتَين لنقل\nهذا التطبيق."</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"تكبير \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"استعادة \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"تصغير \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="close_button_text" msgid="4544839489310949894">"إغلاق \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="back_button_text" msgid="1469718707134137085">"رجوع"</string>
     <string name="handle_text" msgid="4419667835599523257">"مقبض التطبيق"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"رمز التطبيق"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"تغيير حجم النافذة بمحاذاتها إلى اليمين"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"تغيير حجم النافذة بمحاذاتها إلى اليسار"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"تكبير حجم النافذة أو استعادته"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"تكبير نافذة التطبيق"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"استعادة حجم النافذة"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"تصغير نافذة التطبيق"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"إغلاق نافذة التطبيق"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"إعدادات الفتح تلقائيًا"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"اختيار طريقة فتح روابط الويب لهذا التطبيق"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"في التطبيق"</string>
diff --git a/libs/WindowManager/Shell/res/values-as/strings.xml b/libs/WindowManager/Shell/res/values-as/strings.xml
index c59753c..919447e 100644
--- a/libs/WindowManager/Shell/res/values-as/strings.xml
+++ b/libs/WindowManager/Shell/res/values-as/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"বাওঁফালৰ স্ক্ৰীনখন ৫০% কৰক"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"বাওঁফালৰ স্ক্ৰীনখন ৩০% কৰক"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"সোঁফালৰ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"একেবাৰে তলৰ সৈতে একেবাৰে ওপৰৰ এপ্‌টো সলনাসলনি কৰক"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"সোঁফালৰ সৈতে বাওঁফালৰ এপ্‌টো সলনাসলনি কৰক"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"শীৰ্ষ স্ক্ৰীনখন সম্পূৰ্ণ স্ক্ৰীন কৰক"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"শীর্ষ স্ক্ৰীনখন ৭০% কৰক"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ স্ক্ৰীনখন ৫০% কৰক"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ৰিষ্টাৰ্ট কৰক"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"পুনৰাই নেদেখুৱাব"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"এই এপ্‌টো\nস্থানান্তৰ কৰিবলৈ দুবাৰ টিপক"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> মেক্সিমাইজ কৰক"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g>ক পুনঃস্থাপন কৰক"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> মিনিমাইজ কৰক"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> বন্ধ কৰক"</string>
     <string name="back_button_text" msgid="1469718707134137085">"উভতি যাওক"</string>
     <string name="handle_text" msgid="4419667835599523257">"এপৰ হেণ্ডেল"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"এপৰ চিহ্ন"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"সোঁফাললৈ ৱিণ্ড’ৰ আকাৰ সলনি কৰক"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"বাওঁফাললৈ ৱিণ্ড’ৰ আকাৰ সলনি কৰক"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ৱিণ্ড’ৰ আকাৰ মেক্সিমাইজ বা পুনঃস্থাপন কৰক"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"এপ্‌ ৱিণ্ড’ৰ আকাৰ মেক্সিমাইজ কৰক"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ৱিণ্ড’ৰ আকাৰ পুনঃস্থাপন কৰক"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"এপ্‌ ৱিণ্ড’ মিনিমাইজ কৰক"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"এপ্‌ ৱিণ্ড’ বন্ধ কৰক"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ডিফ’ল্ট ছেটিং খোলক"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"এই এপ্‌টোৰ বাবে কিদৰে ৱেব লিংক খুলিব পাৰি সেয়া বাছনি কৰক"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"এপ্‌টোত"</string>
diff --git a/libs/WindowManager/Shell/res/values-az/strings.xml b/libs/WindowManager/Shell/res/values-az/strings.xml
index 63e610b..846240f 100644
--- a/libs/WindowManager/Shell/res/values-az/strings.xml
+++ b/libs/WindowManager/Shell/res/values-az/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sol 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Sol 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Sağ tam ekran"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Yuxarıdakı tətbiqi aşağıdakı ilə dəyişdirin"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Soldakı tətbiqi sağdakı ilə dəyişdirin"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Yuxarı tam ekran"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Yuxarı 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yuxarı 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Yenidən başladın"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Yenidən göstərməyin"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tətbiqi köçürmək üçün\niki dəfə toxunun"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Böyüdün: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Bərpa edin: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Kiçildin: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Bağlayın: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Geriyə"</string>
     <string name="handle_text" msgid="4419667835599523257">"Tətbiq ləqəbi"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Tətbiq ikonası"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pəncərə ölçüsünü sola dəyişin"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pəncərə ölçüsünü sağa dəyişin"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Pəncərə ölçüsünü artırın və ya bərpa edin"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Tətbiq pəncərəsi ölçüsünü böyüdün"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Pəncərə ölçüsünü bərpa edin"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Tətbiq pəncərəsini kiçildin"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Tətbiq pəncərəsini bağlayın"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Defolt ayarlarla açın"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Bu tətbiq üçün veb-linklərin necə açılacağını seçin"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Tətbiqdə"</string>
diff --git a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
index 7cb6f87..4ee7d7e 100644
--- a/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-b+sr+Latn/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Levi ekran 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Levi ekran 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Režim celog ekrana za donji ekran"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Zamenite gornju aplikaciju donjom"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Zamenite levu aplikaciju desnom"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Režim celog ekrana za gornji ekran"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gornji ekran 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gornji ekran 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restartuj"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovo"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvaput dodirnite da biste\npremestili ovu aplikaciju"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Uvećajte: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Vratite: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Umanjite: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zatvorite: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Nazad"</string>
     <string name="handle_text" msgid="4419667835599523257">"Identifikator aplikacije"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Promenite veličinu prozora nalevo"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Promenite veličinu prozora nadesno"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Uvećajte ili vratite veličinu prozora"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Uvećajte veličinu prozora aplikacije"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Vratite veličinu prozora"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Umanjite prozor aplikacije"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zatvorite prozor aplikacije"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Podešavanje Podrazumevano otvaraj"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Odaberite način otvaranja veb-linkova za ovu aplikaciju"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"U aplikaciji"</string>
diff --git a/libs/WindowManager/Shell/res/values-be/strings.xml b/libs/WindowManager/Shell/res/values-be/strings.xml
index 4f3da2b..d686da9 100644
--- a/libs/WindowManager/Shell/res/values-be/strings.xml
+++ b/libs/WindowManager/Shell/res/values-be/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левы экран – 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Левы экран – 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Правы экран – поўнаэкранны рэжым"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Памяняць месцамі верхнюю і ніжнюю праграмы"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Памяняць месцамі левую і правую праграмы"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Верхні экран – поўнаэкранны рэжым"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Верхні экран – 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхні экран – 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Перазапусціць"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Больш не паказваць"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Каб перамясціць праграму,\nнацісніце двойчы"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Разгарнуць праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Аднавіць праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Згарнуць праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Закрыць праграму \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
     <string name="handle_text" msgid="4419667835599523257">"Маркер праграмы"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Значок праграмы"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Змяніць памер акна і перамясціць да левага краю"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Змяніць памер акна і перамясціць да правага краю"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Разгарнуць акно ці аднавіць яго памер"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Разгарнуць акно праграмы"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Аднавіць памер акна"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Згарнуць акно праграмы"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Закрыць акно праграмы"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Налады параметра \"Адкрываць стандартна\""</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Выберыце, як гэта праграма будзе адкрываць вэб-спасылкі"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"У праграме"</string>
diff --git a/libs/WindowManager/Shell/res/values-bg/strings.xml b/libs/WindowManager/Shell/res/values-bg/strings.xml
index 3f867a22..984c20f 100644
--- a/libs/WindowManager/Shell/res/values-bg/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bg/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ляв екран: 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ляв екран: 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Десен екран: Показване на цял екран"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Размяна на горното и долното приложение"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Размяна на лявото и дясното приложение"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Горен екран: Показване на цял екран"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Горен екран: 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горен екран: 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартиране"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Да не се показва отново"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Докоснете двукратно, за да\nпреместите това приложение"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Увеличаване на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Възстановяване на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Намаляване на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Затваряне на <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
     <string name="handle_text" msgid="4419667835599523257">"Манипулатор за приложението"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Икона на приложението"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Преоразмеряване на прозореца наляво"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Преоразмеряване на прозореца надясно"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Увеличаване или възстановяване на размера на прозореца"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Увеличаване на размера на прозореца на приложението"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Възстановяване на размера на прозореца"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Намаляване на прозореца на приложението"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Затваряне на прозореца на приложението"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Отваряне на настройките по подразбиране"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Изберете как да се отварят уеб връзките за това приложение"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"В приложението"</string>
diff --git a/libs/WindowManager/Shell/res/values-bn/strings.xml b/libs/WindowManager/Shell/res/values-bn/strings.xml
index 3967d4b..dd5653c 100644
--- a/libs/WindowManager/Shell/res/values-bn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bn/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"৫০% বাকি আছে"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"৩০% বাকি আছে"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ডান দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"নিচেরটির মাধ্যমে উপরের অ্যাপ অদল বদল করে নিন"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ডানদিকের মাধ্যমে বাঁদিকের অ্যাপ অদল বদল করে নিন"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"উপর দিকের অংশ নিয়ে পূর্ণ স্ক্রিন"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"শীর্ষ ৭০%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"শীর্ষ ৫০%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"রিস্টার্ট করুন"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"আর দেখতে চাই না"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"এই অ্যাপ সরাতে\nডবল ট্যাপ করুন"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> বড় করুন"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> আবার ফিরিয়ে আনুন"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> ছোট করুন"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> বন্ধ করুন"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ফিরে যান"</string>
     <string name="handle_text" msgid="4419667835599523257">"অ্যাপের হ্যান্ডেল"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"অ্যাপ আইকন"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"বাঁদিকে উইন্ডো রিসাইজ করুন"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ডানদিকে উইন্ডো রিসাইজ করুন"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"উইন্ডো সাইজ বড় বা রিস্টোর করুন"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"অ্যাপ উইন্ডোর সাইজ বাড়ান"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"উইন্ডোর সাইজ ফিরিয়ে আনুন"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"অ্যাপ উইন্ডো ছোট করুন"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"অ্যাপ উইন্ডো বন্ধ করুন"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ডিফল্ট হিসেবে থাকা সেটিংস খুলুন"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"এই অ্যাপের জন্য কীভাবে ওয়েব লিঙ্ক খুলবেন তা বেছে নিন"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"অ্যাপের মধ্যে"</string>
diff --git a/libs/WindowManager/Shell/res/values-bs/strings.xml b/libs/WindowManager/Shell/res/values-bs/strings.xml
index 6b59d91..01e0515 100644
--- a/libs/WindowManager/Shell/res/values-bs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-bs/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Lijevo 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Lijevo 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Desno cijeli ekran"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Zamjena gornje aplikacije donjom"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Zamjena lijeve aplikacije desnom"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Gore cijeli ekran"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gore 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gore 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Ponovo pokreni"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovo"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dodirnite dvaput da\npomjerite aplikaciju"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimiziranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Vraćanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimiziranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zatvaranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Nazad"</string>
     <string name="handle_text" msgid="4419667835599523257">"Ručica aplikacije"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Promjena veličine prozora i poravnanje lijevo"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Promjena veličine prozora i poravnanje desno"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimiziranje ili vraćanje veličine prozora"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimiziranje veličine prozora aplikacije"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Vraćanje veličine prozora"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimiziranje prozora aplikacije"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zatvaranje prozora aplikacije"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otvaranje prema zadanim postavkama"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Odaberite način otvaranja web linkova za ovu aplikaciju"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"U aplikaciji"</string>
diff --git a/libs/WindowManager/Shell/res/values-ca/strings.xml b/libs/WindowManager/Shell/res/values-ca/strings.xml
index 955e5cc..77cf94b 100644
--- a/libs/WindowManager/Shell/res/values-ca/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ca/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pantalla esquerra al 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Pantalla esquerra al 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla dreta completa"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Intercanvia l\'aplicació superior amb la inferior"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Intercanvia l\'aplicació esquerra amb la dreta"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Pantalla superior al 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Pantalla superior al 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reinicia"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"No ho tornis a mostrar"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Fes doble toc per\nmoure aquesta aplicació"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximitza <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaura <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimitza <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Tanca <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Enrere"</string>
     <string name="handle_text" msgid="4419667835599523257">"Identificador de l\'aplicació"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icona de l\'aplicació"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Canvia la mida de la finestra a l\'esquerra"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Canvia la mida de la finestra a la dreta"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximitza o restaura la mida de la finestra"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximitza la mida de la finestra de l\'aplicació"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaura la mida de la finestra"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimitza la finestra de l\'aplicació"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Tanca la finestra de l\'aplicació"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Configuració d\'obertura predeterminada"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Tria com vols obrir els enllaços web per a aquesta aplicació"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"A l\'aplicació"</string>
diff --git a/libs/WindowManager/Shell/res/values-cs/strings.xml b/libs/WindowManager/Shell/res/values-cs/strings.xml
index 673f7fc..1a414ba 100644
--- a/libs/WindowManager/Shell/res/values-cs/strings.xml
+++ b/libs/WindowManager/Shell/res/values-cs/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % vlevo"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % vlevo"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pravá část na celou obrazovku"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Prohodit horní a dolní aplikaci"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Prohodit levou a pravou aplikaci"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Horní část na celou obrazovku"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % nahoře"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % nahoře"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restartovat"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Tuto zprávu příště nezobrazovat"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvojitým klepnutím\npřesunete aplikaci"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximalizovat aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Obnovit aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimalizovat aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zavřít aplikaci <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Zpět"</string>
     <string name="handle_text" msgid="4419667835599523257">"Popisovač aplikace"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikace"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Přichytit okno vlevo"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Přichytit okno vpravo"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximalizovat nebo obnovit velikost okna"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximalizovat velikost okna aplikace"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Obnovit velikost okna"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimalizovat okno aplikace"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zavřít okno aplikace"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otevírat podle výchozího nastavení"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Určete, jak se v této aplikaci mají otevírat webové odkazy"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"V aplikaci"</string>
diff --git a/libs/WindowManager/Shell/res/values-da/strings.xml b/libs/WindowManager/Shell/res/values-da/strings.xml
index 635df33..07f1969 100644
--- a/libs/WindowManager/Shell/res/values-da/strings.xml
+++ b/libs/WindowManager/Shell/res/values-da/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Venstre 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Venstre 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Vis højre del i fuld skærm"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Byt om på den øverste og nederste app"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Byt om på den venstre og højre app"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Vis øverste del i fuld skærm"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Øverste 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Øverste 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Genstart"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Vis ikke igen"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tryk to gange\nfor at flytte appen"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Gendan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Luk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Tilbage"</string>
     <string name="handle_text" msgid="4419667835599523257">"Apphåndtag"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Juster størrelsen på vinduet til venstre"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Juster størrelsen på vinduet til højre"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimer eller gendan vinduesstørrelse"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimer størrelsen på appvinduet"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Gendan størrelsen på vinduet"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimer appvindue"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Luk appvindue"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Indstillinger for automatisk åbning"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Vælg, hvordan denne app skal åben weblinks"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string>
diff --git a/libs/WindowManager/Shell/res/values-de/strings.xml b/libs/WindowManager/Shell/res/values-de/strings.xml
index 5be8b0b..7a8f2d9 100644
--- a/libs/WindowManager/Shell/res/values-de/strings.xml
+++ b/libs/WindowManager/Shell/res/values-de/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % links"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % links"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Vollbild rechts"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Obere und untere App vertauschen"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Linke und rechte App vertauschen"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Vollbild oben"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % oben"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % oben"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Neu starten"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Nicht mehr anzeigen"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Zum Verschieben\ndoppeltippen"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> maximieren"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> wiederherstellen"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> minimieren"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> schließen"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Zurück"</string>
     <string name="handle_text" msgid="4419667835599523257">"App-Ziehpunkt"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"App-Symbol"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Fenstergröße nach links anpassen"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Fenstergröße nach rechts anpassen"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Fenstergröße maximieren oder wiederherstellen"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"App-Fenster maximieren"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Fenstergröße wiederherstellen"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"App-Fenster minimieren"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"App-Fenster schließen"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Einstellungen für die Option „Standardmäßig öffnen“"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Festlegen, wie Weblinks für diese App geöffnet werden"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In der App"</string>
diff --git a/libs/WindowManager/Shell/res/values-el/strings.xml b/libs/WindowManager/Shell/res/values-el/strings.xml
index bd3cf05..e2477d3 100644
--- a/libs/WindowManager/Shell/res/values-el/strings.xml
+++ b/libs/WindowManager/Shell/res/values-el/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Αριστερή 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Αριστερή 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Δεξιά πλήρης οθόνη"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Εναλλαγή της εφαρμογής στην κορυφή με αυτή στο κάτω μέρος"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Εναλλαγή της εφαρμογής στα αριστερά με αυτή στα δεξιά"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Πάνω πλήρης οθόνη"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Πάνω 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Πάνω 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Επανεκκίνηση"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Να μην εμφανιστεί ξανά"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Πατήστε δύο φορές για\nμετακίνηση αυτής της εφαρμογής"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Μεγιστοποίηση <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Επαναφορά <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Ελαχιστοποίηση <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Κλείσιμο <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Πίσω"</string>
     <string name="handle_text" msgid="4419667835599523257">"Λαβή εφαρμογής"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Εικονίδιο εφαρμογής"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Αλλαγή μεγέθους παραθύρου προς τα αριστερά"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Αλλαγή μεγέθους παραθύρου προς τα δεξιά"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Μεγιστοποίηση ή επαναφορά μεγέθους παραθύρου"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Μεγιστοποίηση μεγέθους παραθύρου εφαρμογής"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Επαναφορά μεγέθους παραθύρου"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Ελαχιστοποίηση παραθύρου εφαρμογής"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Κλείσιμο παραθύρου εφαρμογής"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Άνοιγμα ρυθμίσεων από προεπιλογή"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Επιλογή τρόπου ανοίγματος συνδέσμων ιστού για την εφαρμογή"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Στην εφαρμογή"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
index b137d80..bed6e50 100644
--- a/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rAU/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Swap top app with bottom"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Swap left app with right"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove this app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximise <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restore <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimise <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Close <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Back"</string>
     <string name="handle_text" msgid="4419667835599523257">"App handle"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximise app window size"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restore window size"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimise app window"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Close app window"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
index b137d80..bed6e50 100644
--- a/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rGB/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Swap top app with bottom"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Swap left app with right"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove this app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximise <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restore <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimise <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Close <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Back"</string>
     <string name="handle_text" msgid="4419667835599523257">"App handle"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximise app window size"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restore window size"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimise app window"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Close app window"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
diff --git a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
index b137d80..bed6e50 100644
--- a/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-en-rIN/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Left 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Left 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Right full screen"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Swap top app with bottom"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Swap left app with right"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Top full screen"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Top 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Top 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restart"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Don\'t show again"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Double-tap to\nmove this app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximise <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restore <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimise <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Close <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Back"</string>
     <string name="handle_text" msgid="4419667835599523257">"App handle"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"App icon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Resize window to left"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Resize window to right"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximise or restore window size"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximise app window size"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restore window size"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimise app window"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Close app window"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Open by default settings"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choose how to open web links for this app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In the app"</string>
diff --git a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
index ebfdc6d..2b7769d 100644
--- a/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es-rUS/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Izquierda: 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Izquierda: 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla derecha completa"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Intercambiar la app superior con la inferior"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Intercambiar la app de la izquierda con la de la derecha"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Superior: 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior: 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"No volver a mostrar"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Presiona dos veces\npara mover esta app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restablecer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Cerrar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string>
     <string name="handle_text" msgid="4419667835599523257">"Controlador de la app"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ícono de la app"</string>
@@ -142,7 +136,7 @@
     <string name="collapse_menu_text" msgid="7515008122450342029">"Cerrar menú"</string>
     <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (vista para computadoras de escritorio)"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maximizar pantalla"</string>
-    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Cambiar el tamaño"</string>
+    <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Dividir pantalla"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"No se puede mover la app aquí"</string>
     <string name="desktop_mode_maximize_menu_immersive_button_text" msgid="559492223133829481">"Inmersivo"</string>
     <string name="desktop_mode_maximize_menu_immersive_restore_button_text" msgid="4900114367354709257">"Restablecer"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ajustar el tamaño de la ventana hacia la izquierda"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ajustar el tamaño de la ventana hacia la derecha"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar o restablecer el tamaño de la ventana"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizar el tamaño de la ventana de la app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restablecer el tamaño de la ventana"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizar ventana de la app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Cerrar ventana de la app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Abrir con la configuración predeterminada"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Elige cómo abrir vínculos web para esta app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"En la app"</string>
diff --git a/libs/WindowManager/Shell/res/values-es/strings.xml b/libs/WindowManager/Shell/res/values-es/strings.xml
index dfa7869..afb1034 100644
--- a/libs/WindowManager/Shell/res/values-es/strings.xml
+++ b/libs/WindowManager/Shell/res/values-es/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Izquierda 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Izquierda 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla derecha completa"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Intercambiar aplicación superior con inferior"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Intercambiar aplicación izquierda con derecha"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla superior completa"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Superior 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Superior 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"No volver a mostrar"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toca dos veces para\nmover esta aplicación"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Cerrar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string>
     <string name="handle_text" msgid="4419667835599523257">"Controlador de la aplicación"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icono de la aplicación"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Cambiar tamaño de la ventana a la izquierda"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Cambiar tamaño de la ventana a la derecha"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar o restaurar tamaño de la ventana"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizar tamaño de la ventana de la aplicación"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurar tamaño de la ventana"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizar ventana de la aplicación"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Cerrar ventana de la aplicación"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Abrir con los ajustes predeterminados"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Elige cómo quieres abrir los enlaces web de esta aplicación"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"En la aplicación"</string>
diff --git a/libs/WindowManager/Shell/res/values-et/strings.xml b/libs/WindowManager/Shell/res/values-et/strings.xml
index 294b7fe..61ca3e0 100644
--- a/libs/WindowManager/Shell/res/values-et/strings.xml
+++ b/libs/WindowManager/Shell/res/values-et/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vasak: 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vasak: 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Parem täisekraan"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Ülemise ja alumise rakenduse vahetamine"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Vasaku ja parema rakenduse vahetamine"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ülemine täisekraan"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Ülemine: 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Ülemine: 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Taaskäivita"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ära kuva uuesti"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Rakenduse teisaldamiseks\ntopeltpuudutage"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> maksimeerimine"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> taastamine"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> minimeerimine"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Rakenduse <xliff:g id="APP_NAME">%1$s</xliff:g> sulgemine"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Tagasi"</string>
     <string name="handle_text" msgid="4419667835599523257">"Rakenduse element"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Rakenduse ikoon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Akna suuruse muutmine, vasakule"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Akna suuruse muutmine, paremale"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Akna suuruse maksimeerimine või taastamine"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Rakenduse akna suuruse maksimeerimine"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Akna suuruse taastamined"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Rakenduse akna minimeerimine"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Rakenduse akna sulgemine"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Avamisviisi vaikeseaded"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Valige, kuidas avada selle rakenduse puhul veebilinke"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Rakenduses"</string>
diff --git a/libs/WindowManager/Shell/res/values-eu/strings.xml b/libs/WindowManager/Shell/res/values-eu/strings.xml
index a8f9212..af175bc 100644
--- a/libs/WindowManager/Shell/res/values-eu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-eu/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ezarri ezkerraldea % 50en"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ezarri ezkerraldea % 30en"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ezarri eskuinaldea pantaila osoan"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Aldatu goiko aplikazioa behekoagatik"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Aldatu ezkerreko aplikazioa eskuinekoagatik"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ezarri goialdea pantaila osoan"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Ezarri goialdea % 70en"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Ezarri goialdea % 50en"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Berrabiarazi"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ez erakutsi berriro"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Sakatu birritan\naplikazioa mugitzeko"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizatu <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Leheneratu <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizatu <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Itxi <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Atzera"</string>
     <string name="handle_text" msgid="4419667835599523257">"Aplikazioaren kontrol-puntua"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Aplikazioaren ikonoa"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Aldatu leihoaren tamaina eta eraman ezkerrera"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Aldatu leihoaren tamaina eta eraman eskuinera"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizatu edo leheneratu leihoaren tamaina"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizatu aplikazioaren leihoaren tamaina"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Leheneratu leihoaren tamaina"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizatu aplikazioaren leihoa"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Itxi aplikazioaren leihoa"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Modu lehenetsian irekitzearen ezarpenak"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Aukeratu nola ireki sareko estekak aplikazio honetan"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Aplikazioan"</string>
diff --git a/libs/WindowManager/Shell/res/values-fa/strings.xml b/libs/WindowManager/Shell/res/values-fa/strings.xml
index 59affd7..4df47c1 100644
--- a/libs/WindowManager/Shell/res/values-fa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fa/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"٪۵۰ چپ"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"٪۳۰ چپ"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"تمام‌صفحه راست"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"جابه‌جا کردن برنامه بالا با پایین"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"جابه‌جا کردن برنامه چپ با راست"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"تمام‌صفحه بالا"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"٪۷۰ بالا"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"٪۵۰ بالا"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"بازراه‌اندازی"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"دوباره نشان داده نشود"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"برای جابه‌جا کردن این برنامه\nدو تک‌ضرب بزنید"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"بزرگ کردن <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"بازیابی <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"کوچک کردن <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"بستن <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"برگشتن"</string>
     <string name="handle_text" msgid="4419667835599523257">"دستگیره برنامه"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"نماد برنامه"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"تغییر اندازه پنجره به چپ"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"تغییر اندازه پنجره به راست"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"بیشینه‌سازی یا بازیابی اندازه پنجره"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"بزرگ کردن اندازه پنجره برنامه"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"بازیابی اندازه پنجره"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"کوچک کردن پنجره برنامه"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"بستن پنجره برنامه"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"تنظیمات باز کردن به‌طور پیش‌فرض"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"انتخاب روش باز کردن پیوندهای وب مربوط به این برنامه"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"در برنامه"</string>
diff --git a/libs/WindowManager/Shell/res/values-fi/strings.xml b/libs/WindowManager/Shell/res/values-fi/strings.xml
index b1d8431..7da06bd 100644
--- a/libs/WindowManager/Shell/res/values-fi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fi/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vasen 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vasen 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Oikea koko näytölle"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Vaihda ylä- ja alareunan sovellukset"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Vaihda vasen sovellus oikealla olevaan sovellukseen"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Yläosa koko näytölle"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Yläosa 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Yläosa 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Käynnistä uudelleen"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Älä näytä uudelleen"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Kaksoisnapauta, jos\nhaluat siirtää sovellusta"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Suurenna <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Palauta <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Pienennä <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Sulje <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Takaisin"</string>
     <string name="handle_text" msgid="4419667835599523257">"Sovelluksen tunnus"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Sovelluskuvake"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Muuta vasemmanpuoleisen ikkunan kokoa"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Muuta vasemmanpuoleisen ikkunan kokoa"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Suurenna ikkuna tai palauta ikkunan koko"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Suurenna sovellusikkunan koko"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Palauta ikkunan koko"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Pienennä sovellusikkuna"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Sulje sovellusikkuna"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Avaa oletusasetusten mukaan"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Valitse, miten verkkolinkit avataan tässä sovelluksessa"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Sovelluksessa"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
index c58f4b0..d0fac37 100644
--- a/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr-rCA/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % à la gauche"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % à la gauche"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Plein écran à la droite"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Inverser l\'appli du haut avec celle du bas"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Inverser l\'appli de gauche avec celle de droite"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Plein écran dans le haut"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % dans le haut"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % dans le haut"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Redémarrer"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne plus afficher"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toucher deux fois pour\ndéplacer cette appli"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Agrandir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Réduire <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Fermer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Retour"</string>
     <string name="handle_text" msgid="4419667835599523257">"Poignée de l\'appli"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icône de l\'appli"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionner la fenêtre vers la gauche"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionner la fenêtre vers la droite"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Agrandir ou restaurer la taille de la fenêtre"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Agrandir la taille de la fenêtre de l\'appli"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurer la taille de la fenêtre"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Réduire la fenêtre de l\'appli"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Fermer la fenêtre de l\'appli"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Ouvrir les paramètres par défaut"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choisissez comment ouvrir les liens Web pour cette appli"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Dans l\'appli"</string>
diff --git a/libs/WindowManager/Shell/res/values-fr/strings.xml b/libs/WindowManager/Shell/res/values-fr/strings.xml
index e8db4c9..91dc6de 100644
--- a/libs/WindowManager/Shell/res/values-fr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-fr/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Écran de gauche à 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Écran de gauche à 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Écran de droite en plein écran"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Inverser les applis du haut et du bas"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Inverser les applis de gauche et de droite"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Écran du haut en plein écran"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Écran du haut à 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Écran du haut à 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Redémarrer"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne plus afficher"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Appuyez deux fois\npour déplacer cette appli"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Agrandir <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Réduire <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Fermer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Retour"</string>
     <string name="handle_text" msgid="4419667835599523257">"Poignée de l\'appli"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icône d\'application"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionner la fenêtre vers la gauche"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionner la fenêtre vers la droite"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Agrandir ou restaurer la taille de la fenêtre"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Agrandir la taille de la fenêtre de l\'application"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurer la taille de la fenêtre"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Réduire la fenêtre de l\'application"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Fermer la fenêtre de l\'application"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Ouvrir les paramètres par défaut"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Choisir comment ouvrir les liens Web pour cette appli"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Dans l\'application"</string>
diff --git a/libs/WindowManager/Shell/res/values-gl/strings.xml b/libs/WindowManager/Shell/res/values-gl/strings.xml
index ba1c4a4..e315648 100644
--- a/libs/WindowManager/Shell/res/values-gl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-gl/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50 % á esquerda"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30 % á esquerda"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pantalla completa á dereita"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Cambiar a aplicación de arriba pola de abaixo"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Cambiar a aplicación da esquerda pola da dereita"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Pantalla completa arriba"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70 % arriba"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50 % arriba"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Non mostrar outra vez"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toca dúas veces para\nmover esta aplicación"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Pechar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Atrás"</string>
     <string name="handle_text" msgid="4419667835599523257">"Controlador da aplicación"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icona de aplicación"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Axustar o tamaño da ventá á esquerda"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Axustar o tamaño da ventá á dereita"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar ou restaurar o tamaño da ventá"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizar o tamaño da ventá da aplicación"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurar o tamaño da ventá"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizar a ventá da aplicación"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Pechar a ventá da aplicación"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Abrir coa configuración predeterminada"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Escoller como abrir as ligazóns web para esta aplicación"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Na aplicación"</string>
diff --git a/libs/WindowManager/Shell/res/values-hi/strings.xml b/libs/WindowManager/Shell/res/values-hi/strings.xml
index d0be7d5..cbcb267 100644
--- a/libs/WindowManager/Shell/res/values-hi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hi/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बाईं स्क्रीन को 50% बनाएं"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"बाईं स्क्रीन को 30% बनाएं"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"दाईं स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"सबसे ऊपर मौजूद ऐप्लिकेशन को सबसे नीचे मौजूद ऐप्लिकेशन से बदलें"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"बाईं ओर मौजूद ऐप्लिकेशन को दाईं ओर मौजूद ऐप्लिकेशन से बदलें"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ऊपर की स्क्रीन को फ़ुल स्क्रीन बनाएं"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ऊपर की स्क्रीन को 70% बनाएं"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ऊपर की स्क्रीन को 50% बनाएं"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"रीस्टार्ट करें"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"फिर से न दिखाएं"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ऐप्लिकेशन की जगह बदलने के लिए\nदो बार टैप करें"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> की विंडो को बड़ा करें"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> की विंडो को पहले जैसा करें"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> की विंडो को छोटा करें"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> को बंद करें"</string>
     <string name="back_button_text" msgid="1469718707134137085">"वापस जाएं"</string>
     <string name="handle_text" msgid="4419667835599523257">"ऐप्लिकेशन का हैंडल"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ऐप्लिकेशन आइकॉन"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"विंडो का साइज़ बाईं ओर से बदलें"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"विंडो का साइज़ दाईं ओर से बढ़ाएं"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विंडो को बड़ा करें या उसका साइज़ पहले जैसा करें"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ऐप्लिकेशन की विंडो का साइज़ बड़ा करें"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"विंडो का साइज़ पहले जैसा करें"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ऐप्लिकेशन की विंडो को छोटा करें"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ऐप्लिकेशन की विंडो बंद करें"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"डिफ़ॉल्ट सेटिंग के हिसाब से खोलें"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"इस ऐप्लिकेशन के लिए वेब लिंक खोलने का तरीका चुनें"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ऐप्लिकेशन में"</string>
diff --git a/libs/WindowManager/Shell/res/values-hr/strings.xml b/libs/WindowManager/Shell/res/values-hr/strings.xml
index d3e7599..0eed0a4 100644
--- a/libs/WindowManager/Shell/res/values-hr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hr/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Lijevi zaslon na 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Lijevi zaslon na 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Desni zaslon u cijeli zaslon"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Zamijeni gornju aplikaciju donjom"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Zamijeni lijevu aplikaciju desnom"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Gornji zaslon u cijeli zaslon"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gornji zaslon na 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gornji zaslon na 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Pokreni ponovno"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikazuj ponovno"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvaput dodirnite da biste\npremjestili ovu aplikaciju"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimiziraj aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Vrati aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimiziraj aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zatvori aplikaciju <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Natrag"</string>
     <string name="handle_text" msgid="4419667835599523257">"Pokazivač aplikacije"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Promijeni veličinu prozora ulijevo"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Promijeni veličinu prozora udesno"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimiziraj ili vrati veličinu prozora"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimiziraj prozor aplikacije"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Vrati veličinu prozora"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimiziraj prozor aplikacije"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zatvori prozor aplikacije"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otvori prema zadanim postavkama"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Odaberite način otvaranja web-veza za ovu aplikaciju"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"U aplikaciji"</string>
diff --git a/libs/WindowManager/Shell/res/values-hu/strings.xml b/libs/WindowManager/Shell/res/values-hu/strings.xml
index 2f7a218..48d5afd 100644
--- a/libs/WindowManager/Shell/res/values-hu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hu/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Bal oldali 50%-ra"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Bal oldali 30%-ra"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Jobb oldali teljes képernyőre"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"A felső alkalmazás és az alsó alkalmazás felcserélése"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Bal és jobb alkalmazás felcserélése"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Felső teljes képernyőre"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Felső 70%-ra"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Felső 50%-ra"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Újraindítás"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne jelenjen meg többé"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Koppintson duplán\naz alkalmazás áthelyezéséhez"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> teljes méretűre állítása"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> visszaállítása"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> kis méretűre állítása"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> bezárása"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Vissza"</string>
     <string name="handle_text" msgid="4419667835599523257">"App fogópontja"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Alkalmazásikon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ablak átméretezése balra"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ablak átméretezése jobbra"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Ablak teljes méretre állítása vagy visszaállítása"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Alkalmazásablak teljes méretre állítása"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Ablak méretének visszaállítása"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Alkalmazásablak kis méretre állítása"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Alkalmazás ablakának bezárása"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Alapértelmezett beállítások megnyitása"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Az app webes linkjeinek megnyitásához használt módszer"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Az alkalmazásban"</string>
diff --git a/libs/WindowManager/Shell/res/values-hy/strings.xml b/libs/WindowManager/Shell/res/values-hy/strings.xml
index 2898dcc..bf1e8401 100644
--- a/libs/WindowManager/Shell/res/values-hy/strings.xml
+++ b/libs/WindowManager/Shell/res/values-hy/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ձախ էկրանը՝ 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ձախ էկրանը՝ 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Աջ էկրանը՝ լիաէկրան"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Փոխեք վերևի հավելվածը վերևից"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Փոխեք ձախ հավելվածը աջից"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Վերևի էկրանը՝ լիաէկրան"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Վերևի էկրանը՝ 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Վերևի էկրանը՝ 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Վերագործարկել"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Այլևս ցույց չտալ"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Կրկնակի հպեք՝\nհավելվածը տեղափոխելու համար"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Ծավալել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Վերականգնել «<xliff:g id="APP_NAME">%1$s</xliff:g>» միջոցառումը"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Ծալել <xliff:g id="APP_NAME">%1$s</xliff:g> հավելվածը"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Փակել՝ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Հետ"</string>
     <string name="handle_text" msgid="4419667835599523257">"Հավելվածի կեղծանուն"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Հավելվածի պատկերակ"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ձգել պատուհանը դեպի ձախ"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ձգել պատուհանը դեպի աջ"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Ծավալել կամ վերականգնել պատուհանի չափսը"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Առավելագույնի հասցրեք հավելվածի պատուհանի չափը"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Վերականգնել պատուհանի չափը"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Ծալել հավելվածի պատուհանը"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Փակեք հավելվածի պատուհանը"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Բացել կարգավորումներն ըստ կանխադրման"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Ընտրեք՝ ինչպես բացել այս հավելվածի վեբ հղումները"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Հավելվածում"</string>
diff --git a/libs/WindowManager/Shell/res/values-in/strings.xml b/libs/WindowManager/Shell/res/values-in/strings.xml
index 617f9c9..d658f59 100644
--- a/libs/WindowManager/Shell/res/values-in/strings.xml
+++ b/libs/WindowManager/Shell/res/values-in/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kiri 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kiri 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Layar penuh di kanan"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Tukar aplikasi atas dengan aplikasi bawah"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Tukar aplikasi kiri dengan aplikasi kanan"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Layar penuh di atas"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Atas 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Atas 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Mulai ulang"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Jangan tampilkan lagi"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Ketuk dua kali untuk\nmemindahkan aplikasi ini"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimalkan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Pulihkan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimalkan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Tutup <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Kembali"</string>
     <string name="handle_text" msgid="4419667835599523257">"Penanganan aplikasi"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikon Aplikasi"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ubah ukuran jendela ke kiri"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ubah ukuran jendela ke kanan"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimalkan atau pulihkan ukuran jendela"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimalkan ukuran jendela aplikasi"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Pulihkan ukuran jendela"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimalkan jendela aplikasi"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Tutup jendela aplikasi"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Buka dengan setelan default"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Pilih cara membuka link web untuk aplikasi ini"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Di aplikasi"</string>
diff --git a/libs/WindowManager/Shell/res/values-is/strings.xml b/libs/WindowManager/Shell/res/values-is/strings.xml
index 797a4cc..f7b78d2 100644
--- a/libs/WindowManager/Shell/res/values-is/strings.xml
+++ b/libs/WindowManager/Shell/res/values-is/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vinstri 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vinstri 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Hægri á öllum skjánum"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Víxla efsta og neðsta forriti"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Víxla hægra og vinstra forriti"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Efri á öllum skjánum"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Efri 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Efri 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Endurræsa"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ekki sýna þetta aftur"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Ýttu tvisvar til\nað færa þetta forrit"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Stækka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Endurheimta <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minnka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Loka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Til baka"</string>
     <string name="handle_text" msgid="4419667835599523257">"Handfang forrits"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Tákn forrits"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Breyta stærð glugga til vinstri"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Breyta stærð glugga til hægri"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Hámarka eða endurheimta stærð glugga"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Hámarka stærð forritsglugga"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Endurheimta gluggastærð"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Lágmarka stærð forritsglugga"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Loka forritsglugga"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Stillingar sjálfvirkrar opnunar"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Veldu hvernig veftenglar opnast í forritinu"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Í forritinu"</string>
diff --git a/libs/WindowManager/Shell/res/values-it/strings.xml b/libs/WindowManager/Shell/res/values-it/strings.xml
index 85f0f8c..a2787a7 100644
--- a/libs/WindowManager/Shell/res/values-it/strings.xml
+++ b/libs/WindowManager/Shell/res/values-it/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Schermata sinistra al 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Schermata sinistra al 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Schermata destra a schermo intero"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Scambia l\'app in alto con quella in basso"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Scambia l\'app di sinistra con quella di destra"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Schermata superiore a schermo intero"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Schermata superiore al 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Schermata superiore al 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Riavvia"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Non mostrare più"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tocca due volte per\nspostare questa app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Ingrandisci <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Ripristina <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Riduci a icona <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Chiudi <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Indietro"</string>
     <string name="handle_text" msgid="4419667835599523257">"Punto di manipolazione app"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icona dell\'app"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ridimensiona la finestra a sinistra"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ridimensiona la finestra a destra"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Ingrandisci o ripristina le dimensioni della finestra"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Ingrandisci le dimensioni della finestra dell\'app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Ripristina le dimensioni della finestra"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Riduci a icona la finestra dell\'app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Chiudi finestra dell\'app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Apri in base alle impostazioni predefinite"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Scegli come aprire i link web per questa app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"All\'interno dell\'app"</string>
diff --git a/libs/WindowManager/Shell/res/values-ja/strings.xml b/libs/WindowManager/Shell/res/values-ja/strings.xml
index 3a12680..d68581b 100644
--- a/libs/WindowManager/Shell/res/values-ja/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ja/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"左 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"右全画面"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"上下のアプリを入れ替える"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"左右のアプリを入れ替える"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"上部全画面"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"上 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"上 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"再起動"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"次回から表示しない"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ダブルタップすると\nこのアプリを移動できます"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」を最大化する"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」を元に戻す"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」を最小化する"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"「<xliff:g id="APP_NAME">%1$s</xliff:g>」を閉じる"</string>
     <string name="back_button_text" msgid="1469718707134137085">"戻る"</string>
     <string name="handle_text" msgid="4419667835599523257">"アプリハンドル"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"アプリのアイコン"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ウィンドウを左側にサイズ変更する"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ウィンドウを右側にサイズ変更する"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ウィンドウを最大化する、またはウィンドウを元のサイズに戻す"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"アプリ ウィンドウを最大化する"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ウィンドウを元のサイズに戻す"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"アプリ ウィンドウを最小化する"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"アプリ ウィンドウを閉じる"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"デフォルトの設定で開く"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"このアプリのウェブリンクを開く方法を選択"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"アプリ内"</string>
diff --git a/libs/WindowManager/Shell/res/values-ka/strings.xml b/libs/WindowManager/Shell/res/values-ka/strings.xml
index 2fbe1a7..369c019 100644
--- a/libs/WindowManager/Shell/res/values-ka/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ka/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"მარცხენა ეკრანი — 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"მარცხენა ეკრანი — 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"მარჯვენა ნაწილის სრულ ეკრანზე გაშლა"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ზედა და ქვედა აპების მდებარეობის გაცვლა"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"მარცხენა და მარჯვენა აპების მდებარეობის გაცვლა"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ზედა ნაწილის სრულ ეკრანზე გაშლა"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ზედა ეკრანი — 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ზედა ეკრანი — 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"გადატვირთვა"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"აღარ გამოჩნდეს"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ამ აპის გადასატანად\nორმაგად შეეხეთ მას"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის მაქსიმალურად გაშლა"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის აღდგენა"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის ჩაკეცვა"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g>-ის დახურვა"</string>
     <string name="back_button_text" msgid="1469718707134137085">"უკან"</string>
     <string name="handle_text" msgid="4419667835599523257">"აპის იდენტიფიკატორი"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"აპის ხატულა"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ფანჯრის ზომის შეცვლა მარცხნივ"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ფანჯრის ზომის შეცვლა მარჯვნივ"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ფანჯრის მაქსიმალურ ზომამდე გაზრდა ან აღდგენა"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"აპის ფანჯრის მაქსიმალურ ზომამდე გაზრდა"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ფანჯრის ზომის აღდგენა"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"აპის ფანჯრის ზომის შემცირება"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"აპის ფანჯრის დახურვა"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"პარამეტრების ნაგულისხმევად გახსნა"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ამ აპისთვის ვებ ბმულების გახსნის წესის არჩევა"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"აპში"</string>
diff --git a/libs/WindowManager/Shell/res/values-kk/strings.xml b/libs/WindowManager/Shell/res/values-kk/strings.xml
index c494b16..1de32d4a 100644
--- a/libs/WindowManager/Shell/res/values-kk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kk/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% сол жақта"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% сол жақта"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Оң жағын толық экранға шығару"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Жоғарыдағы қолданбаны төмендегімен орнын ауыстыру"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Сол жақтағы қолданбаны оң жақтағымен орнын ауыстыру"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Жоғарғы жағын толық экранға шығару"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% жоғарғы жақта"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% жоғарғы жақта"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Өшіріп қосу"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Қайта көрсетілмесін"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Бұл қолданбаны басқа орынға\nжылжыту үшін екі рет түртіңіз."</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын ұлғайту"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын қалпына келтіру"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын кішірейту"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> қолданбасын жабу"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Артқа"</string>
     <string name="handle_text" msgid="4419667835599523257">"Қолданба идентификаторы"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Қолданба белгішесі"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Терезе өлшемін сол жаққа өзгерту"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Терезе өлшемін оң жаққа өзгерту"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Терезе өлшемін ұлғайту не қалпына келтіру"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Қолданба терезесінің өлшемін ұлғайту"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Терезе өлшемін қалпына келтіру"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Қолданба терезесін кішірейту"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Қолданба терезесін жабу"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Әдепкісінше ашу параметрлері"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Осы қолданбадағы веб-сілтемелерді ашу жолын таңдаңыз"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Қолданбада"</string>
diff --git a/libs/WindowManager/Shell/res/values-km/strings.xml b/libs/WindowManager/Shell/res/values-km/strings.xml
index 234c355..6c7faf1 100644
--- a/libs/WindowManager/Shell/res/values-km/strings.xml
+++ b/libs/WindowManager/Shell/res/values-km/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ឆ្វេង 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ឆ្វេង 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"អេក្រង់ពេញខាងស្តាំ"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ប្ដូរកម្មវិធីខាងលើគេទៅខាងក្រោម"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ប្ដូរកម្មវិធីខាងឆ្វេងទៅខាងស្ដាំ"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"អេក្រង់ពេញខាងលើ"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ខាងលើ 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ខាងលើ 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ចាប់ផ្ដើម​ឡើង​វិញ"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"កុំ​បង្ហាញ​ម្ដង​ទៀត"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ចុចពីរដងដើម្បី\nផ្លាស់ទីកម្មវិធីនេះ"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"ពង្រីក <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"ស្ដារ <xliff:g id="APP_NAME">%1$s</xliff:g> ឡើងវិញ"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"បង្រួម <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"បិទ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ថយក្រោយ"</string>
     <string name="handle_text" msgid="4419667835599523257">"ឈ្មោះអ្នកប្រើប្រាស់កម្មវិធី"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"រូប​កម្មវិធី"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ប្ដូរទំហំវិនដូទៅឆ្វេង"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ប្ដូរទំហំវិនដូទៅស្ដាំ"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ស្ដារ ឬបង្កើនទំហំវិនដូជាអតិបរមា"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ពង្រីកទំហំវិនដូកម្មវិធី"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ស្ដារទំហំវិនដូ"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"បង្រួមវិនដូកម្មវិធី"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"បិទវិនដូកម្មវិធី"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ការកំណត់បើកតាមលំនាំដើម"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ជ្រើសរើសរបៀបបើកតំណបណ្ដាញសម្រាប់កម្មវិធីនេះ"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"នៅក្នុងកម្មវិធី"</string>
diff --git a/libs/WindowManager/Shell/res/values-kn/strings.xml b/libs/WindowManager/Shell/res/values-kn/strings.xml
index 61ee3c3..6a9e07f 100644
--- a/libs/WindowManager/Shell/res/values-kn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-kn/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% ಎಡಕ್ಕೆ"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% ಎಡಕ್ಕೆ"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ಬಲ ಫುಲ್ ಸ್ಕ್ರೀನ್"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ಮೇಲಿನ ಮತ್ತು ಕೆಳಗಿನ ಆ್ಯಪ್‌ಗಳನ್ನು ಅದಲು-ಬದಲು ಮಾಡಿ"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ಎಡ ಮತ್ತು ಬಲದ ಆ್ಯಪ್‌ಗಳನ್ನು ಅದಲು-ಬದಲು ಮಾಡಿ"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ಮೇಲಿನ ಫುಲ್ ಸ್ಕ್ರೀನ್"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% ಮೇಲಕ್ಕೆ"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% ಮೇಲಕ್ಕೆ"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ಮರುಪ್ರಾರಂಭಿಸಿ"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ಮತ್ತೊಮ್ಮೆ ತೋರಿಸಬೇಡಿ"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ಈ ಆ್ಯಪ್ ಅನ್ನು ಸರಿಸಲು\nಡಬಲ್-ಟ್ಯಾಪ್ ಮಾಡಿ"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಮರುಸ್ಥಾಪಿಸಿ"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಮಿನಿಮೈಸ್ ಮಾಡಿ"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> ಅನ್ನು ಮುಚ್ಚಿ"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ಹಿಂದಕ್ಕೆ"</string>
     <string name="handle_text" msgid="4419667835599523257">"ಆ್ಯಪ್ ಹ್ಯಾಂಡಲ್"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ಆ್ಯಪ್ ಐಕಾನ್"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ಮರುಗಾತ್ರಗೊಳಿಸಿ ವಿಂಡೋವನ್ನು ಎಡಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ಮರುಗಾತ್ರಗೊಳಿಸಿ ವಿಂಡೋವನ್ನು ಬಲಕ್ಕೆ ಸರಿಸಿ"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ವಿಂಡೋ ಗಾತ್ರವನ್ನು ಗರಿಷ್ಠಗೊಳಿಸಿ ಅಥವಾ ಮರುಸ್ಥಾಪಿಸಿ"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ಆ್ಯಪ್ ವಿಂಡೋದ ಗಾತ್ರವನ್ನು ಮ್ಯಾಕ್ಸಿಮೈಸ್ ಮಾಡಿ"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ವಿಂಡೋ ಗಾತ್ರವನ್ನು ಮರುಸ್ಥಾಪಿಸಿ"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ಆ್ಯಪ್ ವಿಂಡೋವನ್ನು ಮಿನಿಮೈಸ್ ಮಾಡಿ"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ಆ್ಯಪ್ ವಿಂಡೋವನ್ನು ಮುಚ್ಚಿರಿ"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ಡೀಫಾಲ್ಟ್ ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಂದ ತೆರೆಯಿರಿ"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ಈ ಆ್ಯಪ್‌ಗೆ ವೆಬ್ ಲಿಂಕ್‌ಗಳನ್ನು ಹೇಗೆ ತೆರೆಯಬೇಕು ಎಂಬುದನ್ನು ಆಯ್ಕೆಮಾಡಿ"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ಆ್ಯಪ್‌ನಲ್ಲಿ"</string>
diff --git a/libs/WindowManager/Shell/res/values-ko/strings.xml b/libs/WindowManager/Shell/res/values-ko/strings.xml
index 2b36ba1..e94d889 100644
--- a/libs/WindowManager/Shell/res/values-ko/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ko/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"왼쪽 화면 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"왼쪽 화면 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"오른쪽 화면 전체화면"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"상단 앱과 하단 앱 바꾸기"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"왼쪽 앱과 오른쪽 앱 바꾸기"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"위쪽 화면 전체화면"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"위쪽 화면 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"위쪽 화면 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"다시 시작"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"다시 표시 안함"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"두 번 탭하여\n이 앱 이동"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> 최대화"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> 복원"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> 최소화"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> 닫기"</string>
     <string name="back_button_text" msgid="1469718707134137085">"뒤로"</string>
     <string name="handle_text" msgid="4419667835599523257">"앱 핸들"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"앱 아이콘"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"창 크기 왼쪽으로 조절"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"창 크기 오른쪽으로 조절"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"창 최대화 또는 크기 복원"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"앱 창 크기 최대화"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"창 크기 복원"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"앱 창 최소화"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"앱 창 닫기"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"기본값으로 열기 설정"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"이 앱에서 웹 링크를 여는 방법을 선택하세요"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"앱에서"</string>
diff --git a/libs/WindowManager/Shell/res/values-ky/strings.xml b/libs/WindowManager/Shell/res/values-ky/strings.xml
index bb3c2fd..73e7436 100644
--- a/libs/WindowManager/Shell/res/values-ky/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ky/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Сол жактагы экранды 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Сол жактагы экранды 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Оң жактагы экранды толук экран режимине өткөрүү"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Өйдө жактагы колдонмону ылдый жактагы менен алмаштыруу"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Сол жактагы колдонмону оң жактагы менен алмаштыруу"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Үстүнкү экранды толук экран режимине өткөрүү"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Үстүнкү экранды 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Үстүнкү экранды 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Өчүрүп күйгүзүү"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Экинчи көрүнбөсүн"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Бул колдонмону жылдыруу үчүн\nэки жолу таптаңыз"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> чоңойтуу"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> калыбына келтирүү"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> кичирейтүү"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> жабуу"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Артка"</string>
     <string name="handle_text" msgid="4419667835599523257">"Колдонмонун маркери"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Колдонмонун сүрөтчөсү"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Терезенин өлчөмүн солго өзгөртүү"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Терезенин өлчөмүн оңго өзгөртүү"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Терезенин өлчөмүн чоңойтуу же калыбына келтирүү"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Колдонмонун терезесинин өлчөмүн чоңойтуу"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Колдонмонун терезесинин өлчөмүн калыбына келтирүү"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Колдонмонун терезесин кичирейтүү"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Колдонмонун терезесин жабуу"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Демейки шартта ачылуучу шилтемелердин параметрлери"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Колдонмодо шилтемелер кантип ачыларын тандаңыз"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Колдонмодо"</string>
diff --git a/libs/WindowManager/Shell/res/values-lo/strings.xml b/libs/WindowManager/Shell/res/values-lo/strings.xml
index 8850923..fd47465 100644
--- a/libs/WindowManager/Shell/res/values-lo/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lo/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ຊ້າຍ 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ຊ້າຍ 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ເຕັມໜ້າຈໍຂວາ"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ສະຫຼັບແອັບທາງເທິງກັບທາງລຸ່ມ"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ສະຫຼັບແອັບທາງຊ້າຍກັບທາງຂວາ"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ເຕັມໜ້າຈໍເທິງສຸດ"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ເທິງສຸດ 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ເທິງສຸດ 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ຣີສະຕາດ"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ບໍ່ຕ້ອງສະແດງອີກ"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ແຕະສອງເທື່ອເພື່ອ\nຍ້າຍແອັບນີ້"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"ຂະຫຍາຍ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"ກູ້ຄືນ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"ຫຍໍ້ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"ປິດ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ກັບຄືນ"</string>
     <string name="handle_text" msgid="4419667835599523257">"ຊື່ຜູ້ໃຊ້ແອັບ"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ໄອຄອນແອັບ"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ປັບຂະໜາດໜ້າຈໍໄປທາງຊ້າຍ"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ປັບຂະໜາດໜ້າຈໍໄປທາງຂວາ"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ຂະຫຍາຍ ຫຼື ຄືນຄ່າຂະໜາດໜ້າຈໍ"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ຂະຫຍາຍຂະໜາດໜ້າຈໍແອັບໃຫ້ໃຫຍ່ສຸດ"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ກູ້ຄືນຂະໜາດໜ້າຈໍ"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ຫຍໍ້ໜ້າຈໍແອັບ"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ປິດໜ້າຈໍແອັບ"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ເປີດຕາມການຕັ້ງຄ່າເລີ່ມຕົ້ນ"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ເລືອກວິທີເປີດລິ້ງເວັບສຳລັບແອັບນີ້"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ໃນແອັບ"</string>
diff --git a/libs/WindowManager/Shell/res/values-lt/strings.xml b/libs/WindowManager/Shell/res/values-lt/strings.xml
index 8ed826a..902ef04 100644
--- a/libs/WindowManager/Shell/res/values-lt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lt/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kairysis ekranas 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kairysis ekranas 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Dešinysis ekranas viso ekrano režimu"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Sukeisti viršutiniąją programą su apatiniąja"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Sukeisti kairiąją programą su dešiniąja"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Viršutinis ekranas viso ekrano režimu"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Viršutinis ekranas 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Viršutinis ekranas 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Paleisti iš naujo"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Daugiau neberodyti"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dukart palieskite, kad\nperkeltumėte šią programą"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Padidinti „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Atkurti „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Sumažinti „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Uždaryti „<xliff:g id="APP_NAME">%1$s</xliff:g>“"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Atgal"</string>
     <string name="handle_text" msgid="4419667835599523257">"Programos kreipinys"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Programos piktograma"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pakeisti lango dydį kairėje"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pakeisti lango dydį dešinėje"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Padidinti arba atkurti lango dydį"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Padidinti programos lango dydį"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Atkurti lango dydį"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Sumažinti programos langą"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Uždaryti programos langą"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Atidaryti pagal numatytuosius nustatymus"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Pasirinkite, kaip atidaryti šios programos žiniatinklio nuorodas"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Programoje"</string>
diff --git a/libs/WindowManager/Shell/res/values-lv/strings.xml b/libs/WindowManager/Shell/res/values-lv/strings.xml
index 1227055..b4095df 100644
--- a/libs/WindowManager/Shell/res/values-lv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-lv/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Pa kreisi 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Pa kreisi 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Labā daļa pa visu ekrānu"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Apmainīt vietām lietotni augšpusē ar lietotni apakšpusē"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Apmainīt vietām lietotni kreisajā pusē ar lietotni labajā pusē"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Augšdaļa pa visu ekrānu"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Augšdaļa 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Augšdaļa 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Restartēt"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Vairs nerādīt"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Veiciet dubultskārienu,\nlai pārvietotu šo lietotni"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimizēt lietotni <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Atjaunot lietotni <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizēt lietotni <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Aizvērt lietotni <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Atpakaļ"</string>
     <string name="handle_text" msgid="4419667835599523257">"Lietotnes turis"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Lietotnes ikona"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Mainīt loga lielumu uz kreiso pusi"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Mainīt loga lielumu uz labo pusi"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimizēt vai atjaunot loga lielumu"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimizēt lietotnes loga lielumu"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Atjaunot loga lielumu"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizēt lietotnes logu"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Aizvērt lietotnes logu"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Atvērt pēc noklusējuma iestatījumiem"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Izvēlieties, kā atvērt šajā lietotnē norādītās saites"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Lietotnē"</string>
diff --git a/libs/WindowManager/Shell/res/values-mk/strings.xml b/libs/WindowManager/Shell/res/values-mk/strings.xml
index eb51374..be97489 100644
--- a/libs/WindowManager/Shell/res/values-mk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mk/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левиот 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Левиот 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Десниот на цел екран"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Заменете ги местата на горната и долната апликација"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Заменете ги местата на левата и десната апликација"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Горниот на цел екран"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Горниот 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горниот 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартирај"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Не прикажувај повторно"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Допрете двапати за да ја\nпоместите апликацијава"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Максимизирај <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Врати <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Минимизирај <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Затвори <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
     <string name="handle_text" msgid="4419667835599523257">"Прекар на апликацијата"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Икона на апликацијата"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Променете ја големината на прозорецот налево"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Променете ја големината на прозорецот надесно"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Максимизирајте или вратете ја големината на прозорецот"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Максимизирај ја големината на прозорецот на апликацијата"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Врати ја големината на прозорецот"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Минимизирај го прозорецот на апликацијата"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Затвори го прозорецот на апликацијата"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Отвори според стандардните поставки"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Изберете како да се отвораат линковите за апликацијава"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Во апликацијата"</string>
diff --git a/libs/WindowManager/Shell/res/values-ml/strings.xml b/libs/WindowManager/Shell/res/values-ml/strings.xml
index c48cbce..cb84dec8 100644
--- a/libs/WindowManager/Shell/res/values-ml/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ml/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ഇടത് 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ഇടത് 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"വലത് പൂർണ്ണ സ്ക്രീൻ"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"മുകളിലെയും താഴത്തെയും ആപ്പ് സ്വാപ്പ് ചെയ്യുക"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ഇടതുവശത്തെയും വലതുവശത്തെയും ആപ്പ് സ്വാപ്പ് ചെയ്യുക"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"മുകളിൽ പൂർണ്ണ സ്ക്രീൻ"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"മുകളിൽ 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"മുകളിൽ 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"റീസ്റ്റാർട്ട് ചെയ്യൂ"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"വീണ്ടും കാണിക്കരുത്"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ഈ ആപ്പ് നീക്കാൻ\nഡബിൾ ടാപ്പ് ചെയ്യുക"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> പരമാവധിയാക്കുക"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> പുനഃസ്ഥാപിക്കുക"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> ചുരുക്കുക"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> അടയ്ക്കുക"</string>
     <string name="back_button_text" msgid="1469718707134137085">"മടങ്ങുക"</string>
     <string name="handle_text" msgid="4419667835599523257">"ആപ്പ് ഹാൻഡിൽ"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ആപ്പ് ഐക്കൺ"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ഇടത്തേക്ക് ആപ്പ് വിൻഡോ വലുപ്പം മാറ്റുക"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"വലത്തേക്ക് ആപ്പ് വിൻഡോ വലുപ്പം മാറ്റുക"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"വിന്‍ഡോ വലുപ്പം വലുതാക്കുക അല്ലെങ്കിൽ പഴയത് പുനഃസ്ഥാപിക്കുക"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ആപ്പ് വിൻഡോ വലുപ്പം പരമാവധിയാക്കുക"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"വിൻഡോ വലുപ്പം പുനഃസ്ഥാപിക്കുക"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ആപ്പ് വിൻഡോ ചുരുക്കുക"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ആപ്പ് വിൻഡോ അടയ്ക്കുക"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ഡിഫോൾട്ട് ക്രമീകരണം ഉപയോഗിച്ച് തുറക്കുക"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ഈ ആപ്പിനായി വെബ് ലിങ്കുകൾ എങ്ങനെ തുറക്കണമെന്ന് തിരഞ്ഞെടുക്കൂ"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ആപ്പിൽ"</string>
diff --git a/libs/WindowManager/Shell/res/values-mn/strings.xml b/libs/WindowManager/Shell/res/values-mn/strings.xml
index fca2f7c..d8efd8b 100644
--- a/libs/WindowManager/Shell/res/values-mn/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mn/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Зүүн 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Зүүн 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Баруун талын бүтэн дэлгэц"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Дээд талын аппыг доод талынхаар солих"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Зүүн талын аппыг баруун талынхаар солих"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Дээд талын бүтэн дэлгэц"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Дээд 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Дээд 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Дахин эхлүүлэх"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Дахиж бүү харуул"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Энэ аппыг зөөхийн тулд\nхоёр товшино уу"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г томруулах"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г сэргээх"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г жижгэрүүлэх"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g>-г хаах"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Буцах"</string>
     <string name="handle_text" msgid="4419667835599523257">"Аппын бариул"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Aппын дүрс тэмдэг"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Цонхны хэмжээг зүүн тал руу өөрчлөх"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Цонхны хэмжээг баруун тал руу өөрчлөх"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Цонхны хэмжээг томруулах эсвэл сэргээх"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Аппын цонхны хэмжээг томруулах"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Цонхны хэмжээг сэргээх"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Аппын цонхыг жижгэрүүлэх"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Аппын цонхыг хаах"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Өгөгдмөл тохиргоогоор нээх"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Энэ аппад веб холбоосыг хэрхэн нээхийг сонгоно уу"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Аппад"</string>
diff --git a/libs/WindowManager/Shell/res/values-mr/strings.xml b/libs/WindowManager/Shell/res/values-mr/strings.xml
index 8881187..d09a784 100644
--- a/libs/WindowManager/Shell/res/values-mr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-mr/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"डावी 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"डावी 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"उजवी फुल स्क्रीन"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"सर्वात वरचे अ‍ॅप हे तळाशी असलेल्या अ‍ॅपने स्वॅप करा"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"डावीकडील अ‍ॅप हे उजवीकडील अ‍ॅपने स्वॅप करा"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"शीर्ष फुल स्क्रीन"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"शीर्ष 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"शीर्ष 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"रीस्टार्ट करा"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"पुन्हा दाखवू नका"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"हे ॲप हलवण्यासाठी\nदोनदा टॅप करा"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> मोठे करा"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> रिस्टोअर करा"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> लहान करा"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> बंद करा"</string>
     <string name="back_button_text" msgid="1469718707134137085">"मागे जा"</string>
     <string name="handle_text" msgid="4419667835599523257">"अ‍ॅपचे हँडल"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"अ‍ॅप आयकन"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"अ‍ॅप विंडोचा डावीकडे आकार बदला"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"अ‍ॅप विंडोचा उजवीकडे आकार बदला"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विंडोचा आकार मोठा करा किंवा रिस्टोअर करा"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"अ‍ॅप विंडोचा आकार मोठा करा"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"विंडोचा आकार रिस्टोअर करा"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"अ‍ॅप विंडो लहान करा"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"अ‍ॅप विंडो बंद करा"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"बाय डीफॉल्ट सेटिंग्ज उघडा"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"या अ‍ॅपसाठीच्या वेब लिंक कशा उघडाव्यात हे निवडा"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ॲपमध्ये"</string>
diff --git a/libs/WindowManager/Shell/res/values-ms/strings.xml b/libs/WindowManager/Shell/res/values-ms/strings.xml
index f0cd560..e954b0f 100644
--- a/libs/WindowManager/Shell/res/values-ms/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ms/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kiri 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kiri 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Skrin penuh kanan"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Tukar apl bahagian atas dengan apl bahagian bawah"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Tukar apl sebelah kiri dengan apl sebelah kanan"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Skrin penuh atas"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Atas 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Atas 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Mulakan semula"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Jangan tunjukkan lagi"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Ketik dua kali untuk\nalih apl ini"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimumkan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Pulihkan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimumkan <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Tutup <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Kembali"</string>
     <string name="handle_text" msgid="4419667835599523257">"Pengendalian apl"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikon Apl"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ubah saiz tetingkap ke sebelah kiri"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ubah saiz tetingkap ke sebelah kanan"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimumkan atau pulihkan saiz tetingkap"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimumkan saiz tetingkap apl"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Pulihkan saiz tetingkap"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimumkan tetingkap apl"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Tutup tetingkap apl"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Buka tetapan secara lalai"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Pilih cara membuka pautan web untuk apl ini"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Pada apl"</string>
diff --git a/libs/WindowManager/Shell/res/values-my/strings.xml b/libs/WindowManager/Shell/res/values-my/strings.xml
index 3451701..2342564 100644
--- a/libs/WindowManager/Shell/res/values-my/strings.xml
+++ b/libs/WindowManager/Shell/res/values-my/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ဘယ်ဘက် မျက်နှာပြင် ၅၀%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ဘယ်ဘက် မျက်နှာပြင် ၃၀%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ညာဘက် မျက်နှာပြင်အပြည့်"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"အပေါ်အက်ပ်ကို အောက်သို့ ပြောင်းရန်"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ဘယ်ဘက်အက်ပ်ကို ညာဘက်သို့ ပြောင်းရန်"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"အပေါ်ဘက် မျက်နှာပြင်အပြည့်"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"အပေါ်ဘက် မျက်နှာပြင် ၇၀%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"အပေါ်ဘက် မျက်နှာပြင် ၅၀%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ပြန်စရန်"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"နောက်ထပ်မပြပါနှင့်"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ဤအက်ပ်ကို ရွှေ့ရန်\nနှစ်ချက်တို့ပါ"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> ချဲ့ရန်"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> ကို ပြန်ယူရန်"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> ချုံ့ရန်"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> ပိတ်ရန်"</string>
     <string name="back_button_text" msgid="1469718707134137085">"နောက်သို့"</string>
     <string name="handle_text" msgid="4419667835599523257">"အက်ပ်သုံးသူအမည်"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"အက်ပ်သင်္ကေတ"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ဝင်းဒိုးကို ဘယ်ဘက်သို့ အရွယ်ပြင်ရန်"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ဝင်းဒိုးကို ညာဘက်သို့ အရွယ်ပြင်ရန်"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ဝင်းဒိုးအရွယ်အစားကို ချဲ့ရန် (သို့) ပြန်ပြောင်းရန်"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"အက်ပ်ဝင်းဒိုး အရွယ်အစားကို ချဲ့ရန်"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ဝင်းဒိုးအရွယ်အစား ပြန်ပြောင်းရန်"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"အက်ပ်ဝင်းဒိုးကို ချုံ့ရန်"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"အက်ပ်ဝင်းဒိုးကို ပိတ်ရန်"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"မူရင်းဆက်တင်ဖြင့် ဖွင့်ရန်"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ဤအက်ပ်အတွက် ဝဘ်လင့်ခ်များ မည်သို့ဖွင့်မည်ကို ရွေးပါ"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"အက်ပ်တွင်"</string>
diff --git a/libs/WindowManager/Shell/res/values-nb/strings.xml b/libs/WindowManager/Shell/res/values-nb/strings.xml
index 3a4100c..fb61a10 100644
--- a/libs/WindowManager/Shell/res/values-nb/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nb/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Sett størrelsen på den venstre delen av skjermen til 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Sett størrelsen på den venstre delen av skjermen til 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Utvid den høyre delen av skjermen til hele skjermen"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Bytt om på den øvre og nedre appen"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Bytt om på venstre og høyre app"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Utvid den øverste delen av skjermen til hele skjermen"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Sett størrelsen på den øverste delen av skjermen til 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Sett størrelsen på den øverste delen av skjermen til 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Start på nytt"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ikke vis dette igjen"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dobbelttrykk for\nå flytte denne appen"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Gjenopprett <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimer <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Lukk <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Tilbake"</string>
     <string name="handle_text" msgid="4419667835599523257">"Apphåndtak"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Endre størrelsen på vinduet til venstre"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Endre størrelsen på vinduet til høyre"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimer eller gjenopprett størrelsen på vinduet"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimer størrelsen på appvinduet"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Gjenopprett vindusstørrelsen"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimer appvinduet"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Lukk appvinduet"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Innstillinger for åpning som standard"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Velg hvordan nettlinker skal åpnes for denne appen"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string>
diff --git a/libs/WindowManager/Shell/res/values-ne/strings.xml b/libs/WindowManager/Shell/res/values-ne/strings.xml
index cc31e38..fdfa227 100644
--- a/libs/WindowManager/Shell/res/values-ne/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ne/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"बायाँ भाग ५०%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"बायाँ भाग ३०%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"दायाँ भाग फुल स्क्रिन"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"सिरान र पुछारको एप अदलबदल गर्नुहोस्"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"दायाँ र बायाँतिरको एप अदलबदल गर्नुहोस्"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"माथिल्लो भाग फुल स्क्रिन"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"माथिल्लो भाग ७०%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"माथिल्लो भाग ५०%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"रिस्टार्ट गर्नुहोस्"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"फेरि नदेखाउनुहोस्"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"यो एप सार्न डबल\nट्याप गर्नुहोस्"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> म्याक्सिमाइज गर्नुहोस्"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> रिस्टोर गर्नुहोस्"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> मिनिमाइज गर्नुहोस्"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> बन्द गर्नुहोस्"</string>
     <string name="back_button_text" msgid="1469718707134137085">"पछाडि"</string>
     <string name="handle_text" msgid="4419667835599523257">"एपको ह्यान्डल"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"एपको आइकन"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"विन्डोको आकार बदलेर बायाँतिर लैजानुहोस्"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"विन्डोको आकार बदलेर दायाँतिर लैजानुहोस्"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"विन्डोको आकार म्याक्सिमाइज गर्नुहोस् वा रिस्टोर गर्नुहोस्"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"एपको विन्डोको आकार म्याक्सिमाइज गर्नुहोस्"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"विन्डोको आकार रिस्टोर गर्नुहोस्"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"एपको विन्डो मिनिमाइज गर्नुहोस्"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"एपको विन्डो बन्द गर्नुहोस्"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"डिफल्ट सेटिङअनुसार खोल्नुहोस्"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"यो एपका वेब लिंकहरू खोल्ने तरिका छनौट गर्नुहोस्"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"एपमा"</string>
diff --git a/libs/WindowManager/Shell/res/values-nl/strings.xml b/libs/WindowManager/Shell/res/values-nl/strings.xml
index 4234ddf..578877c 100644
--- a/libs/WindowManager/Shell/res/values-nl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-nl/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Linkerscherm 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Linkerscherm 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Rechterscherm op volledig scherm"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Apps bovenaan en onderaan omwisselen"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Apps links en rechts omwisselen"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Bovenste scherm op volledig scherm"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Bovenste scherm 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Bovenste scherm 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Opnieuw opstarten"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Niet opnieuw tonen"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dubbeltik om\ndeze app te verplaatsen"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> maximaliseren"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> herstellen"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> minimaliseren"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> sluiten"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Terug"</string>
     <string name="handle_text" msgid="4419667835599523257">"App-handgreep"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"App-icoon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Formaat van venster naar links aanpassen"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Formaat van venster naar rechts aanpassen"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Formaat van venster maximaliseren of herstellen"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Formaat van app-venster maximaliseren"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Vensterformaat herstellen"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"App-venster minimaliseren"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"App-venster sluiten"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Instellingen voor Standaard openen"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Kies hoe je weblinks voor deze app wilt openen"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"In de app"</string>
diff --git a/libs/WindowManager/Shell/res/values-or/strings.xml b/libs/WindowManager/Shell/res/values-or/strings.xml
index 6390d37..62ee4a0 100644
--- a/libs/WindowManager/Shell/res/values-or/strings.xml
+++ b/libs/WindowManager/Shell/res/values-or/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ବାମ ପଟକୁ 50% କରନ୍ତୁ"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ବାମ ପଟେ 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ଡାହାଣ ପଟକୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍ କରନ୍ତୁ"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ବଟମ ସହ ଟପକୁ ଆପ ସ୍ବାପ କରନ୍ତୁ"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ଡାହାଣ ସହ ବାମକୁ ଆପ ସ୍ବାପ କରନ୍ତୁ"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ଉପର ଆଡ଼କୁ ପୂର୍ଣ୍ଣ ସ୍କ୍ରୀନ୍‍ କରନ୍ତୁ"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ଉପର ଆଡ଼କୁ 70% କରନ୍ତୁ"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ଉପର ଆଡ଼କୁ 50% କରନ୍ତୁ"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ରିଷ୍ଟାର୍ଟ କରନ୍ତୁ"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ପୁଣି ଦେଖାନ୍ତୁ ନାହିଁ"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ଏହି ଆପକୁ ମୁଭ\nକରିବା ପାଇଁ ଦୁଇଥର-ଟାପ କରନ୍ତୁ"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବଡ଼ କରନ୍ତୁ"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> ରିଷ୍ଟୋର କରନ୍ତୁ"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> ଛୋଟ କରନ୍ତୁ"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> ବନ୍ଦ କରନ୍ତୁ"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ପଛକୁ ଫେରନ୍ତୁ"</string>
     <string name="handle_text" msgid="4419667835599523257">"ଆପର ହେଣ୍ଡେଲ"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ଆପ ଆଇକନ"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ବାମପଟକୁ ୱିଣ୍ଡୋ ରିସାଇଜ କରନ୍ତୁ"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ଡାହାଣପଟକୁ ୱିଣ୍ଡୋ ରିସାଇଜ କରନ୍ତୁ"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ୱିଣ୍ଡୋ ସାଇଜକୁ ମେକ୍ସିମାଇଜ କିମ୍ବା ରିଷ୍ଟୋର କରନ୍ତୁ"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ଆପ ଇଣ୍ଡୋ ଆକାର ବଡ଼ କରନ୍ତୁ"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ୱିଣ୍ଡୋ ଆକାର ରିଷ୍ଟୋର କରନ୍ତୁ"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ଆପ ୱିଣ୍ଡୋକୁ ମିନିମାଇଜ କରନ୍ତୁ"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ଆପ ୱିଣ୍ଡୋ ବନ୍ଦ କରନ୍ତୁ"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ଡିଫଲ୍ଟ ସେଟିଂସକୁ ଖୋଲନ୍ତୁ"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ଏହି ଆପ ପାଇଁ ୱେବ ଲିଙ୍କଗୁଡ଼ିକୁ କିପରି ଖୋଲିବେ, ତାହା ବାଛନ୍ତୁ"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ଆପରେ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pa/strings.xml b/libs/WindowManager/Shell/res/values-pa/strings.xml
index d2b837c..4dde6d2 100644
--- a/libs/WindowManager/Shell/res/values-pa/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pa/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ਖੱਬੇ 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ਖੱਬੇ 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"ਸੱਜੇ ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ਸਿਖਰਲੀ ਐਪ ਨੂੰ ਹੇਠਲੀ ਨਾਲ ਬਦਲੋ"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ਖੱਬੀ ਐਪ ਨੂੰ ਸੱਜੀ ਨਾਲ ਬਦਲੋ"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ਉੱਪਰ ਪੂਰੀ ਸਕ੍ਰੀਨ"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ਉੱਪਰ 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ਉੱਪਰ 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ਮੁੜ-ਸ਼ੁਰੂ ਕਰੋ"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ਦੁਬਾਰਾ ਨਾ ਦਿਖਾਓ"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ਇਸ ਐਪ ਦਾ ਟਿਕਾਣਾ ਬਦਲਣ ਲਈ\nਡਬਲ ਟੈਪ ਕਰੋ"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਵੱਡਾ ਕਰੋ"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਮੁੜ-ਬਹਾਲ ਕਰੋ"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਛੋਟਾ ਕਰੋ"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> ਨੂੰ ਬੰਦ ਕਰੋ"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ਪਿੱਛੇ"</string>
     <string name="handle_text" msgid="4419667835599523257">"ਐਪ ਹੈਂਡਲ"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ਐਪ ਪ੍ਰਤੀਕ"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ਵਿੰਡੋ ਦਾ ਆਕਾਰ ਬਦਲ ਕੇ ਖੱਬੇ ਪਾਸੇ ਕਰੋ"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ਵਿੰਡੋ ਦਾ ਆਕਾਰ ਬਦਲ ਕੇ ਸੱਜੇ ਪਾਸੇ ਕਰੋ"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ਵਿੰਡੋ ਦਾ ਆਕਾਰ ਵਧਾਓ ਜਾਂ ਮੁੜ-ਬਹਾਲ ਕਰੋ"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ਐਪ ਵਿੰਡੋ ਦਾ ਆਕਾਰ ਵਧਾਓ"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ਵਿੰਡੋ ਦੇ ਆਕਾਰ ਨੂੰ ਮੁੜ-ਬਹਾਲ ਕਰੋ"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ਐਪ ਵਿੰਡੋ ਨੂੰ ਛੋਟਾ ਕਰੋ"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ਐਪ ਵਿੰਡੋ ਬੰਦ ਕਰੋ"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ਪੂਰਵ-ਨਿਰਧਾਰਿਤ ਸੈਟਿੰਗਾਂ ਮੁਤਾਬਕ ਖੋਲ੍ਹੋ"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ਇਸ ਐਪ ਲਈ ਵੈੱਬ ਲਿੰਕਾਂ ਨੂੰ ਖੋਲ੍ਹਣ ਦਾ ਤਰੀਕਾ ਚੁਣੋ"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ਐਪ ਵਿੱਚ"</string>
diff --git a/libs/WindowManager/Shell/res/values-pl/strings.xml b/libs/WindowManager/Shell/res/values-pl/strings.xml
index 59deb01..50861ba 100644
--- a/libs/WindowManager/Shell/res/values-pl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pl/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% lewej części ekranu"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% lewej części ekranu"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Prawa część ekranu na pełnym ekranie"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Zamień aplikację na górze z tą na dole"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Zamień aplikację po lewej z tą po prawej"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Górna część ekranu na pełnym ekranie"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% górnej części ekranu"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% górnej części ekranu"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Uruchom ponownie"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Nie pokazuj ponownie"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Aby przenieść aplikację,\nkliknij dwukrotnie"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksymalizuj okno aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Przywróć rozmiar okna aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimalizuj okno aplikacji <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zamknij <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Wstecz"</string>
     <string name="handle_text" msgid="4419667835599523257">"Uchwyt aplikacji"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacji"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Zmień rozmiar okna do lewej"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Zmień rozmiar okna do prawej"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Zmaksymalizuj lub przywróć rozmiar okna"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksymalizuj rozmiar okna aplikacji"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Przywróć rozmiar okna"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimalizuj okno aplikacji"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zamknij okno aplikacji"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Ustawienia domyślnego otwierania"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Wybierz, gdzie chcesz otwierać linki z tej aplikacji"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"W aplikacji"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
index 593f830..a8f7403a 100644
--- a/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rBR/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Esquerda a 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Esquerda a 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Lado direito em tela cheia"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Trocar o app de cima pelo de baixo"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Trocar o app da esquerda pelo da direita"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Parte superior em tela cheia"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Parte superior a 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Parte superior a 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar novamente"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toque duas vezes para\nmover o app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Fechar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Voltar"</string>
     <string name="handle_text" msgid="4419667835599523257">"Identificador do app"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionar janela para a esquerda"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionar janela para a direita"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar ou restaurar o tamanho da janela"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizar o tamanho da janela do app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurar o tamanho da janela"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizar janela do app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Fechar janela do app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Configurações \"Abrir por padrão\""</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Escolha como abrir links da Web para este app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"No app"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
index fcf5916..04d40428 100644
--- a/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt-rPT/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"50% no ecrã esquerdo"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"30% no ecrã esquerdo"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ecrã direito inteiro"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Trocar app superior pela inferior"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Trocar app da esquerda pela da direita"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ecrã superior inteiro"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"70% no ecrã superior"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"50% no ecrã superior"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar de novo"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toque duas vezes\npara mover esta app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Fechar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Anterior"</string>
     <string name="handle_text" msgid="4419667835599523257">"Indicador da app"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ícone da app"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionar janela para a esquerda"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionar janela para a direita"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar ou restaurar tamanho da janela"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizar tamanho da janela da app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurar tamanho da janela"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizar janela da app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Fechar janela da app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Definições de Abrir por predefinição"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Escolha como abrir links da Web para esta app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Na app"</string>
diff --git a/libs/WindowManager/Shell/res/values-pt/strings.xml b/libs/WindowManager/Shell/res/values-pt/strings.xml
index 593f830..a8f7403a 100644
--- a/libs/WindowManager/Shell/res/values-pt/strings.xml
+++ b/libs/WindowManager/Shell/res/values-pt/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Esquerda a 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Esquerda a 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Lado direito em tela cheia"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Trocar o app de cima pelo de baixo"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Trocar o app da esquerda pelo da direita"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Parte superior em tela cheia"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Parte superior a 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Parte superior a 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reiniciar"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Não mostrar novamente"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Toque duas vezes para\nmover o app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restaurar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Fechar <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Voltar"</string>
     <string name="handle_text" msgid="4419667835599523257">"Identificador do app"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ícone do app"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionar janela para a esquerda"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionar janela para a direita"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizar ou restaurar o tamanho da janela"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizar o tamanho da janela do app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restaurar o tamanho da janela"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizar janela do app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Fechar janela do app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Configurações \"Abrir por padrão\""</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Escolha como abrir links da Web para este app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"No app"</string>
diff --git a/libs/WindowManager/Shell/res/values-ro/strings.xml b/libs/WindowManager/Shell/res/values-ro/strings.xml
index 81db82a..d781d08 100644
--- a/libs/WindowManager/Shell/res/values-ro/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ro/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Partea stângă: 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Partea stângă: 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Partea dreaptă pe ecran complet"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Schimbă aplicația de sus cu cea de jos"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Schimbă aplicația din stânga cu cea din dreapta"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Partea de sus pe ecran complet"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Partea de sus: 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Partea de sus: 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Repornește"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Nu mai afișa"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Atinge de două ori\nca să muți aplicația"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximizează <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restabilește <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizează <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Închide <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Înapoi"</string>
     <string name="handle_text" msgid="4419667835599523257">"Handle de aplicație"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Pictograma aplicației"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Redimensionează fereastra la stânga"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Redimensionează fereastra la dreapta"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximizează sau restabilește dimensiunea ferestrei"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximizează dimensiunea ferestrei aplicației"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restabilește dimensiunea ferestrei"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizează fereastra aplicației"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Închide fereastra aplicației"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Setări de deschidere în mod prestabilit"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Alege modul de deschidere a linkurilor web pentru aplicație"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"În aplicație"</string>
diff --git a/libs/WindowManager/Shell/res/values-ru/strings.xml b/libs/WindowManager/Shell/res/values-ru/strings.xml
index aa6f484..1837c31 100644
--- a/libs/WindowManager/Shell/res/values-ru/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ru/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Левый на 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Левый на 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Правый во весь экран"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Поменять местами приложения сверху и снизу"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Поменять местами приложения слева и справа"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Верхний во весь экран"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Верхний на 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхний на 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Перезапустить"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Больше не показывать"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Дважды нажмите, чтобы\nпереместить приложение."</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Развернуть окно приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Восстановить окно приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Свернуть окно приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Закрыть окно приложения \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
     <string name="handle_text" msgid="4419667835599523257">"Обозначение приложения"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Значок приложения"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Растянуть окно влево"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Растянуть окно вправо"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Развернуть окно или восстановить его размер"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Развернуть окно приложения"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Восстановить размер окна"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Свернуть окно приложения"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Закрыть окно приложения"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Настройки, регулирующие, как по умолчанию открываются ссылки"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Выберите, где будут открываться ссылки из этого приложения"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"В приложении"</string>
diff --git a/libs/WindowManager/Shell/res/values-si/strings.xml b/libs/WindowManager/Shell/res/values-si/strings.xml
index efa978a..d2fc082 100644
--- a/libs/WindowManager/Shell/res/values-si/strings.xml
+++ b/libs/WindowManager/Shell/res/values-si/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"වම් 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"වම් 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"දකුණු පූර්ණ තිරය"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"ඉහළ යෙදුම පහළ සමග මාරු කරන්න"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"වම් යෙදුම දකුණ සමග මාරු කරන්න"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ඉහළම පූර්ණ තිරය"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ඉහළම 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ඉහළම 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"යළි අරඹන්න"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"නැවත නොපෙන්වන්න"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"මෙම යෙදුම ගෙන යාමට\nදෙවරක් තට්ටු කරන්න"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> විහිදන්න"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> ප්‍රතිසාධනය කරන්න"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> කුඩා කරන්න"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> වසන්න"</string>
     <string name="back_button_text" msgid="1469718707134137085">"ආපසු"</string>
     <string name="handle_text" msgid="4419667835599523257">"යෙදුම් හසුරුව"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"යෙදුම් නිරූපකය"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"කවුළුව වමට ප්‍රතිප්‍රමාණ කරන්න"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"කවුළුව දකුණට ප්‍රතිප්‍රමාණ කරන්න"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"කවුළු ප්‍රමාණය උපරිම කරන්න හෝ ප්‍රතිසාධනය කරන්න"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"යෙදුම් කවුළු ප්‍රමාණය උපරිම කරන්න"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"කවුළු ප්‍රමාණය ප්‍රතිසාධනය කරන්න"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"යෙදුම් කවුළුව අවම කරන්න"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"යෙදුම් කවුළුව වසන්න"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"පෙරනිමි සැකසීම් මඟින් විවෘත කරන්න"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"මෙම යෙදුම සඳහා වෙබ් සබැඳි විවෘත කරන ආකාරය තෝරා ගන්න"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"යෙදුම තුළ"</string>
diff --git a/libs/WindowManager/Shell/res/values-sk/strings.xml b/libs/WindowManager/Shell/res/values-sk/strings.xml
index fac26b4..a9c81a2 100644
--- a/libs/WindowManager/Shell/res/values-sk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sk/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ľavá – 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ľavá – 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Pravá– na celú obrazovku"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Vymeniť hornú aplikáciu za dolnú"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Vymeniť ľavú aplikáciu za pravú"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Horná – na celú obrazovku"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Horná – 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Horná – 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Reštartovať"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Už nezobrazovať"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Túto aplikáciu\npresuniete dvojitým klepnutím"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maximalizovať <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Obnoviť <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimalizovať <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zavrieť <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Späť"</string>
     <string name="handle_text" msgid="4419667835599523257">"Rukoväť aplikácie"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikácie"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Zmeniť veľkosť okna vľavo"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Zmeniť veľkosť okna vpravo"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximalizovať alebo obnoviť veľkosť okna"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximalizovať veľkosť okna aplikácie"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Obnoviť veľkosť okna"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimalizovať okno aplikácie"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zavrieť okno aplikácie"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Otvárať podľa predvolených nastavení"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Vyberte, ako sa majú v tejto aplikácii otvárať webové odkazy"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"V aplikácii"</string>
diff --git a/libs/WindowManager/Shell/res/values-sl/strings.xml b/libs/WindowManager/Shell/res/values-sl/strings.xml
index f8dacc4..8dcca185 100644
--- a/libs/WindowManager/Shell/res/values-sl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sl/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Levi 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Levi 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Desni v celozaslonski način"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Zamenjava zgornje aplikacije s spodnjo"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Zamenjava leve aplikacije z desno"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Zgornji v celozaslonski način"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Zgornji 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Zgornji 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Znova zaženi"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ne prikaži več"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Dvakrat se dotaknite\nza premik te aplikacije"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Povečanje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Obnovitev aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Pomanjšava aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Zapiranje aplikacije <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Nazaj"</string>
     <string name="handle_text" msgid="4419667835599523257">"Identifikator aplikacije"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona aplikacije"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Sprememba velikosti okna na levi"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Sprememba velikosti okna na desni"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Povečava ali obnovitev velikosti okna"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Povečanje velikosti okna aplikacije"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Obnovitev velikosti okna"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Pomanjšava okna aplikacije"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Zapiranje okna aplikacije"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Nastavitve privzetega odpiranja"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Izberite način odpiranja spletnih povezav za to aplikacijo"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"V aplikaciji"</string>
diff --git a/libs/WindowManager/Shell/res/values-sq/strings.xml b/libs/WindowManager/Shell/res/values-sq/strings.xml
index c64df85..6f8bdef 100644
--- a/libs/WindowManager/Shell/res/values-sq/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sq/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Majtas 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Majtas 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Ekrani i plotë djathtas"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Ndërro aplikacionin lart me atë poshtë"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Ndërro aplikacionin majtas me atë djathtas"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Ekrani i plotë lart"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Lart 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Lart 50%"</string>
@@ -115,19 +113,15 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Rinis"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Mos e shfaq përsëri"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Trokit dy herë për të\nlëvizur këtë aplikacion"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Maksimizo \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Restauro \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimizo \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Mbyll \"<xliff:g id="APP_NAME">%1$s</xliff:g>\""</string>
     <string name="back_button_text" msgid="1469718707134137085">"Pas"</string>
     <string name="handle_text" msgid="4419667835599523257">"Emërtimi i aplikacionit"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ikona e aplikacionit"</string>
     <string name="fullscreen_text" msgid="1162316685217676079">"Ekrani i plotë"</string>
-    <string name="desktop_text" msgid="1582173066857454541">"Pamja për desktop"</string>
+    <string name="desktop_text" msgid="1582173066857454541">"Pamja e desktopit"</string>
     <string name="split_screen_text" msgid="1396336058129570886">"Ekrani i ndarë"</string>
     <string name="more_button_text" msgid="3655388105592893530">"Më shumë"</string>
     <string name="float_button_text" msgid="9221657008391364581">"Pluskuese"</string>
@@ -140,7 +134,7 @@
     <string name="change_aspect_ratio_text" msgid="9104456064548212806">"Ndrysho raportin e pamjes"</string>
     <string name="close_text" msgid="4986518933445178928">"Mbyll"</string>
     <string name="collapse_menu_text" msgid="7515008122450342029">"Mbyll menynë"</string>
-    <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Pamja për desktop)"</string>
+    <string name="desktop_mode_app_header_chip_text" msgid="8300164817452574565">"<xliff:g id="APP_NAME">%1$s</xliff:g> (Pamja e desktopit)"</string>
     <string name="desktop_mode_maximize_menu_maximize_text" msgid="3275717276171114411">"Maksimizo ekranin"</string>
     <string name="desktop_mode_maximize_menu_snap_text" msgid="5673738963174074006">"Ndrysho përmasat"</string>
     <string name="desktop_mode_non_resizable_snap_text" msgid="3771776422751387878">"Aplikacioni nuk mund të zhvendoset këtu"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ndrysho përmasat e dritares në të majtë"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ndrysho përmasat e dritares në të djathtë"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maksimizo ose restauro madhësinë e dritares"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maksimizo madhësinë e dritares së aplikacionit"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Restauro madhësinë e dritares"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimizo dritaren e aplikacionit"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Mbyll dritaren e aplikacionit"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Hap sipas cilësimeve të parazgjedhura"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Zgjidh si do t\'i hapësh lidhjet e uebit për këtë aplikacion"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Në aplikacion"</string>
diff --git a/libs/WindowManager/Shell/res/values-sr/strings.xml b/libs/WindowManager/Shell/res/values-sr/strings.xml
index d2462a7..287d34f 100644
--- a/libs/WindowManager/Shell/res/values-sr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sr/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Леви екран 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Леви екран 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Режим целог екрана за доњи екран"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Замените горњу апликацију доњом"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Замените леву апликацију десном"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Режим целог екрана за горњи екран"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Горњи екран 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Горњи екран 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Рестартуј"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Не приказуј поново"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Двапут додирните да бисте\nпреместили ову апликацију"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Увећајте: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Вратите: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Умањите: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Затворите: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
     <string name="handle_text" msgid="4419667835599523257">"Идентификатор апликације"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Икона апликације"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Промените величину прозора налево"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Промените величину прозора надесно"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Увећајте или вратите величину прозора"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Увећајте величину прозора апликације"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Вратите величину прозора"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Умањите прозор апликације"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Затворите прозор апликације"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Подешавање Подразумевано отварај"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Одаберите начин отварања веб-линкова за ову апликацију"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"У апликацији"</string>
diff --git a/libs/WindowManager/Shell/res/values-sv/strings.xml b/libs/WindowManager/Shell/res/values-sv/strings.xml
index 0105e15..d8893df 100644
--- a/libs/WindowManager/Shell/res/values-sv/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sv/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Vänster 50 %"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Vänster 30 %"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Helskärm på höger skärm"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Byt plats på den översta och understa appen"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Byt plats på den vänstra och högra appen"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Helskärm på övre skärm"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Övre 70 %"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Övre 50 %"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Starta om"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Visa inte igen"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Tryck snabbt två gånger\nför att flytta denna app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Utöka <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Återställ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Minimera <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Stäng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Tillbaka"</string>
     <string name="handle_text" msgid="4419667835599523257">"Apphandtag"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Appikon"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Ändra storlek på fönstret åt vänster"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Ändra storlek på fönstret åt höger"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Maximera eller återställ fönsterstorleken"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Maximera appfönstrets storlek"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Återställ fönsterstorlek"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Minimera appfönstret"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Stäng appfönstret"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Inställningar för Öppna som standard"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Välj hur webblänkar ska öppnas för den här appen"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"I appen"</string>
diff --git a/libs/WindowManager/Shell/res/values-sw/strings.xml b/libs/WindowManager/Shell/res/values-sw/strings.xml
index b4415cb..3ee43f3 100644
--- a/libs/WindowManager/Shell/res/values-sw/strings.xml
+++ b/libs/WindowManager/Shell/res/values-sw/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kushoto 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kushoto 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Skrini nzima ya kulia"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Badilisha nafasi ya programu ya juu na ya chini"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Badilisha nafasi ya programu ya kulia na ya kushoto"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Skrini nzima ya juu"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Juu 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Juu 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Zima kisha uwashe"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Usionyeshe tena"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Gusa mara mbili ili\nusogeze programu hii"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Panua <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Rejesha <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Punguza <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Funga <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Rudi nyuma"</string>
     <string name="handle_text" msgid="4419667835599523257">"Utambulisho wa programu"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Aikoni ya Programu"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Badilisha ukubwa wa dirisha kushoto"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Badilisha ukubwa wa dirisha kulia"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Panua au urejeshe ukubwa wa dirisha"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Panua ukubwa wa dirisha la programu"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Rejesha ukubwa wa dirisha"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Punguza dirisha la programu"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Funga dirisha la programu"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Fungua kwa mipangilio chaguomsingi"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Chagua jinsi ya kufungua viungo vya wavuti vya programu hii"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Kwenye programu"</string>
diff --git a/libs/WindowManager/Shell/res/values-ta/strings.xml b/libs/WindowManager/Shell/res/values-ta/strings.xml
index ccc9f94..a0e7c6a 100644
--- a/libs/WindowManager/Shell/res/values-ta/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ta/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"இடது புறம் 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"இடது புறம் 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"வலது புறம் முழுத் திரை"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"மேலுள்ள ஆப்ஸைக் கீழுள்ள ஆப்ஸ் கொண்டு மாற்றும்"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"இடதுபுற ஆப்ஸை வலதுபுற ஆப்ஸ் கொண்டு மாற்றும்"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"மேற்புறம் முழுத் திரை"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"மேலே 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"மேலே 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"மீண்டும் தொடங்கு"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"மீண்டும் காட்டாதே"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"இந்த ஆப்ஸை நகர்த்த\nஇருமுறை தட்டவும்"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸைப் பெரிதாக்கும்"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸை மீட்டெடுக்கும்"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸைச் சிறிதாக்கும்"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> ஆப்ஸை மூடும்"</string>
     <string name="back_button_text" msgid="1469718707134137085">"பின்செல்லும்"</string>
     <string name="handle_text" msgid="4419667835599523257">"ஆப்ஸ் ஹேண்டில்"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ஆப்ஸ் ஐகான்"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"சாளரத்தை இடதுபுறமாக அளவு மாற்றும்"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"சாளரத்தை வலதுபுறமாக அளவு மாற்றும்"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"சாளரத்தின் அளவைப் பெரிதாக்கும்/மீட்டெடுக்கும்"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ஆப்ஸ் சாளரத்தின் அளவைப் பெரிதாக்கும்"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"சாளரத்தின் அளவை மீட்டெடுக்கும்"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ஆப்ஸ் சாளரத்தைச் சிறிதாக்கும்"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ஆப்ஸ் சாளரத்தை மூடும்"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"இயல்பாக அமைப்புகளைத் திறக்கும்"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"இந்த ஆப்ஸில் வலை இணைப்புகளைத் திறக்கும் வழிமுறையைத் தேர்வுசெய்யுங்கள்"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ஆப்ஸில்"</string>
diff --git a/libs/WindowManager/Shell/res/values-te/strings.xml b/libs/WindowManager/Shell/res/values-te/strings.xml
index 96ce40a..e093013 100644
--- a/libs/WindowManager/Shell/res/values-te/strings.xml
+++ b/libs/WindowManager/Shell/res/values-te/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ఎడమవైపు 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ఎడమవైపు 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"కుడివైపు ఫుల్-స్క్రీన్‌"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"పైన ఉన్న యాప్‌ను కింద ఉన్న యాప్‌తో మార్చండి"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"ఎడమ వైపు ఉన్న యాప్‌ను కుడి వైపు ఉన్న యాప్‌తో మార్చండి"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"ఎగువ ఫుల్-స్క్రీన్‌"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ఎగువ 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ఎగువ 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"రీస్టార్ట్ చేయండి"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"మళ్లీ చూపవద్దు"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"ఈ యాప్‌ను తరలించడానికి\nడబుల్-ట్యాప్ చేయండి"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g>ను పెద్దదిగా చేయండి"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g>ను రీస్టోర్ చేయండి"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g>ను చిన్నదిగా చేయండి"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g>‌ను మూసివేయండి"</string>
     <string name="back_button_text" msgid="1469718707134137085">"వెనుకకు"</string>
     <string name="handle_text" msgid="4419667835599523257">"యాప్ హ్యాండిల్"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"యాప్ చిహ్నం"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"విండో ఎడమ వైపునకు సైజ్‌ను మార్చండి"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"విండో కుడి వైపునకు సైజ్‌ను మార్చండి"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"విండో సైజ్‌ను మ్యాగ్జిమైజ్ చేయండి లేదా రీస్టోర్ చేయండి"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"యాప్ విండో సైజ్‌ను పెద్దదిగా చేయండి"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"విండో సైజ్‌ను రీస్టోర్ చేయండి"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"యాప్ విండోను చిన్నదిగా చేయండి"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"యాప్ విండోను మూసివేయండి"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"ఆటోమేటిక్ సెట్టింగ్‌ల ద్వారా తెరవండి"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"ఈ యాప్‌నకు సంబంధించిన వెబ్ లింక్‌లను ఎలా తెరవాలో ఎంచుకోండి"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"యాప్‌లో"</string>
diff --git a/libs/WindowManager/Shell/res/values-th/strings.xml b/libs/WindowManager/Shell/res/values-th/strings.xml
index 16372d2..594ee6c9 100644
--- a/libs/WindowManager/Shell/res/values-th/strings.xml
+++ b/libs/WindowManager/Shell/res/values-th/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"ซ้าย 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"ซ้าย 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"เต็มหน้าจอทางขวา"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"สลับแอปด้านบนกับด้านล่าง"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"สลับแอปด้านซ้ายกับด้านขวา"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"เต็มหน้าจอด้านบน"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"ด้านบน 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"ด้านบน 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"รีสตาร์ท"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"ไม่ต้องแสดงข้อความนี้อีก"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"แตะสองครั้ง\nเพื่อย้ายแอปนี้"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"ขยาย <xliff:g id="APP_NAME">%1$s</xliff:g> ให้ใหญ่สุด"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"คืนค่า <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"ย่อ <xliff:g id="APP_NAME">%1$s</xliff:g> ให้เล็กสุด"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"ปิด <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"กลับ"</string>
     <string name="handle_text" msgid="4419667835599523257">"แฮนเดิลแอป"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ไอคอนแอป"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"ปรับขนาดหน้าต่างไปทางซ้าย"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ปรับขนาดหน้าต่างไปทางขวา"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ขยายหรือคืนค่าขนาดหน้าต่าง"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ขยายขนาดหน้าต่างแอปให้ใหญ่สุด"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"คืนค่าขนาดหน้าต่าง"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ย่อหน้าต่างแอปให้เล็กสุด"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ปิดหน้าต่างแอป"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"เปิดตามการตั้งค่าเริ่มต้น"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"เลือกวิธีเปิดเว็บลิงก์สำหรับแอปนี้"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ในแอป"</string>
diff --git a/libs/WindowManager/Shell/res/values-tl/strings.xml b/libs/WindowManager/Shell/res/values-tl/strings.xml
index ad38be8..f13de5b 100644
--- a/libs/WindowManager/Shell/res/values-tl/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tl/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Gawing 50% ang nasa kaliwa"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Gawing 30% ang nasa kaliwa"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"I-full screen ang nasa kanan"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Pagpalitin ang app sa itaas at ibaba"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Pagpalitin ang app sa kaliwa at kanan"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"I-full screen ang nasa itaas"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Gawing 70% ang nasa itaas"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Gawing 50% ang nasa itaas"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"I-restart"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Huwag nang ipakita ulit"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"I-double tap para\nilipat ang app na ito"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"I-maximize ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"I-restore ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"I-minimize ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Isara ang <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Bumalik"</string>
     <string name="handle_text" msgid="4419667835599523257">"Handle ng app"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Icon ng App"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"I-resize pakaliwa ang window"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"I-resize pakanan ang window"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"I-maximize o i-restore ang laki ng window"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"I-maximize ang laki ng window ng app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"I-restore ang laki ng window"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"I-minimize ang window ng app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Isara ang window ng app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Buksan sa pamamagitan ng mga default na setting"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Piliin kung paano magbukas ng web link para sa app na ito"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Sa app"</string>
diff --git a/libs/WindowManager/Shell/res/values-tr/strings.xml b/libs/WindowManager/Shell/res/values-tr/strings.xml
index 2bc0a96..61fae05 100644
--- a/libs/WindowManager/Shell/res/values-tr/strings.xml
+++ b/libs/WindowManager/Shell/res/values-tr/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Solda %50"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Solda %30"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Sağda tam ekran"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Üstteki uygulamayı alttaki uygulamayla değiştir"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Soldaki uygulamayı sağdakiyle değiştir"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Üstte tam ekran"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Üstte %70"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Üstte %50"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Yeniden başlat"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Bir daha gösterme"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Bu uygulamayı taşımak için\niki kez dokunun"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasını büyüt"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasını geri yükle"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasını küçült"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"<xliff:g id="APP_NAME">%1$s</xliff:g> uygulamasını kapat"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Geri"</string>
     <string name="handle_text" msgid="4419667835599523257">"Uygulama tanıtıcısı"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Uygulama Simgesi"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Pencereyi sola yeniden boyutlandır"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Pencereyi sağa yeniden boyutlandır"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Pencereyi ekranı kaplayacak şekilde büyüt veya önceki boyutuna döndür"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Uygulama penceresini ekranı kaplayacak şekilde büyüt"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Pencere boyutunu geri yükle"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Uygulama penceresini küçült"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Uygulama penceresini kapat"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Varsayılan olarak açma ayarları"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Bu uygulama için web bağlantılarının nasıl açılacağını seçin"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Uygulamada"</string>
diff --git a/libs/WindowManager/Shell/res/values-uk/strings.xml b/libs/WindowManager/Shell/res/values-uk/strings.xml
index c1aa82e..ada82df 100644
--- a/libs/WindowManager/Shell/res/values-uk/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uk/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Ліве вікно на 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Ліве вікно на 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Праве вікно на весь екран"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Поміняти місцями додатки зверху й знизу"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Поміняти місцями додатки ліворуч і праворуч"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Верхнє вікно на весь екран"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Верхнє вікно на 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Верхнє вікно на 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Перезапустити"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Більше не показувати"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Двічі торкніться, щоб\nперемістити цей додаток"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Розгорнути додаток <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Відновити додаток <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Згорнути додаток <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Закрити додаток <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Назад"</string>
     <string name="handle_text" msgid="4419667835599523257">"Дескриптор додатка"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Значок додатка"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Змінити розмір вікна ліворуч"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Змінити розмір вікна праворуч"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Розгорнути вікно або відновити його розмір"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Розгорнути вікно додатка"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Відновити розмір вікна"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Згорнути вікно додатка"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Закрити вікно додатка"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Налаштування \"Відкривати за умовчанням\""</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Виберіть, як відкривати вебпосилання в цьому додатку"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"У додатку"</string>
diff --git a/libs/WindowManager/Shell/res/values-ur/strings.xml b/libs/WindowManager/Shell/res/values-ur/strings.xml
index 1afb48d..ded104c 100644
--- a/libs/WindowManager/Shell/res/values-ur/strings.xml
+++ b/libs/WindowManager/Shell/res/values-ur/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"بائیں %50"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"بائیں %30"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"دائیں فل اسکرین"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"اوپری ایپ کو نیچے کے ساتھ سویپ کریں"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"بائیں ایپ کو دائیں کے ساتھ سویپ کریں"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"بالائی فل اسکرین"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"اوپر %70"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"اوپر %50"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"ری اسٹارٹ کریں"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"دوبارہ نہ دکھائیں"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"اس ایپ کو منتقل کرنے کیلئے\nدو بار تھپتھپائیں"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> بڑا کریں"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> کو بحال کریں"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> چھوٹا کریں"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"‫<xliff:g id="APP_NAME">%1$s</xliff:g> بند کریں"</string>
     <string name="back_button_text" msgid="1469718707134137085">"پیچھے"</string>
     <string name="handle_text" msgid="4419667835599523257">"ایپ ہینڈل"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"ایپ کا آئیکن"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"دائیں طرف ونڈو کا سائز تبدیل کریں"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"ونڈو کا سائز بائیں طرف تبدیل کریں"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"ونڈو کا سائز زیادہ سے زیادہ یا بحال کریں"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"ایپ ونڈو سائز بڑا کریں"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"ونڈو سائز بحال کریں"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"ایپ ونڈو چھوٹا کریں"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"ایپ ونڈو بند کریں"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"بطور ڈیفالٹ ترتیبات کھولیں"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"اس ایپ کے لیے ویب لنکس کھولنے کا طریقہ منتخب کریں"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"ایپ میں"</string>
diff --git a/libs/WindowManager/Shell/res/values-uz/strings.xml b/libs/WindowManager/Shell/res/values-uz/strings.xml
index 04fd429..8a9dad0 100644
--- a/libs/WindowManager/Shell/res/values-uz/strings.xml
+++ b/libs/WindowManager/Shell/res/values-uz/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Chapda 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Chapda 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"O‘ngda to‘liq ekran"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Tepadagi ilovani pastkisi bilan almashtirish"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Chap ilovani oʻngdagisi bilan almashtirish"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Tepada to‘liq ekran"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Tepada 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Tepada 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Qaytadan"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Boshqa chiqmasin"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Bu ilovani siljitish uchun\nikki marta bosing"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Yoyish: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Tiklash: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Kichraytirish: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Yopish: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Orqaga"</string>
     <string name="handle_text" msgid="4419667835599523257">"Ilova identifikatori"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Ilova belgisi"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Oyna oʻlchamini chapga oʻzgartirish"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Oyna oʻlchamini oʻngga oʻzgartirish"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Oyna oʻlchamini kengaytirish yoki asliga qaytarish"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Ilova oynasini kattartirish"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Oyna hajmini tiklash"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Ilova oynasini kichraytirish"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Ilova oynasini yopish"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Birlamchi sozlamalar asosida ochish"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Bu ilovalardagi veb havolalar qanday ochilishini tanlang"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Ilovada"</string>
diff --git a/libs/WindowManager/Shell/res/values-vi/strings.xml b/libs/WindowManager/Shell/res/values-vi/strings.xml
index 169c2b7..d6c8bc6 100644
--- a/libs/WindowManager/Shell/res/values-vi/strings.xml
+++ b/libs/WindowManager/Shell/res/values-vi/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Trái 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Trái 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Toàn màn hình bên phải"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Hoán đổi ứng dụng ở trên cùng với ứng dụng ở dưới cùng"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Hoán đổi ứng dụng bên trái với ứng dụng bên phải"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Toàn màn hình phía trên"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Trên 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Trên 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Khởi động lại"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Không hiện lại"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Nhấn đúp để\ndi chuyển ứng dụng này"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Phóng to <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Khôi phục <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Thu nhỏ <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Đóng <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Quay lại"</string>
     <string name="handle_text" msgid="4419667835599523257">"Ô điều khiển ứng dụng"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Biểu tượng ứng dụng"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Đổi kích thước và chuyển cửa sổ sang trái"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Đổi kích thước và chuyển cửa sổ sang phải"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Phóng to hoặc khôi phục kích thước cửa sổ"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Phóng to kích thước cửa sổ ứng dụng"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Khôi phục kích thước cửa sổ"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Thu nhỏ cửa sổ ứng dụng"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Đóng cửa sổ ứng dụng"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Mở các chế độ cài đặt theo mặc định"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Chọn cách mở đường liên kết trang web cho ứng dụng này"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Trong ứng dụng"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
index 942734a..1009afc 100644
--- a/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rCN/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左侧 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"左侧 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"右侧全屏"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"将顶部应用与底部应用互换"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"将左侧应用与右侧应用互换"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"顶部全屏"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"顶部 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"顶部 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"重启"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"不再显示"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"点按两次\n即可移动此应用"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"将“<xliff:g id="APP_NAME">%1$s</xliff:g>”窗口最大化"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"恢复“<xliff:g id="APP_NAME">%1$s</xliff:g>”窗口大小"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"将“<xliff:g id="APP_NAME">%1$s</xliff:g>”窗口最小化"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"关闭“<xliff:g id="APP_NAME">%1$s</xliff:g>”"</string>
     <string name="back_button_text" msgid="1469718707134137085">"返回"</string>
     <string name="handle_text" msgid="4419667835599523257">"应用手柄"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"应用图标"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"调整窗口大小并贴靠左侧"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"调整窗口大小并贴靠右侧"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"将窗口最大化或恢复大小"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"将应用窗口最大化"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"恢复窗口大小"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"将应用窗口最小化"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"关闭应用窗口"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"默认打开设置"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"选择如何打开此应用中的网页链接"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"在此应用内"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
index f897922..edd67c1 100644
--- a/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rHK/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"左邊 50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"左邊 30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"右邊全螢幕"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"調換上下應用程式"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"調換左右應用程式"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"頂部全螢幕"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"頂部 70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"頂部 50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"重新啟動"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"不要再顯示"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"輕按兩下\n即可移動此應用程式"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"將 <xliff:g id="APP_NAME">%1$s</xliff:g> 放到最大"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"還原 <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"將 <xliff:g id="APP_NAME">%1$s</xliff:g> 縮到最細"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"閂 <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"返去"</string>
     <string name="handle_text" msgid="4419667835599523257">"應用程式控點"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"將視窗移去左邊調整大小"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"將視窗移去右邊調整大小"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"將視窗放到最大或者還原視窗大小"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"將應用程式視窗放到最大"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"還原視窗大細"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"將應用程式視窗縮到最細"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"關閉應用程式視窗"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"採用預設設定打開"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"選擇此應用程式開啟網絡連結的方式"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"在應用程式內"</string>
diff --git a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
index 3c6abec..32d87f3 100644
--- a/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zh-rTW/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"以 50% 的螢幕空間顯示左側畫面"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"以 30% 的螢幕空間顯示左側畫面"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"以全螢幕顯示右側畫面"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"將頂端與底部的應用程式對調"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"將左側與右側的應用程式對調"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"以全螢幕顯示頂端畫面"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"以 70% 的螢幕空間顯示頂端畫面"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"以 50% 的螢幕空間顯示頂端畫面"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"重新啟動"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"不要再顯示"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"輕觸兩下即可\n移動這個應用程式"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"最大化「<xliff:g id="APP_NAME">%1$s</xliff:g>」視窗"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"還原「<xliff:g id="APP_NAME">%1$s</xliff:g>」視窗"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"最小化「<xliff:g id="APP_NAME">%1$s</xliff:g>」視窗"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"關閉「<xliff:g id="APP_NAME">%1$s</xliff:g>」"</string>
     <string name="back_button_text" msgid="1469718707134137085">"返回"</string>
     <string name="handle_text" msgid="4419667835599523257">"應用程式控制代碼"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"應用程式圖示"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"調整應用程式視窗大小並向左貼齊"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"調整應用程式視窗大小並向右貼齊"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"將視窗最大化或還原大小"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"最大化應用程式視窗"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"還原視窗大小"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"最小化應用程式視窗"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"關閉應用程式視窗"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"開啟連結的預設設定"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"選擇如何開啟這個應用程式的網頁連結"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"使用應用程式"</string>
diff --git a/libs/WindowManager/Shell/res/values-zu/strings.xml b/libs/WindowManager/Shell/res/values-zu/strings.xml
index b304299..94f0d34 100644
--- a/libs/WindowManager/Shell/res/values-zu/strings.xml
+++ b/libs/WindowManager/Shell/res/values-zu/strings.xml
@@ -43,10 +43,8 @@
     <string name="accessibility_action_divider_left_50" msgid="3488317024557521561">"Kwesokunxele ngo-50%"</string>
     <string name="accessibility_action_divider_left_30" msgid="6023611335723838727">"Kwesokunxele ngo-30%"</string>
     <string name="accessibility_action_divider_right_full" msgid="3408505054325944903">"Isikrini esigcwele esingakwesokudla"</string>
-    <!-- no translation found for accessibility_action_divider_swap_vertical (3644891227133372072) -->
-    <skip />
-    <!-- no translation found for accessibility_action_divider_swap_horizontal (2722197605446631628) -->
-    <skip />
+    <string name="accessibility_action_divider_swap_vertical" msgid="3644891227133372072">"Shintshanisa i-app ephezulu ngengaphansi"</string>
+    <string name="accessibility_action_divider_swap_horizontal" msgid="2722197605446631628">"Shintshanisa i-app engakwesokunxele naleyo engakwesokudla"</string>
     <string name="accessibility_action_divider_top_full" msgid="3495871951082107594">"Isikrini esigcwele esiphezulu"</string>
     <string name="accessibility_action_divider_top_70" msgid="1779164068887875474">"Okuphezulu okungu-70%"</string>
     <string name="accessibility_action_divider_top_50" msgid="8649582798829048946">"Okuphezulu okungu-50%"</string>
@@ -115,14 +113,10 @@
     <string name="letterbox_restart_restart" msgid="8529976234412442973">"Qala kabusha"</string>
     <string name="letterbox_restart_dialog_checkbox_title" msgid="5252918008140768386">"Ungabonisi futhi"</string>
     <string name="letterbox_reachability_reposition_text" msgid="3522042240665748268">"Thepha kabili ukuze\nuhambise le-app"</string>
-    <!-- no translation found for maximize_button_text (8106849394538234709) -->
-    <skip />
-    <!-- no translation found for restore_button_text (5377571986086775288) -->
-    <skip />
-    <!-- no translation found for minimize_button_text (5213953162664451152) -->
-    <skip />
-    <!-- no translation found for close_button_text (4544839489310949894) -->
-    <skip />
+    <string name="maximize_button_text" msgid="8106849394538234709">"Khulisa i-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="restore_button_text" msgid="5377571986086775288">"Buyisela i-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="minimize_button_text" msgid="5213953162664451152">"Nciphisa i-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="close_button_text" msgid="4544839489310949894">"Vala i-<xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
     <string name="back_button_text" msgid="1469718707134137085">"Emuva"</string>
     <string name="handle_text" msgid="4419667835599523257">"Inkomba ye-App"</string>
     <string name="app_icon_text" msgid="2823268023931811747">"Isithonjana Se-app"</string>
@@ -158,14 +152,10 @@
     <string name="maximize_menu_talkback_action_snap_left_text" msgid="500309467459084564">"Shintsha usayizi wewindi ngakwesokunxele"</string>
     <string name="maximize_menu_talkback_action_snap_right_text" msgid="7010831426654467163">"Shintsha usayizi wewindi ngakwesokudla"</string>
     <string name="maximize_menu_talkback_action_maximize_restore_text" msgid="4942610897847934859">"Khulisa noma buyisela usayizi wewindi"</string>
-    <!-- no translation found for app_header_talkback_action_maximize_button_text (8776156791095878638) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_restore_button_text (2153022340772980863) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_minimize_button_text (7491054416186901764) -->
-    <skip />
-    <!-- no translation found for app_header_talkback_action_close_button_text (5159612596378268926) -->
-    <skip />
+    <string name="app_header_talkback_action_maximize_button_text" msgid="8776156791095878638">"Khulisa usayizi wewindi le-app"</string>
+    <string name="app_header_talkback_action_restore_button_text" msgid="2153022340772980863">"Buyisela usayizi wewindi"</string>
+    <string name="app_header_talkback_action_minimize_button_text" msgid="7491054416186901764">"Nciphisa iwindi le-app"</string>
+    <string name="app_header_talkback_action_close_button_text" msgid="5159612596378268926">"Vala iwindi le-app"</string>
     <string name="open_by_default_settings_text" msgid="2526548548598185500">"Vula amasethingi ngokuzenzakalela"</string>
     <string name="open_by_default_dialog_subheader_text" msgid="1729599730664063881">"Khetha indlela yokuvula amalinki ewebhu ale app"</string>
     <string name="open_by_default_dialog_in_app_text" msgid="6978022419634199806">"Ku-app"</string>
diff --git a/libs/WindowManager/Shell/res/values/dimen.xml b/libs/WindowManager/Shell/res/values/dimen.xml
index 32660e8..60044ad 100644
--- a/libs/WindowManager/Shell/res/values/dimen.xml
+++ b/libs/WindowManager/Shell/res/values/dimen.xml
@@ -619,13 +619,13 @@
     <dimen name="desktop_mode_header_app_chip_ripple_inset_vertical">4dp</dimen>
 
      <!-- The corner radius of the windowing actions pill buttons's ripple drawable -->
-     <dimen name="desktop_mode_handle_menu_windowing_action_ripple_radius">24dp</dimen>
+     <dimen name="desktop_mode_handle_menu_icon_button_ripple_radius">24dp</dimen>
      <!-- The horizontal/vertical inset to apply to the ripple drawable effect of windowing
      actions pill central buttons -->
-     <dimen name="desktop_mode_handle_menu_windowing_action_ripple_inset_base">2dp</dimen>
+     <dimen name="desktop_mode_handle_menu_icon_button_ripple_inset_base">2dp</dimen>
      <!-- The horizontal/vertical vertical inset to apply to the ripple drawable effect of windowing
      actions pill edge buttons -->
-     <dimen name="desktop_mode_handle_menu_windowing_action_ripple_inset_shift">4dp</dimen>
+     <dimen name="desktop_mode_handle_menu_icon_button_ripple_inset_shift">4dp</dimen>
 
     <!-- The corner radius of the minimize button's ripple drawable -->
     <dimen name="desktop_mode_header_minimize_ripple_radius">18dp</dimen>
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DeviceConfig.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DeviceConfig.kt
index f479da0..1b7c9c2 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DeviceConfig.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DeviceConfig.kt
@@ -49,19 +49,29 @@
                     or WindowInsets.Type.displayCutout())
             val windowBounds = windowMetrics.bounds
             val config: Configuration = context.resources.configuration
-            val isLargeScreen = config.smallestScreenWidthDp >= LARGE_SCREEN_MIN_EDGE_DP
-            val largestEdgeDp = max(config.screenWidthDp, config.screenHeightDp)
-            val isSmallTablet = isLargeScreen && largestEdgeDp < SMALL_TABLET_MAX_EDGE_DP
             val isLandscape = context.resources.configuration.orientation == ORIENTATION_LANDSCAPE
             val isRtl = context.resources.configuration.layoutDirection == LAYOUT_DIRECTION_RTL
             return DeviceConfig(
-                    isLargeScreen = isLargeScreen,
-                    isSmallTablet = isSmallTablet,
+                    isLargeScreen = isLargeScreen(config),
+                    isSmallTablet = isSmallTablet(context),
                     isLandscape = isLandscape,
                     isRtl = isRtl,
                     windowBounds = windowBounds,
                     insets = insets
             )
         }
+
+        @JvmStatic
+        fun isSmallTablet(context: Context): Boolean {
+            val config: Configuration = context.resources.configuration
+            if (!isLargeScreen(config)) {
+                return false
+            }
+            val largestEdgeDp = max(config.screenWidthDp, config.screenHeightDp)
+            return largestEdgeDp < SMALL_TABLET_MAX_EDGE_DP
+        }
+
+        private fun isLargeScreen(config: Configuration) =
+            config.smallestScreenWidthDp >= LARGE_SCREEN_MIN_EDGE_DP
     }
 }
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt
index 1a80b0f..362a5c5 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DragZoneFactory.kt
@@ -111,47 +111,28 @@
 
     /** Updates all dimensions after a configuration change. */
     fun onConfigurationUpdated() {
-        dismissDragZoneSize =
-            if (deviceConfig.isSmallTablet) {
-                context.resolveDimension(R.dimen.drag_zone_dismiss_fold)
-            } else {
-                context.resolveDimension(R.dimen.drag_zone_dismiss_tablet)
-            }
-        bubbleDragZoneTabletSize = context.resolveDimension(R.dimen.drag_zone_bubble_tablet)
-        bubbleDragZoneFoldableSize = context.resolveDimension(R.dimen.drag_zone_bubble_fold)
-        fullScreenDragZoneWidth = context.resolveDimension(R.dimen.drag_zone_full_screen_width)
-        fullScreenDragZoneHeight = context.resolveDimension(R.dimen.drag_zone_full_screen_height)
-        desktopWindowDragZoneWidth =
-            context.resolveDimension(R.dimen.drag_zone_desktop_window_width)
-        desktopWindowDragZoneHeight =
-            context.resolveDimension(R.dimen.drag_zone_desktop_window_height)
-        desktopWindowFromExpandedViewDragZoneWidth =
-            context.resolveDimension(R.dimen.drag_zone_desktop_window_expanded_view_width)
-        desktopWindowFromExpandedViewDragZoneHeight =
-            context.resolveDimension(R.dimen.drag_zone_desktop_window_expanded_view_height)
-        splitFromBubbleDragZoneHeight =
-            context.resolveDimension(R.dimen.drag_zone_split_from_bubble_height)
-        splitFromBubbleDragZoneWidth =
-            context.resolveDimension(R.dimen.drag_zone_split_from_bubble_width)
-        hSplitFromExpandedViewDragZoneWidth =
-            context.resolveDimension(R.dimen.drag_zone_h_split_from_expanded_view_width)
-        vSplitFromExpandedViewDragZoneWidth =
-            context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_width)
-        vSplitFromExpandedViewDragZoneHeightTablet =
-            context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_height_tablet)
-        vSplitFromExpandedViewDragZoneHeightFoldTall =
-            context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_height_fold_tall)
-        vSplitFromExpandedViewDragZoneHeightFoldShort =
-            context.resolveDimension(R.dimen.drag_zone_v_split_from_expanded_view_height_fold_short)
-        fullScreenDropTargetPadding =
-            context.resolveDimension(R.dimen.drop_target_full_screen_padding)
-        desktopWindowDropTargetPaddingSmall =
-            context.resolveDimension(R.dimen.drop_target_desktop_window_padding_small)
-        desktopWindowDropTargetPaddingLarge =
-            context.resolveDimension(R.dimen.drop_target_desktop_window_padding_large)
-
-        // TODO b/393172431: Use the shared xml resources once we can easily access them from
+        // TODO b/396539130: Use the shared xml resources once we can easily access them from
         //  launcher
+        dismissDragZoneSize =
+            if (deviceConfig.isSmallTablet) 140.dpToPx() else 200.dpToPx()
+        bubbleDragZoneTabletSize = 200.dpToPx()
+        bubbleDragZoneFoldableSize = 140.dpToPx()
+        fullScreenDragZoneWidth = 512.dpToPx()
+        fullScreenDragZoneHeight = 44.dpToPx()
+        desktopWindowDragZoneWidth = 880.dpToPx()
+        desktopWindowDragZoneHeight = 300.dpToPx()
+        desktopWindowFromExpandedViewDragZoneWidth = 200.dpToPx()
+        desktopWindowFromExpandedViewDragZoneHeight = 350.dpToPx()
+        splitFromBubbleDragZoneHeight = 100.dpToPx()
+        splitFromBubbleDragZoneWidth = 60.dpToPx()
+        hSplitFromExpandedViewDragZoneWidth = 60.dpToPx()
+        vSplitFromExpandedViewDragZoneWidth = 200.dpToPx()
+        vSplitFromExpandedViewDragZoneHeightTablet = 285.dpToPx()
+        vSplitFromExpandedViewDragZoneHeightFoldTall = 150.dpToPx()
+        vSplitFromExpandedViewDragZoneHeightFoldShort = 100.dpToPx()
+        fullScreenDropTargetPadding = 20.dpToPx()
+        desktopWindowDropTargetPaddingSmall = 100.dpToPx()
+        desktopWindowDropTargetPaddingLarge = 130.dpToPx()
         expandedViewDropTargetWidth = 364.dpToPx()
         expandedViewDropTargetHeight = 578.dpToPx()
         expandedViewDropTargetPaddingBottom = 108.dpToPx()
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt
index 5c25908..2dbbeae 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/bubbles/DropTargetManager.kt
@@ -33,7 +33,6 @@
 class DropTargetManager(
     private val context: Context,
     private val container: FrameLayout,
-    private val isLayoutRtl: Boolean,
     private val dragZoneChangedListener: DragZoneChangedListener,
 ) {
 
@@ -41,6 +40,7 @@
     private val dropTargetView = DropTargetView(context)
     private var animator: ValueAnimator? = null
     private var morphRect: RectF = RectF(0f, 0f, 0f, 0f)
+    private val isLayoutRtl = container.isLayoutRtl
 
     private companion object {
         const val MORPH_ANIM_DURATION = 250L
@@ -80,9 +80,11 @@
 
     /** Called when the drag ended. */
     fun onDragEnded() {
+        val dropState = state ?: return
         startFadeAnimation(from = dropTargetView.alpha, to = 0f) {
             container.removeView(dropTargetView)
         }
+        dragZoneChangedListener.onDragEnded(dropState.currentDragZone)
         state = null
     }
 
@@ -156,6 +158,9 @@
 
         /** Called when the object was dragged to a different drag zone. */
         fun onDragZoneChanged(from: DragZone, to: DragZone)
+
+        /** Called when the drag has ended with the zone it ended in. */
+        fun onDragEnded(zone: DragZone)
     }
 
     private fun Animator.doOnEnd(onEnd: () -> Unit) {
diff --git a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
index 2e33253..ed5e0c6 100644
--- a/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
+++ b/libs/WindowManager/Shell/shared/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatus.java
@@ -17,7 +17,9 @@
 package com.android.wm.shell.shared.desktopmode;
 
 import static android.hardware.display.DisplayManager.DISPLAY_CATEGORY_ALL_INCLUDING_DISABLED;
+import static android.window.DesktopExperienceFlags.ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE;
 
+import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
 import static com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper.enableBubbleToFullscreen;
 
 import android.annotation.NonNull;
@@ -224,7 +226,7 @@
     /**
      * Return {@code true} if the current device can host desktop sessions on its internal display.
      */
-    public static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
+    private static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
         return context.getResources().getBoolean(R.bool.config_canInternalDisplayHostDesktops);
     }
 
@@ -269,6 +271,29 @@
     }
 
     /**
+     * Check to see if a display should have desktop mode enabled or not. Internal
+     * and external displays have separate logic.
+     */
+    public static boolean isDesktopModeSupportedOnDisplay(Context context, Display display) {
+        if (!canEnterDesktopMode(context)) {
+            return false;
+        }
+        if (display.getType() == Display.TYPE_INTERNAL) {
+            return canInternalDisplayHostDesktops(context);
+        }
+
+        // TODO (b/395014779): Change this to use WM API
+        if ((display.getType() == Display.TYPE_EXTERNAL
+                || display.getType() == Display.TYPE_OVERLAY)
+                && enableDisplayContentModeManagement()) {
+            final WindowManager wm = context.getSystemService(WindowManager.class);
+            return wm != null && wm.shouldShowSystemDecors(display.getDisplayId());
+        }
+
+        return false;
+    }
+
+    /**
      * Returns whether the multiple desktops feature is enabled for this device (both backend and
      * frontend implementations).
      */
@@ -341,8 +366,11 @@
         if (!enforceDeviceRestrictions()) {
             return true;
         }
-        final boolean desktopModeSupported = isDesktopModeSupported(context)
-                && canInternalDisplayHostDesktops(context);
+        // If projected display is enabled, #canInternalDisplayHostDesktops is no longer a
+        // requirement.
+        final boolean desktopModeSupported = ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE.isTrue()
+                ? isDesktopModeSupported(context) : (isDesktopModeSupported(context)
+                && canInternalDisplayHostDesktops(context));
         final boolean desktopModeSupportedByDevOptions =
                 Flags.enableDesktopModeThroughDevOption()
                     && isDesktopModeDevOptionSupported(context);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java
index 5018fdb..8e78686 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/animation/SizeChangeAnimation.java
@@ -83,7 +83,11 @@
     private static final int ANIMATION_RESOLUTION = 1000;
 
     public SizeChangeAnimation(Rect startBounds, Rect endBounds) {
-        mAnimation = buildContainerAnimation(startBounds, endBounds);
+        this(startBounds, endBounds, 1f);
+    }
+
+    public SizeChangeAnimation(Rect startBounds, Rect endBounds, float initialScale) {
+        mAnimation = buildContainerAnimation(startBounds, endBounds, initialScale);
         mSnapshotAnim = buildSnapshotAnimation(startBounds, endBounds);
     }
 
@@ -167,7 +171,8 @@
     }
 
     /** Animation for the whole container (snapshot is inside this container). */
-    private static AnimationSet buildContainerAnimation(Rect startBounds, Rect endBounds) {
+    private static AnimationSet buildContainerAnimation(Rect startBounds, Rect endBounds,
+            float initialScale) {
         final long duration = ANIMATION_RESOLUTION;
         boolean growing = endBounds.width() - startBounds.width()
                 + endBounds.height() - startBounds.height() >= 0;
@@ -180,15 +185,27 @@
 
         final Animation scaleAnim = new ScaleAnimation(startScaleX, 1, startScaleY, 1);
         scaleAnim.setDuration(scalePeriod);
+        long scaleStartOffset = 0;
         if (!growing) {
-            scaleAnim.setStartOffset(duration - scalePeriod);
+            scaleStartOffset = duration - scalePeriod;
         }
+        scaleAnim.setStartOffset(scaleStartOffset);
         animSet.addAnimation(scaleAnim);
+
+        if (initialScale != 1f) {
+            final Animation initialScaleAnim = new ScaleAnimation(initialScale, 1f, initialScale,
+                    1f);
+            initialScaleAnim.setDuration(scalePeriod);
+            initialScaleAnim.setStartOffset(scaleStartOffset);
+            animSet.addAnimation(initialScaleAnim);
+        }
+
         final Animation translateAnim = new TranslateAnimation(startBounds.left,
                 endBounds.left, startBounds.top, endBounds.top);
         translateAnim.setDuration(duration);
         animSet.addAnimation(translateAnim);
         Rect startClip = new Rect(startBounds);
+        startClip.scale(initialScale);
         Rect endClip = new Rect(endBounds);
         startClip.offsetTo(0, 0);
         endClip.offsetTo(0, 0);
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 d1c7f7d..80b65d0 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
@@ -28,6 +28,7 @@
 import static android.window.TransitionInfo.FLAG_SHOW_WALLPAPER;
 
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_PREDICTIVE_BACK_HOME;
+import static com.android.systemui.Flags.predictiveBackDelayTransition;
 import static com.android.window.flags.Flags.unifyBackNavigationTransition;
 import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_BACK_PREVIEW;
 
@@ -431,6 +432,11 @@
     @VisibleForTesting
     public void onThresholdCrossed() {
         mThresholdCrossed = true;
+        BackTouchTracker activeTracker = getActiveTracker();
+        if (predictiveBackDelayTransition() && activeTracker != null && mActiveCallback == null
+                && mBackGestureStarted) {
+            startBackNavigation(activeTracker);
+        }
         // There was no focus window when calling startBackNavigation, still pilfer pointers so
         // the next focus window won't receive motion events.
         if (mBackNavigationInfo == null && mReceivedNullNavigationInfo) {
@@ -488,9 +494,14 @@
                 if (swipeEdge == EDGE_NONE) {
                     // start animation immediately for non-gestural sources (without ACTION_MOVE
                     // events)
-                    mThresholdCrossed = true;
+                    if (!predictiveBackDelayTransition()) {
+                        mThresholdCrossed = true;
+                    }
                     mPointersPilfered = true;
                     onGestureStarted(touchX, touchY, swipeEdge);
+                    if (predictiveBackDelayTransition()) {
+                        onThresholdCrossed();
+                    }
                     mShouldStartOnNextMoveEvent = false;
                 } else {
                     mShouldStartOnNextMoveEvent = true;
@@ -544,14 +555,17 @@
             mPostCommitAnimationInProgress = false;
             mShellExecutor.removeCallbacks(mAnimationTimeoutRunnable);
             startSystemAnimation();
-        } else if (touchTracker == mCurrentTracker) {
-            // Only start the back navigation if no other gesture is being processed. Otherwise,
-            // the back navigation will fall back to legacy back event injection.
-            startBackNavigation(mCurrentTracker);
+        } else if (!predictiveBackDelayTransition()) {
+            startBackNavigation(touchTracker);
         }
     }
 
     private void startBackNavigation(@NonNull BackTouchTracker touchTracker) {
+        if (touchTracker != mCurrentTracker) {
+            // Only start the back navigation if no other gesture is being processed. Otherwise,
+            // the back navigation will fall back to legacy back event injection.
+            return;
+        }
         try {
             startLatencyTracking();
             if (mBackAnimationAdapter != null
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index be22402..50e2f4d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -2643,6 +2643,15 @@
         mBubbleData.setSelectedBubbleAndExpandStack(bubbleToSelect);
     }
 
+    private void moveBubbleToFullscreen(String key) {
+        Bubble b = mBubbleData.getBubbleInStackWithKey(key);
+        if (b == null) {
+            Log.w(TAG, "can't find bubble with key " + key + " to move to fullscreen");
+            return;
+        }
+        b.getTaskView().moveToFullscreen();
+    }
+
     private boolean isDeviceLocked() {
         return !mIsStatusBarShade;
     }
@@ -2929,6 +2938,11 @@
                 }
             });
         }
+
+        @Override
+        public void moveBubbleToFullscreen(String key) {
+            mMainExecutor.execute(() -> mController.moveBubbleToFullscreen(key));
+        }
     }
 
     private class BubblesImpl implements Bubbles {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index abcdb7e..226ad57 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -1236,7 +1236,6 @@
 
     /** @return the bubble in the stack that matches the provided key. */
     @Nullable
-    @VisibleForTesting(visibility = PRIVATE)
     public Bubble getBubbleInStackWithKey(String key) {
         return getBubbleWithPredicate(mBubbles, b -> b.getKey().equals(key));
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
index 33f1b94..70340d7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubblePositioner.java
@@ -136,6 +136,11 @@
         updateInternal(mRotation, deviceConfig.getInsets(), deviceConfig.getWindowBounds());
     }
 
+    /** Returns the device config being used. */
+    public DeviceConfig getCurrentConfig() {
+        return mDeviceConfig;
+    }
+
     @VisibleForTesting
     public void updateInternal(int rotation, Insets insets, Rect bounds) {
         BubbleStackView.RelativeStackPosition prevStackPosition = null;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java
index 338ffe7..e7e7be9 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleTransitions.java
@@ -30,6 +30,7 @@
 import android.app.ActivityManager;
 import android.app.TaskInfo;
 import android.content.Context;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.util.Slog;
@@ -155,28 +156,23 @@
      * Information about the task when it is being dragged to a bubble
      */
     public static class DragData {
-        private final Rect mBounds;
         private final WindowContainerTransaction mPendingWct;
         private final boolean mReleasedOnLeft;
+        private final float mTaskScale;
+        private final PointF mDragPosition;
 
         /**
-         * @param bounds bounds of the dragged task when the drag was released
-         * @param wct pending operations to be applied when finishing the drag
          * @param releasedOnLeft true if the bubble was released in the left drop target
+         * @param taskScale      the scale of the task when it was dragged to bubble
+         * @param dragPosition   the position of the task when it was dragged to bubble
+         * @param wct            pending operations to be applied when finishing the drag
          */
-        public DragData(@Nullable Rect bounds, @Nullable WindowContainerTransaction wct,
-                boolean releasedOnLeft) {
-            mBounds = bounds;
+        public DragData(boolean releasedOnLeft, float taskScale, @Nullable PointF dragPosition,
+                @Nullable WindowContainerTransaction wct) {
             mPendingWct = wct;
             mReleasedOnLeft = releasedOnLeft;
-        }
-
-        /**
-         * @return bounds of the dragged task when the drag was released
-         */
-        @Nullable
-        public Rect getBounds() {
-            return mBounds;
+            mTaskScale = taskScale;
+            mDragPosition = dragPosition != null ? dragPosition : new PointF(0, 0);
         }
 
         /**
@@ -193,6 +189,20 @@
         public boolean isReleasedOnLeft() {
             return mReleasedOnLeft;
         }
+
+        /**
+         * @return the scale of the task when it was dragged to bubble
+         */
+        public float getTaskScale() {
+            return mTaskScale;
+        }
+
+        /**
+         * @return position of the task when it was dragged to bubble
+         */
+        public PointF getDragPosition() {
+            return mDragPosition;
+        }
     }
 
     /**
@@ -347,21 +357,24 @@
             }
             mFinishCb = finishCallback;
 
-            if (mDragData != null && mDragData.getBounds() != null) {
-                // Override start bounds with the dragged task bounds
-                mStartBounds.set(mDragData.getBounds());
+            if (mDragData != null) {
+                mStartBounds.offsetTo((int) mDragData.getDragPosition().x,
+                        (int) mDragData.getDragPosition().y);
+                startTransaction.setScale(mSnapshot, mDragData.getTaskScale(),
+                        mDragData.getTaskScale());
             }
 
             // Now update state (and talk to launcher) in parallel with snapshot stuff
             mBubbleData.notificationEntryUpdated(mBubble, /* suppressFlyout= */ true,
                     /* showInShade= */ false);
 
+            final int left = mStartBounds.left - info.getRoot(0).getOffset().x;
+            final int top = mStartBounds.top - info.getRoot(0).getOffset().y;
+            startTransaction.setPosition(mTaskLeash, left, top);
             startTransaction.show(mSnapshot);
             // Move snapshot to root so that it remains visible while task is moved to taskview
             startTransaction.reparent(mSnapshot, info.getRoot(0).getLeash());
-            startTransaction.setPosition(mSnapshot,
-                    mStartBounds.left - info.getRoot(0).getOffset().x,
-                    mStartBounds.top - info.getRoot(0).getOffset().y);
+            startTransaction.setPosition(mSnapshot, left, top);
             startTransaction.setLayer(mSnapshot, Integer.MAX_VALUE);
 
             BubbleBarExpandedView bbev = mBubble.getBubbleBarExpandedView();
@@ -416,6 +429,8 @@
         private void playAnimation(boolean animate) {
             final TaskViewTaskController tv = mBubble.getTaskView().getController();
             final SurfaceControl.Transaction startT = new SurfaceControl.Transaction();
+            // Set task position to 0,0 as it will be placed inside the TaskView
+            startT.setPosition(mTaskLeash, 0, 0);
             mTaskViewTransitions.prepareOpenAnimation(tv, true /* new */, startT, mFinishT,
                     (ActivityManager.RunningTaskInfo) mTaskInfo, mTaskLeash, mFinishWct);
 
@@ -424,10 +439,12 @@
             }
 
             if (animate) {
-                mLayerView.animateConvert(startT, mStartBounds, mSnapshot, mTaskLeash, () -> {
-                    mFinishCb.onTransitionFinished(mFinishWct);
-                    mFinishCb = null;
-                });
+                float startScale = mDragData != null ? mDragData.getTaskScale() : 1f;
+                mLayerView.animateConvert(startT, mStartBounds, startScale, mSnapshot, mTaskLeash,
+                        () -> {
+                            mFinishCb.onTransitionFinished(mFinishWct);
+                            mFinishCb = null;
+                        });
             } else {
                 startT.apply();
                 mFinishCb.onTransitionFinished(mFinishWct);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
index ae1b407..079edb3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/IBubbles.aidl
@@ -58,4 +58,6 @@
     oneway void showExpandedView() = 14;
 
     oneway void showDropTarget(in boolean show, in @nullable BubbleBarLocation location) = 15;
+
+    oneway void moveBubbleToFullscreen(in String key) = 16;
 }
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
index 52f2064..fa22a39 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarAnimationHelper.java
@@ -580,6 +580,7 @@
     public void animateConvert(BubbleViewProvider expandedBubble,
             @NonNull SurfaceControl.Transaction startT,
             @NonNull Rect origBounds,
+            float origScale,
             @NonNull SurfaceControl snapshot,
             @NonNull SurfaceControl taskLeash,
             @Nullable Runnable afterAnimation) {
@@ -599,7 +600,7 @@
                 new SizeChangeAnimation(
                         new Rect(origBounds.left - position.x, origBounds.top - position.y,
                                 origBounds.right - position.x, origBounds.bottom - position.y),
-                        new Rect(0, 0, size.getWidth(), size.getHeight()));
+                        new Rect(0, 0, size.getWidth(), size.getHeight()), origScale);
         sca.initialize(bbev, taskLeash, snapshot, startT);
 
         Animator a = sca.buildViewAnimator(bbev, tvSf, snapshot, /* onFinish */ (va) -> {
@@ -614,6 +615,7 @@
 
         bbev.setSurfaceZOrderedOnTop(true);
         a.setDuration(EXPANDED_VIEW_ANIMATE_TO_REST_DURATION);
+        a.setInterpolator(Interpolators.EMPHASIZED);
         a.start();
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
index 34259bf..9d4f904 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarExpandedViewDragController.kt
@@ -21,7 +21,11 @@
 import android.view.View
 import androidx.annotation.VisibleForTesting
 import com.android.wm.shell.bubbles.BubblePositioner
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation
 import com.android.wm.shell.shared.bubbles.DismissView
+import com.android.wm.shell.shared.bubbles.DragZoneFactory
+import com.android.wm.shell.shared.bubbles.DraggedObject
+import com.android.wm.shell.shared.bubbles.DropTargetManager
 import com.android.wm.shell.shared.bubbles.RelativeTouchListener
 import com.android.wm.shell.shared.magnetictarget.MagnetizedObject
 
@@ -33,6 +37,8 @@
     private val animationHelper: BubbleBarAnimationHelper,
     private val bubblePositioner: BubblePositioner,
     private val pinController: BubbleExpandedViewPinController,
+    private val dropTargetManager: DropTargetManager?,
+    private val dragZoneFactory: DragZoneFactory?,
     @get:VisibleForTesting val dragListener: DragListener,
 ) {
 
@@ -97,7 +103,21 @@
         override fun onDown(v: View, ev: MotionEvent): Boolean {
             // While animating, don't allow new touch events
             if (expandedView.isAnimating) return false
-            pinController.onDragStart(bubblePositioner.isBubbleBarOnLeft)
+            if (dropTargetManager != null && dragZoneFactory != null) {
+                val draggedObject = DraggedObject.ExpandedView(
+                    if (bubblePositioner.isBubbleBarOnLeft) {
+                        BubbleBarLocation.LEFT
+                    } else {
+                        BubbleBarLocation.RIGHT
+                    }
+                )
+                dropTargetManager.onDragStarted(
+                    draggedObject,
+                    dragZoneFactory.createSortedDragZones(draggedObject)
+                )
+            } else {
+                pinController.onDragStart(bubblePositioner.isBubbleBarOnLeft)
+            }
             isDragged = true
             return true
         }
@@ -117,7 +137,11 @@
             expandedView.translationX = expandedViewInitialTranslationX + dx
             expandedView.translationY = expandedViewInitialTranslationY + dy
             dismissView.show()
-            pinController.onDragUpdate(ev.rawX, ev.rawY)
+            if (dropTargetManager != null) {
+                dropTargetManager.onDragUpdated(ev.rawX.toInt(), ev.rawY.toInt())
+            } else {
+                pinController.onDragUpdate(ev.rawX, ev.rawY)
+            }
         }
 
         override fun onUp(
@@ -140,7 +164,11 @@
 
         private fun finishDrag() {
             if (!isStuckToDismiss) {
-                pinController.onDragEnd()
+                if (dropTargetManager != null) {
+                    dropTargetManager.onDragEnded()
+                } else {
+                    pinController.onDragEnd()
+                }
                 dragListener.onReleased(inDismiss = false)
                 animationHelper.animateToRestPosition()
                 dismissView.hide()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
index 677c21c..6c840f0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/bar/BubbleBarLayerView.java
@@ -27,6 +27,7 @@
 import android.graphics.Rect;
 import android.graphics.Region;
 import android.graphics.drawable.ColorDrawable;
+import android.util.Log;
 import android.view.Gravity;
 import android.view.SurfaceControl;
 import android.view.TouchDelegate;
@@ -48,9 +49,13 @@
 import com.android.wm.shell.bubbles.DismissViewUtils;
 import com.android.wm.shell.bubbles.bar.BubbleBarExpandedViewDragController.DragListener;
 import com.android.wm.shell.shared.bubbles.BaseBubblePinController;
+import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
 import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
 import com.android.wm.shell.shared.bubbles.DeviceConfig;
 import com.android.wm.shell.shared.bubbles.DismissView;
+import com.android.wm.shell.shared.bubbles.DragZone;
+import com.android.wm.shell.shared.bubbles.DragZoneFactory;
+import com.android.wm.shell.shared.bubbles.DropTargetManager;
 
 import kotlin.Unit;
 
@@ -76,6 +81,10 @@
     private final BubbleEducationViewController mEducationViewController;
     private final View mScrimView;
     private final BubbleExpandedViewPinController mBubbleExpandedViewPinController;
+    @Nullable
+    private DropTargetManager mDropTargetManager = null;
+    @Nullable
+    private DragZoneFactory mDragZoneFactory = null;
 
     @Nullable
     private BubbleViewProvider mExpandedBubble;
@@ -123,8 +132,72 @@
 
         mBubbleExpandedViewPinController = new BubbleExpandedViewPinController(
                 context, this, mPositioner);
-        mBubbleExpandedViewPinController.setListener(new LocationChangeListener());
+        LocationChangeListener locationChangeListener = new LocationChangeListener();
+        mBubbleExpandedViewPinController.setListener(locationChangeListener);
 
+        if (BubbleAnythingFlagHelper.enableBubbleToFullscreen()) {
+            mDropTargetManager = new DropTargetManager(context, this,
+                    new DropTargetManager.DragZoneChangedListener() {
+                        private DragZone mLastBubbleLocationDragZone = null;
+                        private BubbleBarLocation mInitialLocation = null;
+                        @Override
+                        public void onDragEnded(@NonNull DragZone zone) {
+                            if (mExpandedBubble == null || !(mExpandedBubble instanceof Bubble)) {
+                                Log.w(TAG, "dropped invalid bubble: " + mExpandedBubble);
+                                return;
+                            }
+                            if (zone instanceof DragZone.FullScreen) {
+                                ((Bubble) mExpandedBubble).getTaskView().moveToFullscreen();
+                                // Make sure location change listener is updated with the initial
+                                // location -- even if we "switched sides" during the drag, since
+                                // we've ended up in fullscreen, the location shouldn't change.
+                                locationChangeListener.onRelease(mInitialLocation);
+                            } else if (zone instanceof DragZone.Bubble.Left) {
+                                locationChangeListener.onRelease(BubbleBarLocation.LEFT);
+                            } else if (zone instanceof DragZone.Bubble.Right) {
+                                locationChangeListener.onRelease(BubbleBarLocation.RIGHT);
+                            }
+                        }
+
+                        @Override
+                        public void onInitialDragZoneSet(@NonNull DragZone dragZone) {
+                            mInitialLocation = dragZone instanceof DragZone.Bubble.Left
+                                    ? BubbleBarLocation.LEFT
+                                    : BubbleBarLocation.RIGHT;
+                            locationChangeListener.onStart(mInitialLocation);
+                        }
+
+                        @Override
+                        public void onDragZoneChanged(@NonNull DragZone from,
+                                @NonNull DragZone to) {
+                            final boolean isBubbleLeft = to instanceof DragZone.Bubble.Left;
+                            final boolean isBubbleRight = to instanceof DragZone.Bubble.Right;
+                            if ((isBubbleLeft || isBubbleRight)
+                                    && to != mLastBubbleLocationDragZone) {
+                                mLastBubbleLocationDragZone = to;
+                                locationChangeListener.onChange(isBubbleLeft
+                                        ? BubbleBarLocation.LEFT
+                                        : BubbleBarLocation.RIGHT);
+
+                            }
+                        }
+                    });
+            // TODO - currently only fullscreen is supported, should enable for split & desktop
+            mDragZoneFactory = new DragZoneFactory(context, mPositioner.getCurrentConfig(),
+                    new DragZoneFactory.SplitScreenModeChecker() {
+                        @NonNull
+                        @Override
+                        public SplitScreenMode getSplitScreenMode() {
+                            return SplitScreenMode.NONE;
+                        }
+                    },
+                    new DragZoneFactory.DesktopWindowModeChecker() {
+                        @Override
+                        public boolean isSupported() {
+                            return false;
+                        }
+                    });
+        }
         setOnClickListener(view -> hideModalOrCollapse());
     }
 
@@ -272,6 +345,8 @@
                     mAnimationHelper,
                     mPositioner,
                     mBubbleExpandedViewPinController,
+                    mDropTargetManager,
+                    mDragZoneFactory,
                     dragListener);
 
             addView(mExpandedView, new LayoutParams(width, height, Gravity.LEFT));
@@ -348,13 +423,13 @@
      * @param startT A transaction with first-frame work. this *will* be applied here!
      */
     public void animateConvert(@NonNull SurfaceControl.Transaction startT,
-            @NonNull Rect startBounds, @NonNull SurfaceControl snapshot, SurfaceControl taskLeash,
-            Runnable animFinish) {
+            @NonNull Rect startBounds, float startScale, @NonNull SurfaceControl snapshot,
+            SurfaceControl taskLeash, Runnable animFinish) {
         if (!mIsExpanded || mExpandedBubble == null) {
             throw new IllegalStateException("Can't animateExpand without expanded state");
         }
-        mAnimationHelper.animateConvert(mExpandedBubble, startT, startBounds, snapshot, taskLeash,
-                animFinish);
+        mAnimationHelper.animateConvert(mExpandedBubble, startT, startBounds, startScale, snapshot,
+                taskLeash, animFinish);
     }
 
     /**
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
index 3f21e74..453ca16 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/pip/PipDesktopState.java
@@ -19,18 +19,14 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
 
-import android.app.ActivityManager;
 import android.window.DesktopExperienceFlags;
+import android.window.DesktopModeFlags;
 import android.window.DisplayAreaInfo;
-import android.window.WindowContainerToken;
-import android.window.WindowContainerTransaction;
 
-import com.android.window.flags.Flags;
+import com.android.wm.shell.Flags;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
-import com.android.wm.shell.desktopmode.DesktopRepository;
 import com.android.wm.shell.desktopmode.DesktopUserRepositories;
-import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider;
-import com.android.wm.shell.pip2.phone.PipTransition;
+import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler;
 
 import java.util.Optional;
 
@@ -38,37 +34,38 @@
 public class PipDesktopState {
     private final PipDisplayLayoutState mPipDisplayLayoutState;
     private final Optional<DesktopUserRepositories> mDesktopUserRepositoriesOptional;
-    private final Optional<DesktopWallpaperActivityTokenProvider>
-            mDesktopWallpaperActivityTokenProviderOptional;
+    private final Optional<DragToDesktopTransitionHandler> mDragToDesktopTransitionHandlerOptional;
     private final RootTaskDisplayAreaOrganizer mRootTaskDisplayAreaOrganizer;
 
     public PipDesktopState(PipDisplayLayoutState pipDisplayLayoutState,
             Optional<DesktopUserRepositories> desktopUserRepositoriesOptional,
-            Optional<DesktopWallpaperActivityTokenProvider>
-                    desktopWallpaperActivityTokenProviderOptional,
+            Optional<DragToDesktopTransitionHandler> dragToDesktopTransitionHandlerOptional,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer) {
         mPipDisplayLayoutState = pipDisplayLayoutState;
         mDesktopUserRepositoriesOptional = desktopUserRepositoriesOptional;
-        mDesktopWallpaperActivityTokenProviderOptional =
-                desktopWallpaperActivityTokenProviderOptional;
+        mDragToDesktopTransitionHandlerOptional = dragToDesktopTransitionHandlerOptional;
         mRootTaskDisplayAreaOrganizer = rootTaskDisplayAreaOrganizer;
     }
 
     /**
      * Returns whether PiP in Desktop Windowing is enabled by checking the following:
-     * - Desktop Windowing in PiP flag is enabled
-     * - DesktopWallpaperActivityTokenProvider is injected
+     * - PiP in Desktop Windowing flag is enabled
      * - DesktopUserRepositories is injected
+     * - DragToDesktopTransitionHandler is injected
      */
     public boolean isDesktopWindowingPipEnabled() {
-        return Flags.enableDesktopWindowingPip()
-                && mDesktopWallpaperActivityTokenProviderOptional.isPresent()
-                && mDesktopUserRepositoriesOptional.isPresent();
+        return DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue()
+                && mDesktopUserRepositoriesOptional.isPresent()
+                && mDragToDesktopTransitionHandlerOptional.isPresent();
     }
 
-    /** Returns whether PiP in Connected Displays is enabled by checking the flag. */
+    /**
+     * Returns whether PiP in Connected Displays is enabled by checking the following:
+     * - PiP in Connected Displays flag is enabled
+     * - PiP2 flag is enabled
+     */
     public boolean isConnectedDisplaysPipEnabled() {
-        return DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_PIP.isTrue();
+        return DesktopExperienceFlags.ENABLE_CONNECTED_DISPLAYS_PIP.isTrue() && Flags.enablePip2();
     }
 
     /** Returns whether the display with the PiP task is in freeform windowing mode. */
@@ -89,45 +86,10 @@
             return false;
         }
         final int displayId = mPipDisplayLayoutState.getDisplayId();
-        return getDesktopRepository().isAnyDeskActive(displayId)
-                || getDesktopWallpaperActivityTokenProvider().isWallpaperActivityVisible(displayId)
+        return mDesktopUserRepositoriesOptional.get().getCurrent().isAnyDeskActive(displayId)
                 || isDisplayInFreeform();
     }
 
-    /** Returns whether {@param pipTask} would be entering in a Desktop Mode session. */
-    public boolean isPipEnteringInDesktopMode(ActivityManager.RunningTaskInfo pipTask) {
-        // Early return if PiP in Desktop Windowing is not supported.
-        if (!isDesktopWindowingPipEnabled()) {
-            return false;
-        }
-        final DesktopRepository desktopRepository = getDesktopRepository();
-        return desktopRepository.isAnyDeskActive(pipTask.getDisplayId())
-                || desktopRepository.isMinimizedPipPresentInDisplay(pipTask.getDisplayId());
-    }
-
-    /**
-     * Invoked when an EXIT_PiP transition is detected in {@link PipTransition}.
-     * Returns whether the PiP exiting should also trigger the active Desktop Mode session to exit.
-     */
-    public boolean shouldExitPipExitDesktopMode() {
-        // Early return if PiP in Desktop Windowing is not supported.
-        if (!isDesktopWindowingPipEnabled()) {
-            return false;
-        }
-        final int displayId = mPipDisplayLayoutState.getDisplayId();
-        return !getDesktopRepository().isAnyDeskActive(displayId)
-                && getDesktopWallpaperActivityTokenProvider().isWallpaperActivityVisible(displayId);
-    }
-
-    /**
-     * Returns a {@link WindowContainerTransaction} that reorders the {@link WindowContainerToken}
-     * of the DesktopWallpaperActivity for the display with the given {@param displayId}.
-     */
-    public WindowContainerTransaction getWallpaperActivityTokenWct(int displayId) {
-        return new WindowContainerTransaction().reorder(
-                getDesktopWallpaperActivityTokenProvider().getToken(displayId), /* onTop= */ false);
-    }
-
     /**
      * The windowing mode to restore to when resizing out of PIP direction.
      * Defaults to undefined and can be overridden to restore to an alternate windowing mode.
@@ -150,11 +112,12 @@
         return WINDOWING_MODE_UNDEFINED;
     }
 
-    private DesktopRepository getDesktopRepository() {
-        return mDesktopUserRepositoriesOptional.get().getCurrent();
-    }
-
-    private DesktopWallpaperActivityTokenProvider getDesktopWallpaperActivityTokenProvider() {
-        return mDesktopWallpaperActivityTokenProviderOptional.get();
+    /** Returns whether there is a drag-to-desktop transition in progress. */
+    public boolean isDragToDesktopInProgress() {
+        // Early return if PiP in Desktop Windowing is not supported.
+        if (!isDesktopWindowingPipEnabled()) {
+            return false;
+        }
+        return mDragToDesktopTransitionHandlerOptional.get().getInProgress();
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
index 5b2dd97..bc0a857 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/DividerSnapAlgorithm.java
@@ -39,6 +39,7 @@
 import com.android.wm.shell.shared.split.SplitScreenConstants.PersistentSnapPosition;
 
 import java.util.ArrayList;
+import java.util.stream.IntStream;
 
 /**
  * Calculates the snap targets and the snap position given a position and a velocity. All positions
@@ -354,10 +355,20 @@
         float ratio = areOffscreenRatiosSupported()
                 ? SplitSpec.OFFSCREEN_ASYMMETRIC_RATIO
                 : SplitSpec.ONSCREEN_ONLY_ASYMMETRIC_RATIO;
+
+        // The intended size of the smaller app, in pixels
         int size = (int) (ratio * (end - start)) - mDividerSize / 2;
 
-        int leftTopPosition = start + pinnedTaskbarShiftStart + size;
-        int rightBottomPosition = end - pinnedTaskbarShiftEnd - size - mDividerSize;
+        // If there are insets that interfere with the smaller app (visually or blocking touch
+        // targets), make the smaller app bigger by that amount to compensate. This applies to
+        // pinned taskbar, 3-button nav (both create an opaque bar at bottom) and status bar (blocks
+        // touch targets at top).
+        int extraSpace = IntStream.of(
+                getStartInset(), getEndInset(), pinnedTaskbarShiftStart, pinnedTaskbarShiftEnd
+        ).max().getAsInt();
+
+        int leftTopPosition = start + extraSpace + size;
+        int rightBottomPosition = end - extraSpace - size - mDividerSize;
         addNonDismissingTargets(isLeftRightSplit, leftTopPosition, rightBottomPosition, dividerMax);
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
index 720e8e5..e20a3d8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/split/SplitLayout.java
@@ -662,14 +662,14 @@
             return;
         }
 
-        // Check to see if insets changed in such a way that the divider algorithm needs to be
-        // recalculated.
+        // Check to see if insets changed in such a way that the divider needs to be animated to
+        // a new position. (We only do this when switching to pinned taskbar mode and back).
         Insets pinnedTaskbarInsets = calculatePinnedTaskbarInsets(insetsState);
         if (!mPinnedTaskbarInsets.equals(pinnedTaskbarInsets)) {
             mPinnedTaskbarInsets = pinnedTaskbarInsets;
             // Refresh the DividerSnapAlgorithm.
             updateLayouts();
-            // If the divider is no longer placed on a snap point, animate it to the nearest one.
+            // If the divider is no longer placed on a snap point, animate it to the nearest one
             DividerSnapAlgorithm.SnapTarget snapTarget =
                     findSnapTarget(mDividerPosition, 0, false /* hardDismiss */);
             if (snapTarget.position != mDividerPosition) {
@@ -683,18 +683,12 @@
     }
 
     /**
-     * Calculates the insets that might trigger a divider algorithm recalculation. Currently, only
-     * pinned Taskbar does this, and only when the IME is not showing.
+     * Calculates the insets that might trigger a divider algorithm recalculation.
      */
     private Insets calculatePinnedTaskbarInsets(InsetsState insetsState) {
-        if (insetsState.isSourceOrDefaultVisible(InsetsSource.ID_IME, WindowInsets.Type.ime())) {
-            return Insets.NONE;
-        }
-
-        // If IME is not showing...
         for (int i = insetsState.sourceSize() - 1; i >= 0; i--) {
             final InsetsSource source = insetsState.sourceAt(i);
-            // and Taskbar is pinned...
+            // If Taskbar is pinned...
             if (source.getType() == WindowInsets.Type.navigationBars()
                     && source.hasFlags(InsetsSource.FLAG_INSETS_ROUNDED_CORNER)) {
                 // Return Insets representing the pinned taskbar state.
@@ -1543,11 +1537,28 @@
             }
         }
 
+        /**
+         * When IME is triggered on the bottom app in split screen, we want to translate the bottom
+         * app up by a certain amount so that it's not covered too much by the IME. But there's also
+         * an upper limit to the amount we want to translate (since we still need some of the top
+         * app to be visible too). So this function essentially says "try to translate the bottom
+         * app up, but stop before you make the top app too small."
+         */
         private int getTargetYOffset() {
-            final int desireOffset = Math.abs(mEndImeTop - mStartImeTop);
-            // Make sure to keep at least 30% visible for the top split.
-            final int maxOffset = (int) (getTopLeftBounds().height() * ADJUSTED_SPLIT_FRACTION_MAX);
-            return -Math.min(desireOffset, maxOffset);
+            // We want to translate up the bottom app by this amount.
+            final int desiredOffset = Math.abs(mEndImeTop - mStartImeTop);
+
+            // But we also want to keep this much of the top app visible.
+            final float amountOfTopAppToKeepVisible =
+                    getTopLeftBounds().height() * (1 - ADJUSTED_SPLIT_FRACTION_MAX);
+
+            // So the current onscreen size of the top app, minus the minimum size, is the max
+            // translation we will allow.
+            final float currentOnScreenSizeOfTopApp = getTopLeftBounds().bottom;
+            final int maxOffset =
+                    (int) Math.max(currentOnScreenSizeOfTopApp - amountOfTopAppToKeepVisible, 0);
+
+            return -Math.min(desiredOffset, maxOffset);
         }
 
         @SplitPosition
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
index 0e6481b..318cdee 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java
@@ -1052,23 +1052,8 @@
         });
     }
 
-    @WMSingleton
-    @Provides
-    static DesktopWallpaperActivityTokenProvider provideDesktopWallpaperActivityTokenProvider() {
-        return new DesktopWallpaperActivityTokenProvider();
-    }
-
-    @WMSingleton
-    @Provides
-    static Optional<DesktopWallpaperActivityTokenProvider>
-            provideOptionalDesktopWallpaperActivityTokenProvider(
-            Context context,
-            DesktopWallpaperActivityTokenProvider desktopWallpaperActivityTokenProvider) {
-        if (DesktopModeStatus.canEnterDesktopMode(context)) {
-            return Optional.of(desktopWallpaperActivityTokenProvider);
-        }
-        return Optional.empty();
-    }
+    @BindsOptionalOf
+    abstract DesktopWallpaperActivityTokenProvider optionalDesktopWallpaperActivityTokenProvider();
 
     //
     // App zoom out (optional feature)
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 79fbd32..423d175 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -36,6 +36,7 @@
 import android.os.UserManager;
 import android.view.Choreographer;
 import android.view.IWindowManager;
+import android.view.SurfaceControl;
 import android.view.WindowManager;
 import android.window.DesktopModeFlags;
 
@@ -93,6 +94,7 @@
 import com.android.wm.shell.desktopmode.DesktopModeEventLogger;
 import com.android.wm.shell.desktopmode.DesktopModeKeyGestureHandler;
 import com.android.wm.shell.desktopmode.DesktopModeLoggerTransitionObserver;
+import com.android.wm.shell.desktopmode.DesktopModeMoveToDisplayTransitionHandler;
 import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger;
 import com.android.wm.shell.desktopmode.DesktopTaskChangeListener;
 import com.android.wm.shell.desktopmode.DesktopTasksController;
@@ -167,6 +169,7 @@
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 import com.android.wm.shell.windowdecor.additionalviewcontainer.AdditionalSystemViewContainer;
+import com.android.wm.shell.windowdecor.common.AppHandleAndHeaderVisibilityHelper;
 import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader;
 import com.android.wm.shell.windowdecor.common.viewhost.DefaultWindowDecorViewHostSupplier;
 import com.android.wm.shell.windowdecor.common.viewhost.PooledWindowDecorViewHostSupplier;
@@ -772,7 +775,8 @@
             DesksTransitionObserver desksTransitionObserver,
             UserProfileContexts userProfileContexts,
             DesktopModeCompatPolicy desktopModeCompatPolicy,
-            DragToDisplayTransitionHandler dragToDisplayTransitionHandler) {
+            DragToDisplayTransitionHandler dragToDisplayTransitionHandler,
+            DesktopModeMoveToDisplayTransitionHandler moveToDisplayTransitionHandler) {
         return new DesktopTasksController(
                 context,
                 shellInit,
@@ -812,7 +816,8 @@
                 desksTransitionObserver,
                 userProfileContexts,
                 desktopModeCompatPolicy,
-                dragToDisplayTransitionHandler);
+                dragToDisplayTransitionHandler,
+                moveToDisplayTransitionHandler);
     }
 
     @WMSingleton
@@ -873,8 +878,7 @@
             @ShellMainThread Handler handler) {
         int maxTaskLimit = DesktopModeStatus.getMaxTaskLimit(context);
         if (!DesktopModeStatus.canEnterDesktopMode(context)
-                || !ENABLE_DESKTOP_WINDOWING_TASK_LIMIT.isTrue()
-                || maxTaskLimit <= 0) {
+                || !ENABLE_DESKTOP_WINDOWING_TASK_LIMIT.isTrue()) {
             return Optional.empty();
         }
         return Optional.of(
@@ -882,7 +886,7 @@
                         transitions,
                         desktopUserRepositories,
                         shellTaskOrganizer,
-                        maxTaskLimit,
+                        maxTaskLimit <= 0 ? null : maxTaskLimit,
                         interactionJankMonitor,
                         context,
                         handler));
@@ -938,12 +942,24 @@
 
     @WMSingleton
     @Provides
+    static DesktopWallpaperActivityTokenProvider provideDesktopWallpaperActivityTokenProvider() {
+        return new DesktopWallpaperActivityTokenProvider();
+    }
+
+    @WMSingleton
+    @Provides
     static DragToDisplayTransitionHandler provideDragToDisplayTransitionHandler() {
         return new DragToDisplayTransitionHandler();
     }
 
     @WMSingleton
     @Provides
+    static DesktopModeMoveToDisplayTransitionHandler provideMoveToDisplayTransitionHandler() {
+        return new DesktopModeMoveToDisplayTransitionHandler(new SurfaceControl.Transaction());
+    }
+
+    @WMSingleton
+    @Provides
     static Optional<DesktopModeKeyGestureHandler> provideDesktopModeKeyGestureHandler(
             Context context,
             Optional<DesktopModeWindowDecorViewModel> desktopModeWindowDecorViewModel,
@@ -996,6 +1012,7 @@
             Optional<DesktopTasksLimiter> desktopTasksLimiter,
             AppHandleEducationController appHandleEducationController,
             AppToWebEducationController appToWebEducationController,
+            AppHandleAndHeaderVisibilityHelper appHandleAndHeaderVisibilityHelper,
             WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
             Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
             FocusTransitionObserver focusTransitionObserver,
@@ -1019,10 +1036,10 @@
                 rootTaskDisplayAreaOrganizer, interactionJankMonitor, genericLinksParser,
                 assistContentRequester, windowDecorViewHostSupplier, multiInstanceHelper,
                 desktopTasksLimiter, appHandleEducationController, appToWebEducationController,
-                windowDecorCaptionHandleRepository, activityOrientationChangeHandler,
-                focusTransitionObserver, desktopModeEventLogger, desktopModeUiEventLogger,
-                taskResourceLoader, recentsTransitionHandler, desktopModeCompatPolicy,
-                desktopTilingDecorViewModel,
+                appHandleAndHeaderVisibilityHelper, windowDecorCaptionHandleRepository,
+                activityOrientationChangeHandler, focusTransitionObserver, desktopModeEventLogger,
+                desktopModeUiEventLogger, taskResourceLoader, recentsTransitionHandler,
+                desktopModeCompatPolicy, desktopTilingDecorViewModel,
                 multiDisplayDragMoveIndicatorController));
     }
 
@@ -1050,6 +1067,16 @@
 
     @WMSingleton
     @Provides
+    static AppHandleAndHeaderVisibilityHelper provideAppHandleAndHeaderVisibilityHelper(
+            @NonNull Context context,
+            @NonNull DisplayController displayController,
+            @NonNull DesktopModeCompatPolicy desktopModeCompatPolicy) {
+        return new AppHandleAndHeaderVisibilityHelper(context, displayController,
+                desktopModeCompatPolicy);
+    }
+
+    @WMSingleton
+    @Provides
     static WindowDecorTaskResourceLoader provideWindowDecorTaskResourceLoader(
             @NonNull Context context, @NonNull ShellInit shellInit,
             @NonNull ShellController shellController,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
index f8b18f2..6f0919e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/pip/Pip2Module.java
@@ -20,6 +20,7 @@
 import android.content.Context;
 import android.os.Handler;
 
+import com.android.internal.jank.InteractionJankMonitor;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.common.DisplayController;
@@ -42,9 +43,10 @@
 import com.android.wm.shell.dagger.WMShellBaseModule;
 import com.android.wm.shell.dagger.WMSingleton;
 import com.android.wm.shell.desktopmode.DesktopUserRepositories;
-import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider;
+import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler;
 import com.android.wm.shell.pip2.phone.PhonePipMenuController;
 import com.android.wm.shell.pip2.phone.PipController;
+import com.android.wm.shell.pip2.phone.PipInteractionHandler;
 import com.android.wm.shell.pip2.phone.PipMotionHelper;
 import com.android.wm.shell.pip2.phone.PipScheduler;
 import com.android.wm.shell.pip2.phone.PipTaskListener;
@@ -59,6 +61,7 @@
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 
+import dagger.BindsOptionalOf;
 import dagger.Module;
 import dagger.Provides;
 
@@ -87,12 +90,13 @@
             @NonNull PipUiStateChangeController pipUiStateChangeController,
             DisplayController displayController,
             Optional<SplitScreenController> splitScreenControllerOptional,
-            PipDesktopState pipDesktopState) {
+            PipDesktopState pipDesktopState,
+            PipInteractionHandler pipInteractionHandler) {
         return new PipTransition(context, shellInit, shellTaskOrganizer, transitions,
                 pipBoundsState, null, pipBoundsAlgorithm, pipTaskListener,
                 pipScheduler, pipStackListenerController, pipDisplayLayoutState,
                 pipUiStateChangeController, displayController, splitScreenControllerOptional,
-                pipDesktopState);
+                pipDesktopState, pipInteractionHandler);
     }
 
     @WMSingleton
@@ -209,8 +213,9 @@
 
     @WMSingleton
     @Provides
-    static PipTransitionState providePipTransitionState(@ShellMainThread Handler handler) {
-        return new PipTransitionState(handler);
+    static PipTransitionState providePipTransitionState(@ShellMainThread Handler handler,
+            PipDesktopState pipDesktopState) {
+        return new PipTransitionState(handler, pipDesktopState);
     }
 
     @WMSingleton
@@ -238,11 +243,23 @@
     static PipDesktopState providePipDesktopState(
             PipDisplayLayoutState pipDisplayLayoutState,
             Optional<DesktopUserRepositories> desktopUserRepositoriesOptional,
-            Optional<DesktopWallpaperActivityTokenProvider>
-                    desktopWallpaperActivityTokenProviderOptional,
+            Optional<DragToDesktopTransitionHandler> dragToDesktopTransitionHandlerOptional,
             RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer
     ) {
         return new PipDesktopState(pipDisplayLayoutState, desktopUserRepositoriesOptional,
-                desktopWallpaperActivityTokenProviderOptional, rootTaskDisplayAreaOrganizer);
+                dragToDesktopTransitionHandlerOptional, rootTaskDisplayAreaOrganizer);
+    }
+
+    @BindsOptionalOf
+    abstract DragToDesktopTransitionHandler optionalDragToDesktopTransitionHandler();
+
+    @WMSingleton
+    @Provides
+    static PipInteractionHandler providePipInteractionHandler(
+            Context context,
+            @ShellMainThread Handler mainHandler
+    ) {
+        return new PipInteractionHandler(context, mainHandler,
+                InteractionJankMonitor.getInstance());
     }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandler.kt
new file mode 100644
index 0000000..fbf170f13
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandler.kt
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import android.animation.Animator
+import android.animation.ValueAnimator
+import android.os.IBinder
+import android.view.Choreographer
+import android.view.SurfaceControl
+import android.window.TransitionInfo
+import android.window.TransitionRequestInfo
+import android.window.WindowContainerTransaction
+import com.android.wm.shell.shared.animation.Interpolators
+import com.android.wm.shell.transition.Transitions
+import kotlin.time.Duration.Companion.milliseconds
+
+/**
+ * Transition handler for moving a window to a different display.
+ */
+class DesktopModeMoveToDisplayTransitionHandler(
+    private val animationTransaction: SurfaceControl.Transaction
+) : Transitions.TransitionHandler {
+
+    override fun handleRequest(
+        transition: IBinder,
+        request: TransitionRequestInfo,
+    ): WindowContainerTransaction? = null
+
+    override fun startAnimation(
+        transition: IBinder,
+        info: TransitionInfo,
+        startTransaction: SurfaceControl.Transaction,
+        finishTransaction: SurfaceControl.Transaction,
+        finishCallback: Transitions.TransitionFinishCallback,
+    ): Boolean {
+        val change = info.changes.find { it.startDisplayId != it.endDisplayId } ?: return false
+        ValueAnimator.ofFloat(0f, 1f)
+            .apply {
+                duration = ANIM_DURATION.inWholeMilliseconds
+                interpolator = Interpolators.LINEAR
+                addUpdateListener { animation ->
+                    animationTransaction
+                        .setAlpha(change.leash, animation.animatedValue as Float)
+                        .setFrameTimeline(Choreographer.getInstance().vsyncId)
+                        .apply()
+                }
+                addListener(
+                    object : Animator.AnimatorListener {
+                        override fun onAnimationStart(animation: Animator) {
+                            val endBounds = change.endAbsBounds
+                            startTransaction
+                                .setPosition(
+                                    change.leash,
+                                    endBounds.left.toFloat(),
+                                    endBounds.top.toFloat(),
+                                )
+                                .setWindowCrop(change.leash, endBounds.width(), endBounds.height())
+                                .apply()
+                        }
+
+                        override fun onAnimationEnd(animation: Animator) {
+                            finishTransaction.apply()
+                            finishCallback.onTransitionFinished(null)
+                        }
+
+                        override fun onAnimationCancel(animation: Animator) {
+                            finishTransaction.apply()
+                            finishCallback.onTransitionFinished(null)
+                        }
+
+                        override fun onAnimationRepeat(animation: Animator) = Unit
+                    }
+                )
+            }
+            .start()
+        return true
+    }
+
+    private companion object {
+        val ANIM_DURATION = 100.milliseconds
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
index 56de48d..7053990 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicator.java
@@ -103,6 +103,10 @@
                 return null;
             }
         }
+
+        private static boolean isDragToDesktopStartState(DragStartState startState) {
+            return startState == FROM_FULLSCREEN || startState == FROM_SPLIT;
+        }
     }
 
     private final VisualIndicatorViewContainer mVisualIndicatorViewContainer;
@@ -125,7 +129,12 @@
             @Nullable BubbleDropTargetBoundsProvider bubbleBoundsProvider,
             SnapEventHandler snapEventHandler) {
         SurfaceControl.Builder builder = new SurfaceControl.Builder();
-        taskDisplayAreaOrganizer.attachToDisplayArea(taskInfo.displayId, builder);
+        if (!DragStartState.isDragToDesktopStartState(dragStartState)
+                || !DesktopModeFlags.ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX.isTrue()) {
+            // In the DragToDesktop transition we attach the indicator to the transition root once
+            // that is available - for all other cases attach the indicator here.
+            taskDisplayAreaOrganizer.attachToDisplayArea(taskInfo.displayId, builder);
+        }
         mVisualIndicatorViewContainer = new VisualIndicatorViewContainer(
                 DesktopModeFlags.ENABLE_DESKTOP_INDICATOR_IN_SEPARATE_THREAD_BUGFIX.isTrue()
                         ? desktopExecutor : mainExecutor,
@@ -159,6 +168,18 @@
         mVisualIndicatorViewContainer.releaseVisualIndicator();
     }
 
+    /** Reparent the visual indicator to {@code newParent}. */
+    void reparentLeash(SurfaceControl.Transaction t, SurfaceControl newParent) {
+        mVisualIndicatorViewContainer.reparentLeash(t, newParent);
+    }
+
+    /** Start the fade-in animation. */
+    void fadeInIndicator() {
+        mVisualIndicatorViewContainer.fadeInIndicator(
+                mDisplayController.getDisplayLayout(mTaskInfo.displayId), mCurrentType,
+                mTaskInfo.displayId);
+    }
+
     /**
      * Based on the coordinates of the current drag event, determine which indicator type we should
      * display, including no visible indicator.
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index 73df976..bbb300e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -28,7 +28,6 @@
 import androidx.core.util.valueIterator
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.protolog.ProtoLog
-import com.android.window.flags.Flags
 import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
 import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
 import com.android.wm.shell.shared.annotations.ShellMainThread
@@ -70,9 +69,6 @@
      *   fullscreen task launched on top of the desk. Cleared when the transparent task is closed or
      *   sent to back. (top is at index 0).
      * @property pipTaskId the task id of PiP task entered while in Desktop Mode.
-     * @property pipShouldKeepDesktopActive whether an active PiP window should keep the desk
-     *   active. Only false when we are explicitly exiting Desktop Mode (via user action) while
-     *   there is an active PiP window.
      */
     private data class Desk(
         val deskId: Int,
@@ -86,8 +82,6 @@
         var fullImmersiveTaskId: Int? = null,
         var topTransparentFullscreenTaskId: Int? = null,
         var pipTaskId: Int? = null,
-        // TODO: b/389960283 - consolidate this with [DesktopDisplay#activeDeskId].
-        var pipShouldKeepDesktopActive: Boolean = true,
     ) {
         fun deepCopy(): Desk =
             Desk(
@@ -101,7 +95,6 @@
                 fullImmersiveTaskId = fullImmersiveTaskId,
                 topTransparentFullscreenTaskId = topTransparentFullscreenTaskId,
                 pipTaskId = pipTaskId,
-                pipShouldKeepDesktopActive = pipShouldKeepDesktopActive,
             )
 
         // TODO: b/362720497 - remove when multi-desktops is enabled where instances aren't
@@ -115,7 +108,6 @@
             fullImmersiveTaskId = null
             topTransparentFullscreenTaskId = null
             pipTaskId = null
-            pipShouldKeepDesktopActive = true
         }
     }
 
@@ -625,7 +617,6 @@
                 ?: error("Expected active desk in display: $displayId")
         if (enterPip) {
             activeDesk.pipTaskId = taskId
-            activeDesk.pipShouldKeepDesktopActive = true
         } else {
             activeDesk.pipTaskId =
                 if (activeDesk.pipTaskId == taskId) null
@@ -638,19 +629,9 @@
                     activeDesk.pipTaskId
                 }
         }
-        notifyVisibleTaskListeners(displayId, getVisibleTaskCount(displayId))
     }
 
     /**
-     * Returns whether there is a PiP that was entered/minimized from Desktop in this display's
-     * active desk.
-     *
-     * TODO: b/389960283 - add explicit [deskId] argument.
-     */
-    fun isMinimizedPipPresentInDisplay(displayId: Int): Boolean =
-        desktopData.getActiveDesk(displayId)?.pipTaskId != null
-
-    /**
      * Returns whether the given task is the Desktop-entered PiP task in this display's active desk.
      *
      * TODO: b/389960283 - add explicit [deskId] argument.
@@ -659,25 +640,6 @@
         desktopData.getActiveDesk(displayId)?.pipTaskId == taskId
 
     /**
-     * Returns whether a desk should be active in this display due to active PiP.
-     *
-     * TODO: b/389960283 - add explicit [deskId] argument.
-     */
-    fun shouldDesktopBeActiveForPip(displayId: Int): Boolean =
-        Flags.enableDesktopWindowingPip() &&
-            isMinimizedPipPresentInDisplay(displayId) &&
-            (desktopData.getActiveDesk(displayId)?.pipShouldKeepDesktopActive ?: false)
-
-    /**
-     * Saves whether a PiP window should keep Desktop session active in this display.
-     *
-     * TODO: b/389960283 - add explicit [deskId] argument.
-     */
-    fun setPipShouldKeepDesktopActive(displayId: Int, keepActive: Boolean) {
-        desktopData.getActiveDesk(displayId)?.pipShouldKeepDesktopActive = keepActive
-    }
-
-    /**
      * Saves callback to handle a pending PiP transition being aborted.
      *
      * TODO: b/389960283 - add explicit [deskId] argument.
@@ -771,13 +733,10 @@
         desktopData.getActiveDesk(displayId)?.topTransparentFullscreenTaskId = null
     }
 
-    private fun notifyVisibleTaskListeners(displayId: Int, visibleTasksCount: Int) {
-        val visibleAndPipTasksCount =
-            if (shouldDesktopBeActiveForPip(displayId)) visibleTasksCount + 1 else visibleTasksCount
+    @VisibleForTesting
+    public fun notifyVisibleTaskListeners(displayId: Int, visibleTasksCount: Int) {
         visibleTasksListeners.forEach { (listener, executor) ->
-            executor.execute {
-                listener.onTasksVisibilityChanged(displayId, visibleAndPipTasksCount)
-            }
+            executor.execute { listener.onTasksVisibilityChanged(displayId, visibleTasksCount) }
         }
     }
 
@@ -957,6 +916,7 @@
         val wasActive = desktopData.getActiveDesk(desk.displayId)?.deskId == desk.deskId
         val activeTasks = ArraySet(desk.activeTasks)
         desktopData.remove(desk.deskId)
+        notifyVisibleTaskListeners(desk.displayId, getVisibleTaskCount(displayId = desk.displayId))
         deskChangeListeners.forEach { (listener, executor) ->
             executor.execute {
                 if (wasActive) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
index 70a648f..e04d14459 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt
@@ -53,24 +53,12 @@
         // Case 1: When the task change is from a task in the desktop repository which is now
         // fullscreen,
         // remove the task from the desktop repository since it is no longer a freeform task.
-        if (!isFreeformTask(taskInfo)) {
-            if (desktopRepository.isActiveTask(taskInfo.taskId)) {
-                desktopRepository.removeTask(taskInfo.displayId, taskInfo.taskId)
-            }
-        } else { // Task change is a freeform task
-            if (!desktopRepository.isActiveTask(taskInfo.taskId)) {
-                // Case 2: When the task change is a freeform visible task, but the task is not
-                // yet active in the desktop repository, adds task to desktop repository.
-                desktopRepository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible)
-            } else {
-                // Case 3: When the task change is a freeform task which already exists as an active
-                // task in the desktop repository, updates the task state.
-                desktopRepository.updateTask(
-                    taskInfo.displayId,
-                    taskInfo.taskId,
-                    taskInfo.isVisible,
-                )
-            }
+        if (!isFreeformTask(taskInfo) && desktopRepository.isActiveTask(taskInfo.taskId)) {
+            desktopRepository.removeTask(taskInfo.displayId, taskInfo.taskId)
+        } else if (isFreeformTask(taskInfo)) {
+            // If the task is already active in the repository, then moves task to the front,
+            // else adds the task.
+            desktopRepository.addTask(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible)
         }
     }
 
@@ -109,7 +97,7 @@
             desktopUserRepositories.getProfile(taskInfo.userId)
         if (!desktopRepository.isActiveTask(taskInfo.taskId)) return
         logD("onTaskMovingToBack for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId)
-        // TODO: b/367268953 - Connect this with DesktopRepository.
+        desktopRepository.updateTask(taskInfo.displayId, taskInfo.taskId, /* isVisible= */ false)
     }
 
     override fun onTaskClosing(taskInfo: RunningTaskInfo) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 8f7e52e..301b79a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -22,6 +22,7 @@
 import android.app.ActivityOptions
 import android.app.KeyguardManager
 import android.app.PendingIntent
+import android.app.TaskInfo
 import android.app.WindowConfiguration.ACTIVITY_TYPE_HOME
 import android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD
 import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
@@ -208,6 +209,7 @@
     private val userProfileContexts: UserProfileContexts,
     private val desktopModeCompatPolicy: DesktopModeCompatPolicy,
     private val dragToDisplayTransitionHandler: DragToDisplayTransitionHandler,
+    private val moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler,
 ) :
     RemoteCallable<DesktopTasksController>,
     Transitions.TransitionHandler,
@@ -343,45 +345,28 @@
     fun isAnyDeskActive(displayId: Int): Boolean = taskRepository.isAnyDeskActive(displayId)
 
     /**
-     * Returns true if any of the following is true:
-     * - Any freeform tasks are visible
-     * - A transparent fullscreen task exists on top in Desktop Mode
-     * - PiP on Desktop Windowing is enabled, there is an active PiP window and the desktop
-     *   wallpaper is visible.
+     * Returns true if any freeform tasks are visible or if a transparent fullscreen task exists on
+     * top in Desktop Mode.
      *
      * TODO: b/362720497 - consolidate with [isAnyDeskActive].
      *     - top-transparent-fullscreen case: should not be needed if we allow it to launch inside
      *       the desk in fullscreen instead of force-exiting desktop and having to trick this method
      *       into thinking it is in desktop mode when a task in this state exists.
-     *     - PIP case: a PIP presence should influence desk activation, so
-     *       [DesktopRepository#isAnyDeskActive] should be sufficient.
      */
     fun isDesktopModeShowing(displayId: Int): Boolean {
         val hasVisibleTasks = taskRepository.isAnyDeskActive(displayId)
         val hasTopTransparentFullscreenTask =
             taskRepository.getTopTransparentFullscreenTaskId(displayId) != null
-        val hasMinimizedPip =
-            Flags.enableDesktopWindowingPip() &&
-                taskRepository.isMinimizedPipPresentInDisplay(displayId) &&
-                desktopWallpaperActivityTokenProvider.isWallpaperActivityVisible(displayId)
         if (
             DesktopModeFlags.INCLUDE_TOP_TRANSPARENT_FULLSCREEN_TASK_IN_DESKTOP_HEURISTIC
                 .isTrue() && DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_MODALS_POLICY.isTrue()
         ) {
             logV(
-                "isDesktopModeShowing: hasVisibleTasks=%s hasTopTransparentFullscreenTask=%s hasMinimizedPip=%s",
+                "isDesktopModeShowing: hasVisibleTasks=%s hasTopTransparentFullscreenTask=%s",
                 hasVisibleTasks,
                 hasTopTransparentFullscreenTask,
-                hasMinimizedPip,
             )
-            return hasVisibleTasks || hasTopTransparentFullscreenTask || hasMinimizedPip
-        } else if (Flags.enableDesktopWindowingPip()) {
-            logV(
-                "isDesktopModeShowing: hasVisibleTasks=%s hasMinimizedPip=%s",
-                hasVisibleTasks,
-                hasMinimizedPip,
-            )
-            return hasVisibleTasks || hasMinimizedPip
+            return hasVisibleTasks || hasTopTransparentFullscreenTask
         }
         logV("isDesktopModeShowing: hasVisibleTasks=%s", hasVisibleTasks)
         return hasVisibleTasks
@@ -537,8 +522,8 @@
             return false
         }
         logV("moveBackgroundTaskToDesktop with taskId=%d", taskId)
-        val taskIdToMinimize =
-            bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, taskId)
+        val deskId = getDefaultDeskId(task.displayId)
+        val runOnTransitStart = addDeskActivationChanges(deskId, wct, task)
         val exitResult =
             desktopImmersiveController.exitImmersiveIfApplicable(
                 wct = wct,
@@ -567,9 +552,7 @@
         desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(
             FREEFORM_ANIMATION_DURATION
         )
-        taskIdToMinimize?.let {
-            addPendingMinimizeTransition(transition, it, MinimizeReason.TASK_LIMIT)
-        }
+        runOnTransitStart?.invoke(transition)
         exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
         return true
     }
@@ -603,13 +586,7 @@
                 reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
             )
 
-        val taskIdToMinimize =
-            prepareMoveTaskToDeskAndActivate(
-                wct = wct,
-                displayId = displayId,
-                deskId = deskId,
-                task = task,
-            )
+        val runOnTransitStart = addDeskActivationWithMovingTaskChanges(deskId, wct, task)
 
         val transition: IBinder
         if (remoteTransition != null) {
@@ -624,63 +601,14 @@
         desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(
             FREEFORM_ANIMATION_DURATION
         )
-        taskIdToMinimize?.let {
-            addPendingMinimizeTransition(transition, it, MinimizeReason.TASK_LIMIT)
-        }
+        runOnTransitStart?.invoke(transition)
         exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
-        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
-            desksTransitionObserver.addPendingTransition(
-                DeskTransition.ActiveDeskWithTask(
-                    token = transition,
-                    displayId = displayId,
-                    deskId = deskId,
-                    enterTaskId = task.taskId,
-                )
-            )
-        } else {
+        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
             taskRepository.setActiveDesk(displayId = displayId, deskId = deskId)
         }
         return true
     }
 
-    /**
-     * Applies the necessary changes and operations to [wct] to move a task into a desk and
-     * activating that desk. This includes showing pre-existing tasks of that desk behind the new
-     * task (but minimizing one of them if needed) and showing Home and the desktop wallpaper.
-     *
-     * @return the id of the task that is being minimized, if any.
-     */
-    private fun prepareMoveTaskToDeskAndActivate(
-        wct: WindowContainerTransaction,
-        displayId: Int,
-        deskId: Int,
-        task: RunningTaskInfo,
-    ): Int? {
-        val taskIdToMinimize =
-            if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
-                // Activate the desk first.
-                prepareForDeskActivation(displayId, wct)
-                desksOrganizer.activateDesk(wct, deskId)
-                if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
-                    // TODO: b/362720497 - do non-running tasks need to be restarted with
-                    // |wct#startTask|?
-                }
-                taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
-                    doesAnyTaskRequireTaskbarRounding(displayId)
-                )
-                // TODO: b/362720497 - activating a desk with the intention to move a new task to
-                //  it means we may need to minimize something in the activating desk. Do so here
-                //  similar to how it's done in #bringDesktopAppsToFrontBeforeShowingNewTask
-                //  instead of returning null.
-                null
-            } else {
-                // Bring other apps to front first.
-                bringDesktopAppsToFrontBeforeShowingNewTask(displayId, wct, task.taskId)
-            }
-        addMoveToDeskTaskChanges(wct = wct, task = task, deskId = deskId)
-        return taskIdToMinimize
-    }
-
     private fun invokeCallbackToOverview(transition: IBinder, callback: IMoveToDesktopCallback?) {
         // TODO: b/333524374 - Remove this later.
         // This is a temporary implementation for adding CUJ end and
@@ -712,6 +640,7 @@
         dragToDesktopTransitionHandler.startDragToDesktopTransition(
             taskInfo,
             dragToDesktopValueAnimator,
+            visualIndicator,
         )
     }
 
@@ -738,13 +667,7 @@
                 moveHomeTask(context.displayId, wct)
             }
         }
-        val taskIdToMinimize =
-            prepareMoveTaskToDeskAndActivate(
-                wct = wct,
-                displayId = taskInfo.displayId,
-                deskId = deskId,
-                task = taskInfo,
-            )
+        val runOnTransitStart = addDeskActivationWithMovingTaskChanges(deskId, wct, taskInfo)
         val exitResult =
             desktopImmersiveController.exitImmersiveIfApplicable(
                 wct = wct,
@@ -757,20 +680,9 @@
             DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS.toInt()
         )
         if (transition != null) {
-            taskIdToMinimize?.let {
-                addPendingMinimizeTransition(transition, it, MinimizeReason.TASK_LIMIT)
-            }
+            runOnTransitStart?.invoke(transition)
             exitResult.asExit()?.runOnTransitionStart?.invoke(transition)
-            if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
-                desksTransitionObserver.addPendingTransition(
-                    DeskTransition.ActiveDeskWithTask(
-                        token = transition,
-                        displayId = taskInfo.displayId,
-                        deskId = deskId,
-                        enterTaskId = taskInfo.taskId,
-                    )
-                )
-            } else {
+            if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
                 taskRepository.setActiveDesk(displayId = taskInfo.displayId, deskId = deskId)
             }
         } else {
@@ -818,7 +730,6 @@
                 displayId = displayId,
                 forceExitDesktop = false,
             )
-        taskRepository.setPipShouldKeepDesktopActive(displayId, keepActive = true)
         val desktopExitRunnable =
             performDesktopExitCleanUp(
                 wct = wct,
@@ -888,7 +799,6 @@
         val wct = WindowContainerTransaction()
 
         snapEventHandler.removeTaskIfTiled(displayId, taskId)
-        taskRepository.setPipShouldKeepDesktopActive(displayId, keepActive = true)
         val willExitDesktop = willExitDesktop(taskId, displayId, forceExitDesktop = false)
         val desktopExitRunnable =
             performDesktopExitCleanUp(
@@ -1003,11 +913,9 @@
         // handles case where we are moving to full screen without closing all DW tasks.
         if (
             !taskRepository.isOnlyVisibleNonClosingTask(task.taskId)
-            // This callback is already invoked by |addMoveToFullscreenChanges| when one of these
-            // flags is enabled.
-            &&
-                !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue &&
-                !Flags.enableDesktopWindowingPip()
+            // This callback is already invoked by |addMoveToFullscreenChanges| when this flag is
+            // enabled.
+            && !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue
         ) {
             desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(
                 FULLSCREEN_ANIMATION_DURATION
@@ -1129,19 +1037,14 @@
                         ?: getDefaultDeskId(displayId)
                 )
             val activateDeskWct = WindowContainerTransaction()
-            addDeskActivationChanges(deskIdToActivate, activateDeskWct)
+            // TODO: b/391485148 - pass in the launching task here to apply task-limit policy,
+            //  but make sure to not do it twice since it is also done at the start of this
+            //  function.
+            activationRunOnTransitStart =
+                addDeskActivationChanges(deskIdToActivate, activateDeskWct)
             // Desk activation must be handled before app launch-related transactions.
             activateDeskWct.merge(launchTransaction, /* transfer= */ true)
             launchTransaction = activateDeskWct
-            activationRunOnTransitStart = { transition ->
-                desksTransitionObserver.addPendingTransition(
-                    DeskTransition.ActivateDesk(
-                        token = transition,
-                        displayId = displayId,
-                        deskId = deskIdToActivate,
-                    )
-                )
-            }
             desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(
                 FREEFORM_ANIMATION_DURATION
             )
@@ -1300,7 +1203,8 @@
                 } else {
                     null
                 }
-            val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null)
+            val transition =
+                transitions.startTransition(TRANSIT_CHANGE, wct, moveToDisplayTransitionHandler)
             deactivationRunnable?.invoke(transition)
             return
         }
@@ -1327,17 +1231,8 @@
             wct.reparent(task.token, displayAreaInfo.token, /* onTop= */ true)
         }
 
-        addDeskActivationChanges(destinationDeskId, wct)
-        val activationRunnable: RunOnTransitStart = { transition ->
-            desksTransitionObserver.addPendingTransition(
-                DeskTransition.ActiveDeskWithTask(
-                    token = transition,
-                    displayId = displayId,
-                    deskId = destinationDeskId,
-                    enterTaskId = task.taskId,
-                )
-            )
-        }
+        // TODO: b/391485148 - pass in the moving-to-desk |task| here to apply task-limit policy.
+        val activationRunnable = addDeskActivationChanges(destinationDeskId, wct)
 
         if (Flags.enableDisplayFocusInShellTransitions()) {
             // Bring the destination display to top with includingParents=true, so that the
@@ -1368,7 +1263,8 @@
             } else {
                 null
             }
-        val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ null)
+        val transition =
+            transitions.startTransition(TRANSIT_CHANGE, wct, moveToDisplayTransitionHandler)
         deactivationRunnable?.invoke(transition)
         activationRunnable?.invoke(transition)
     }
@@ -1733,13 +1629,10 @@
         }
     }
 
-    private fun bringDesktopAppsToFrontBeforeShowingNewTask(
-        displayId: Int,
-        wct: WindowContainerTransaction,
-        newTaskIdInFront: Int,
-    ): Int? = bringDesktopAppsToFront(displayId, wct, newTaskIdInFront)
-
-    @Deprecated("Use activeDesk() instead.", ReplaceWith("activateDesk()"))
+    @Deprecated(
+        "Use addDeskActivationChanges() instead.",
+        ReplaceWith("addDeskActivationChanges()"),
+    )
     private fun bringDesktopAppsToFront(
         displayId: Int,
         wct: WindowContainerTransaction,
@@ -1911,11 +1804,7 @@
         displayId: Int,
         forceExitDesktop: Boolean,
     ): Boolean {
-        if (
-            forceExitDesktop &&
-                (Flags.enableDesktopWindowingPip() ||
-                    DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue)
-        ) {
+        if (forceExitDesktop && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
             // |forceExitDesktop| is true when the callers knows we'll exit desktop, such as when
             // explicitly going fullscreen, so there's no point in checking the desktop state.
             return true
@@ -1924,11 +1813,6 @@
             if (!taskRepository.isOnlyVisibleNonClosingTask(triggerTaskId, displayId)) {
                 return false
             }
-        } else if (
-            Flags.enableDesktopWindowingPip() &&
-                taskRepository.isMinimizedPipPresentInDisplay(displayId)
-        ) {
-            return false
         } else {
             if (!taskRepository.isOnlyVisibleNonClosingTask(triggerTaskId)) {
                 return false
@@ -1945,7 +1829,6 @@
         forceToFullscreen: Boolean,
         shouldEndUpAtHome: Boolean = true,
     ): RunOnTransitStart? {
-        taskRepository.setPipShouldKeepDesktopActive(displayId, keepActive = !forceToFullscreen)
         if (!willExitDesktop(taskId, displayId, forceToFullscreen)) {
             return null
         }
@@ -2363,7 +2246,9 @@
                 runOnTransitStart?.invoke(transition)
                 return wct
             }
-            bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId)
+            val deskId = getDefaultDeskId(task.displayId)
+            val runOnTransitStart = addDeskActivationChanges(deskId, wct, task)
+            runOnTransitStart?.invoke(transition)
             wct.reorder(task.token, true)
             return wct
         }
@@ -2426,25 +2311,42 @@
             return WindowContainerTransaction().also { wct ->
                 val deskId = getDefaultDeskId(task.displayId)
                 addMoveToDeskTaskChanges(wct = wct, task = task, deskId = deskId)
-                // In some launches home task is moved behind new task being launched. Make sure
-                // that's not the case for launches in desktop. Also, if this launch is the first
-                // one to trigger the desktop mode (e.g., when [forceEnterDesktop()]), activate the
-                // desktop mode here.
-                if (
-                    task.baseIntent.flags.and(Intent.FLAG_ACTIVITY_TASK_ON_HOME) != 0 ||
-                        !isDesktopModeShowing(task.displayId)
-                ) {
-                    bringDesktopAppsToFrontBeforeShowingNewTask(task.displayId, wct, task.taskId)
-                    wct.reorder(task.token, true)
-                }
-
-                // Desktop Mode is already showing and we're launching a new Task - we might need to
-                // minimize another Task.
-                val taskIdToMinimize = addAndGetMinimizeChanges(task.displayId, wct, task.taskId)
-                taskIdToMinimize?.let {
-                    addPendingMinimizeTransition(transition, it, MinimizeReason.TASK_LIMIT)
-                }
-                addPendingAppLaunchTransition(transition, task.taskId, taskIdToMinimize)
+                val runOnTransitStart: RunOnTransitStart? =
+                    if (
+                        task.baseIntent.flags.and(Intent.FLAG_ACTIVITY_TASK_ON_HOME) != 0 ||
+                            !isDesktopModeShowing(task.displayId)
+                    ) {
+                        // In some launches home task is moved behind new task being launched. Make
+                        // sure that's not the case for launches in desktop. Also, if this launch is
+                        // the first one to trigger the desktop mode (e.g., when
+                        // [forceEnterDesktop()]), activate the desk here.
+                        val activationRunnable =
+                            addDeskActivationChanges(
+                                deskId = deskId,
+                                wct = wct,
+                                newTask = task,
+                                addPendingLaunchTransition = true,
+                            )
+                        wct.reorder(task.token, true)
+                        activationRunnable
+                    } else {
+                        { transition: IBinder ->
+                            // The desk was already showing and we're launching a new Task - we
+                            // might need to minimize another Task.
+                            val taskIdToMinimize =
+                                addAndGetMinimizeChanges(task.displayId, wct, task.taskId)
+                            taskIdToMinimize?.let { minimizingTaskId ->
+                                addPendingMinimizeTransition(
+                                    transition,
+                                    minimizingTaskId,
+                                    MinimizeReason.TASK_LIMIT,
+                                )
+                            }
+                            // Also track the pending launching task.
+                            addPendingAppLaunchTransition(transition, task.taskId, taskIdToMinimize)
+                        }
+                    }
+                runOnTransitStart?.invoke(transition)
                 desktopImmersiveController.exitImmersiveIfApplicable(
                     transition,
                     wct,
@@ -2559,6 +2461,20 @@
     }
 
     /**
+     * Applies the [wct] changes need when a task is first moving to a desk and the desk needs to be
+     * activated.
+     */
+    private fun addDeskActivationWithMovingTaskChanges(
+        deskId: Int,
+        wct: WindowContainerTransaction,
+        task: RunningTaskInfo,
+    ): RunOnTransitStart? {
+        val runOnTransitStart = addDeskActivationChanges(deskId, wct, task)
+        addMoveToDeskTaskChanges(wct = wct, task = task, deskId = deskId)
+        return runOnTransitStart
+    }
+
+    /**
      * Applies the [wct] changes needed when a task is first moving to a desk.
      *
      * Note that this recalculates the initial bounds of the task, so it should not be used when
@@ -2697,7 +2613,6 @@
         if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
             wct.reparent(taskInfo.token, tdaInfo.token, /* onTop= */ true)
         }
-        taskRepository.setPipShouldKeepDesktopActive(taskInfo.displayId, keepActive = false)
         val deskId = taskRepository.getDeskIdForTask(taskInfo.taskId)
         return performDesktopExitCleanUp(
             wct = wct,
@@ -2826,28 +2741,74 @@
         activateDesk(deskId, remoteTransition)
     }
 
-    /** Activates the given desk but without starting a transition. */
-    fun addDeskActivationChanges(deskId: Int, wct: WindowContainerTransaction) {
+    /**
+     * Applies the necessary [wct] changes to activate the given desk.
+     *
+     * When a task is being brought into a desk together with the activation, then [newTask] is not
+     * null and may be used to run other desktop policies, such as minimizing another task if the
+     * task limit has been exceeded.
+     */
+    fun addDeskActivationChanges(
+        deskId: Int,
+        wct: WindowContainerTransaction,
+        newTask: TaskInfo? = null,
+        // TODO: b/362720497 - should this be true in other places? Can it be calculated locally
+        //  without having to specify the value?
+        addPendingLaunchTransition: Boolean = false,
+    ): RunOnTransitStart? {
+        logV("addDeskActivationChanges newTaskId=%d deskId=%d", newTask?.taskId, deskId)
+        val newTaskIdInFront = newTask?.taskId
         val displayId = taskRepository.getDisplayForDesk(deskId)
-        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
-            prepareForDeskActivation(displayId, wct)
-            desksOrganizer.activateDesk(wct, deskId)
-            if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
-                // TODO: 362720497 - do non-running tasks need to be restarted with |wct#startTask|?
+        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
+            val taskIdToMinimize = bringDesktopAppsToFront(displayId, wct, newTask?.taskId)
+            return { transition ->
+                taskIdToMinimize?.let { minimizingTaskId ->
+                    addPendingMinimizeTransition(
+                        transition = transition,
+                        taskIdToMinimize = minimizingTaskId,
+                        minimizeReason = MinimizeReason.TASK_LIMIT,
+                    )
+                }
+                if (newTask != null && addPendingLaunchTransition) {
+                    addPendingAppLaunchTransition(transition, newTask.taskId, taskIdToMinimize)
+                }
             }
-            taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
-                doesAnyTaskRequireTaskbarRounding(displayId)
-            )
-        } else {
-            bringDesktopAppsToFront(displayId, wct)
+        }
+        prepareForDeskActivation(displayId, wct)
+        desksOrganizer.activateDesk(wct, deskId)
+        if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
+            // TODO: 362720497 - do non-running tasks need to be restarted with |wct#startTask|?
+        }
+        taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
+            doesAnyTaskRequireTaskbarRounding(displayId)
+        )
+        // TODO: b/362720497 - activating a desk with the intention to move a new task to
+        //  it means we may need to minimize something in the activating desk. Do so here
+        //  similar to how it's done in #bringDesktopAppsToFront.
+        return { transition ->
+            val activateDeskTransition =
+                if (newTaskIdInFront != null) {
+                    DeskTransition.ActiveDeskWithTask(
+                        token = transition,
+                        displayId = displayId,
+                        deskId = deskId,
+                        enterTaskId = newTaskIdInFront,
+                    )
+                } else {
+                    DeskTransition.ActivateDesk(
+                        token = transition,
+                        displayId = displayId,
+                        deskId = deskId,
+                    )
+                }
+            desksTransitionObserver.addPendingTransition(activateDeskTransition)
         }
     }
 
     /** Activates the given desk. */
     fun activateDesk(deskId: Int, remoteTransition: RemoteTransition? = null) {
-        val displayId = taskRepository.getDisplayForDesk(deskId)
         val wct = WindowContainerTransaction()
-        addDeskActivationChanges(deskId, wct)
+        val runOnTransitStart = addDeskActivationChanges(deskId, wct)
 
         val transitionType = transitionType(remoteTransition)
         val handler =
@@ -2857,15 +2818,7 @@
 
         val transition = transitions.startTransition(transitionType, wct, handler)
         handler?.setTransition(transition)
-        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
-            desksTransitionObserver.addPendingTransition(
-                DeskTransition.ActivateDesk(
-                    token = transition,
-                    displayId = displayId,
-                    deskId = deskId,
-                )
-            )
-        }
+        runOnTransitStart?.invoke(transition)
 
         desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(
             FREEFORM_ANIMATION_DURATION
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
index f9ab359..da369f0 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt
@@ -38,17 +38,17 @@
 import com.android.wm.shell.transition.Transitions.TransitionObserver
 
 /**
- * Limits the number of tasks shown in Desktop Mode.
+ * Keeps track of minimized tasks and limits the number of tasks shown in Desktop Mode.
  *
- * This class should only be used if
- * [android.window.DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_TASK_LIMIT] is enabled and
- * [maxTasksLimit] is strictly greater than 0.
+ * [maxTasksLimit] must be strictly greater than 0 if it's given.
+ *
+ * TODO(b/400634379): Separate two responsibilities of this class into two classes.
  */
 class DesktopTasksLimiter(
     transitions: Transitions,
     private val desktopUserRepositories: DesktopUserRepositories,
     private val shellTaskOrganizer: ShellTaskOrganizer,
-    private val maxTasksLimit: Int,
+    private val maxTasksLimit: Int?,
     private val interactionJankMonitor: InteractionJankMonitor,
     private val context: Context,
     @ShellMainThread private val handler: Handler,
@@ -59,13 +59,19 @@
     private var userId: Int
 
     init {
-        require(maxTasksLimit > 0) {
-            "DesktopTasksLimiter: maxTasksLimit should be greater than 0. Current value: $maxTasksLimit."
+        maxTasksLimit?.let {
+            require(it > 0) {
+                "DesktopTasksLimiter: maxTasksLimit should be greater than 0. Current value: $it."
+            }
         }
         transitions.registerObserver(minimizeTransitionObserver)
         userId = ActivityManager.getCurrentUser()
         desktopUserRepositories.current.addActiveTaskListener(leftoverMinimizedTasksRemover)
-        logV("Starting limiter with a maximum of %d tasks", maxTasksLimit)
+        if (maxTasksLimit != null) {
+            logV("Starting limiter with a maximum of %d tasks", maxTasksLimit)
+        } else {
+            logV("Starting limiter without the task limit")
+        }
     }
 
     data class TaskDetails(
@@ -268,6 +274,7 @@
         // If it's a running task, reorder it to back.
         taskIdToMinimize
             ?.let { shellTaskOrganizer.getRunningTaskInfo(it) }
+            // TODO: b/391485148 - this won't really work with multi-desks enabled.
             ?.let { wct.reorder(it.token, /* onTop= */ false) }
         return taskIdToMinimize
     }
@@ -324,7 +331,7 @@
         launchingNewIntent: Boolean,
     ): Int? {
         val newTasksOpening = if (launchingNewIntent) 1 else 0
-        if (visibleOrderedTasks.size + newTasksOpening <= maxTasksLimit) {
+        if (visibleOrderedTasks.size + newTasksOpening <= (maxTasksLimit ?: Int.MAX_VALUE)) {
             logV("No need to minimize; tasks below limit")
             // No need to minimize anything
             return null
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
index df2cf67..bd9c30e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
@@ -25,7 +25,6 @@
 import android.view.WindowManager.TRANSIT_OPEN
 import android.view.WindowManager.TRANSIT_PIP
 import android.view.WindowManager.TRANSIT_TO_BACK
-import android.view.WindowManager.TRANSIT_TO_FRONT
 import android.window.DesktopExperienceFlags
 import android.window.DesktopModeFlags
 import android.window.DesktopModeFlags.ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER
@@ -33,7 +32,6 @@
 import android.window.TransitionInfo
 import android.window.WindowContainerTransaction
 import com.android.internal.protolog.ProtoLog
-import com.android.window.flags.Flags
 import com.android.wm.shell.ShellTaskOrganizer
 import com.android.wm.shell.back.BackAnimationController
 import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.isExitDesktopModeTransition
@@ -108,7 +106,7 @@
         info.changes.forEach { change ->
             change.taskInfo?.let { taskInfo ->
                 if (
-                    Flags.enableDesktopWindowingPip() &&
+                    DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue &&
                         desktopRepository.isTaskMinimizedPipInDisplay(
                             taskInfo.displayId,
                             taskInfo.taskId,
@@ -332,10 +330,6 @@
                                 taskInfo.token,
                                 taskInfo.displayId,
                             )
-                            desktopWallpaperActivityTokenProvider.setWallpaperActivityIsVisible(
-                                isVisible = true,
-                                taskInfo.displayId,
-                            )
                             // After the task for the wallpaper is created, set it non-trimmable.
                             // This is important to prevent recents from trimming and removing the
                             // task.
@@ -346,16 +340,6 @@
                         }
                         TRANSIT_CLOSE ->
                             desktopWallpaperActivityTokenProvider.removeToken(taskInfo.displayId)
-                        TRANSIT_TO_FRONT ->
-                            desktopWallpaperActivityTokenProvider.setWallpaperActivityIsVisible(
-                                isVisible = true,
-                                taskInfo.displayId,
-                            )
-                        TRANSIT_TO_BACK ->
-                            desktopWallpaperActivityTokenProvider.setWallpaperActivityIsVisible(
-                                isVisible = false,
-                                taskInfo.displayId,
-                            )
                         else -> {}
                     }
                 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
index d396d8b..e943c42 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandler.kt
@@ -25,6 +25,7 @@
 import android.os.UserHandle
 import android.view.SurfaceControl
 import android.view.WindowManager.TRANSIT_CLOSE
+import android.window.DesktopModeFlags
 import android.window.TransitionInfo
 import android.window.TransitionInfo.Change
 import android.window.TransitionRequestInfo
@@ -118,6 +119,7 @@
     fun startDragToDesktopTransition(
         taskInfo: RunningTaskInfo,
         dragToDesktopAnimator: MoveToDesktopAnimator,
+        visualIndicator: DesktopModeVisualIndicator?,
     ) {
         if (inProgress) {
             logV("Drag to desktop transition already in progress.")
@@ -163,12 +165,14 @@
                     dragAnimator = dragToDesktopAnimator,
                     startTransitionToken = startTransitionToken,
                     otherSplitTask = otherTask,
+                    visualIndicator = visualIndicator,
                 )
             } else {
                 TransitionState.FromFullscreen(
                     draggedTaskId = taskInfo.taskId,
                     dragAnimator = dragToDesktopAnimator,
                     startTransitionToken = startTransitionToken,
+                    visualIndicator = visualIndicator,
                 )
             }
     }
@@ -277,6 +281,7 @@
         val state = requireTransitionState()
         val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo")
         val animatedTaskBounds = getAnimatedTaskBounds()
+        state.dragAnimator.cancelAnimator()
         requestSplitSelect(wct, taskInfo, splitPosition, animatedTaskBounds)
     }
 
@@ -288,7 +293,6 @@
         val scaledWidth = taskBounds.width() * taskScale
         val scaledHeight = taskBounds.height() * taskScale
         val dragPosition = PointF(state.dragAnimator.position)
-        state.dragAnimator.cancelAnimator()
         return Rect(
             dragPosition.x.toInt(),
             dragPosition.y.toInt(),
@@ -321,22 +325,24 @@
         // TODO(b/391928049): update density once we can drag from desktop to bubble
         val state = requireTransitionState()
         val taskInfo = state.draggedTaskChange?.taskInfo ?: error("Expected non-null taskInfo")
-        val taskBounds = getAnimatedTaskBounds()
+        val dragPosition = PointF(state.dragAnimator.position)
+        val scale = state.dragAnimator.scale
         state.dragAnimator.cancelAnimator()
-        requestBubble(wct, taskInfo, onLeft, taskBounds)
+        requestBubble(wct, taskInfo, onLeft, scale, dragPosition)
     }
 
     private fun requestBubble(
         wct: WindowContainerTransaction,
         taskInfo: RunningTaskInfo,
         onLeft: Boolean,
-        taskBounds: Rect = Rect(taskInfo.configuration.windowConfiguration.bounds),
+        taskScale: Float = 1f,
+        dragPosition: PointF = PointF(0f, 0f),
     ) {
         val controller =
             bubbleController.orElseThrow { IllegalStateException("BubbleController not set") }
         controller.expandStackAndSelectBubble(
             taskInfo,
-            BubbleTransitions.DragData(taskBounds, wct, onLeft),
+            BubbleTransitions.DragData(onLeft, taskScale, dragPosition, wct),
         )
     }
 
@@ -457,6 +463,13 @@
         state.surfaceLayers = layers
         state.startTransitionFinishCb = finishCallback
         state.startTransitionFinishTransaction = finishTransaction
+
+        val taskChange = state.draggedTaskChange ?: error("Expected non-null task change.")
+        val taskInfo = taskChange.taskInfo ?: error("Expected non-null task info.")
+
+        if (DesktopModeFlags.ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX.isTrue) {
+            attachIndicatorToTransitionRoot(state, info, taskInfo, startTransaction)
+        }
         startTransaction.apply()
 
         if (state.cancelState == CancelState.NO_CANCEL) {
@@ -485,8 +498,6 @@
                 } else {
                     SPLIT_POSITION_BOTTOM_OR_RIGHT
                 }
-            val taskInfo =
-                state.draggedTaskChange?.taskInfo ?: error("Expected non-null task info.")
             val wct = WindowContainerTransaction()
             restoreWindowOrder(wct)
             state.startTransitionFinishTransaction?.apply()
@@ -511,6 +522,21 @@
         return true
     }
 
+    private fun attachIndicatorToTransitionRoot(
+        state: TransitionState,
+        info: TransitionInfo,
+        taskInfo: RunningTaskInfo,
+        t: SurfaceControl.Transaction,
+    ) {
+        val transitionRoot = info.getRoot(info.findRootIndex(taskInfo.displayId))
+        state.visualIndicator?.let {
+            // Attach the indicator to the transition root so that it's removed at the end of the
+            // transition regardless of whether we managed to release the indicator.
+            it.reparentLeash(t, transitionRoot.leash)
+            it.fadeInIndicator()
+        }
+    }
+
     /**
      * Calculates start drag to desktop layers for transition [info]. The leash layer is calculated
      * based on its change position in the transition, e.g. `appLayer = appLayers - i`, where i is
@@ -901,6 +927,7 @@
         abstract var surfaceLayers: DragToDesktopLayers?
         abstract var cancelState: CancelState
         abstract var startAborted: Boolean
+        abstract val visualIndicator: DesktopModeVisualIndicator?
 
         data class FromFullscreen(
             override val draggedTaskId: Int,
@@ -915,6 +942,7 @@
             override var surfaceLayers: DragToDesktopLayers? = null,
             override var cancelState: CancelState = CancelState.NO_CANCEL,
             override var startAborted: Boolean = false,
+            override val visualIndicator: DesktopModeVisualIndicator?,
             var otherRootChanges: MutableList<Change> = mutableListOf(),
         ) : TransitionState()
 
@@ -931,6 +959,7 @@
             override var surfaceLayers: DragToDesktopLayers? = null,
             override var cancelState: CancelState = CancelState.NO_CANCEL,
             override var startAborted: Boolean = false,
+            override val visualIndicator: DesktopModeVisualIndicator?,
             var splitRootChange: Change? = null,
             var otherSplitTask: Int,
         ) : TransitionState()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
index 5e84019..1a66ca8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/ToggleResizeDesktopTaskTransitionHandler.kt
@@ -47,6 +47,7 @@
 
     private var boundsAnimator: Animator? = null
     private var initialBounds: Rect? = null
+    private var callback: (() -> Unit)? = null
 
     constructor(
         transitions: Transitions,
@@ -61,9 +62,14 @@
      *   bounds of the actual task). This is provided so that the animation resizing can begin where
      *   the task leash currently is for smoother UX.
      */
-    fun startTransition(wct: WindowContainerTransaction, taskLeashBounds: Rect? = null) {
+    fun startTransition(
+        wct: WindowContainerTransaction,
+        taskLeashBounds: Rect? = null,
+        callback: (() -> Unit)? = null,
+    ) {
         transitions.startTransition(TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE, wct, this)
         initialBounds = taskLeashBounds
+        this.callback = callback
     }
 
     fun setOnTaskResizeAnimationListener(listener: OnTaskResizeAnimationListener) {
@@ -121,6 +127,8 @@
                             interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_MAXIMIZE_WINDOW)
                             interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_UNMAXIMIZE_WINDOW)
                             interactionJankMonitor.end(Cuj.CUJ_DESKTOP_MODE_SNAP_RESIZE)
+                            callback?.invoke()
+                            callback = null
                         },
                     )
                     addUpdateListener { anim ->
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt
index 919e816..2356238 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainer.kt
@@ -130,6 +130,12 @@
         }
     }
 
+    /** Reparent the indicator to {@code newParent}. */
+    fun reparentLeash(t: SurfaceControl.Transaction, newParent: SurfaceControl) {
+        val leash = indicatorLeash ?: return
+        t.reparent(leash, newParent)
+    }
+
     private fun showIndicator(taskSurface: SurfaceControl, leash: SurfaceControl) {
         mainExecutor.execute {
             indicatorLeash = leash
@@ -166,7 +172,7 @@
                 displayController.getDisplayLayout(taskInfo.displayId)
                     ?: error("Expected to find DisplayLayout for taskId${taskInfo.taskId}.")
             if (currentType == IndicatorType.NO_INDICATOR) {
-                fadeInIndicator(layout, newType, taskInfo.displayId, snapEventHandler)
+                fadeInIndicatorInternal(layout, newType, taskInfo.displayId, snapEventHandler)
             } else if (newType == IndicatorType.NO_INDICATOR) {
                 fadeOutIndicator(
                     layout,
@@ -195,10 +201,22 @@
     }
 
     /**
+     * Fade indicator in as provided type.
+     *
+     * Animator fades the indicator in while expanding the bounds outwards.
+     */
+    fun fadeInIndicator(layout: DisplayLayout, type: IndicatorType, displayId: Int) {
+        if (isReleased) return
+        desktopExecutor.execute {
+            fadeInIndicatorInternal(layout, type, displayId, snapEventHandler)
+        }
+    }
+
+    /**
      * Fade indicator in as provided type. Animator fades it in while expanding the bounds outwards.
      */
     @VisibleForTesting
-    fun fadeInIndicator(
+    fun fadeInIndicatorInternal(
         layout: DisplayLayout,
         type: IndicatorType,
         displayId: Int,
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt
index b5490cb..d185ed5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/desktopwallpaperactivity/DesktopWallpaperActivityTokenProvider.kt
@@ -17,7 +17,6 @@
 package com.android.wm.shell.desktopmode.desktopwallpaperactivity
 
 import android.util.SparseArray
-import android.util.SparseBooleanArray
 import android.view.Display.DEFAULT_DISPLAY
 import android.window.WindowContainerToken
 import androidx.core.util.keyIterator
@@ -28,7 +27,6 @@
 class DesktopWallpaperActivityTokenProvider {
 
     private val wallpaperActivityTokenByDisplayId = SparseArray<WindowContainerToken>()
-    private val wallpaperActivityVisByDisplayId = SparseBooleanArray()
 
     fun setToken(token: WindowContainerToken, displayId: Int = DEFAULT_DISPLAY) {
         logV("Setting desktop wallpaper activity token for display %s", displayId)
@@ -55,18 +53,6 @@
         }
     }
 
-    fun setWallpaperActivityIsVisible(
-        isVisible: Boolean = false,
-        displayId: Int = DEFAULT_DISPLAY,
-    ) {
-        wallpaperActivityVisByDisplayId.put(displayId, isVisible)
-    }
-
-    fun isWallpaperActivityVisible(displayId: Int = DEFAULT_DISPLAY): Boolean {
-        return wallpaperActivityTokenByDisplayId[displayId] != null &&
-            wallpaperActivityVisByDisplayId.get(displayId, false)
-    }
-
     private fun logV(msg: String, vararg arguments: Any?) {
         ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/dagger.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/dagger.md
index 9b09904..84525a7 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/dagger.md
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/dagger.md
@@ -1,4 +1,5 @@
 # Usage of Dagger in the Shell library
+
 [Back to home](README.md)
 
 ---
@@ -16,36 +17,69 @@
 ## Modules
 
 All the Dagger related code in the Shell can be found in the `com.android.wm.shell.dagger` package,
-this is intentional as it keeps the "magic" in a single location.  The explicit nature of how
+this is intentional as it keeps the "magic" in a single location. The explicit nature of how
 components in the shell are provided is as a result a bit more verbose, but it makes it easy for
 developers to jump into a few select files and understand how different components are provided
 (especially as products override components).
 
 The module dependency tree looks a bit like:
+
 - [WMShellConcurrencyModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellConcurrencyModule.java)
   (provides threading-related components)
-  - [WMShellBaseModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java)
-    (provides components that are likely common to all products, ie. DisplayController,
-    Transactions, etc.)
-    - [WMShellModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java)
-      (phone/tablet specific components only)
-    - [TvPipModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java)
-      (PIP specific components for TV)
-      - [TvWMShellModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java)
-        (TV specific components only)
-  - etc.
+    - [WMShellBaseModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java)
+      (provides components that are common to many products, ie. DisplayController, Transactions,
+      etc.)
+        - [WMShellModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java)
+          (phone/tablet specific components only)
+        - [TvPipModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java)
+          (PIP specific components for TV)
+            - [TvWMShellModule](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvWMShellModule.java)
+              (TV specific components only)
+    - etc.
 
 Ideally features could be abstracted out into their own modules and included as needed by each
 product.
 
+## Changing WMShellBaseModule
+
+Because all products will include WMShellBaseModule, we don't want it to provide instances for
+features that aren't used across multiple products (ie. Handheld, TV, Auto, Wear). This module
+should generally only provide:
+
+- Concrete implementations that are needed for startup
+  (see `provideIndependentShellComponentsToCreate()`)
+- Things used directly/indirectly by interfaces
+  exposed to SysUI
+  in [WMComponent.java](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMComponent.java).
+
+For the latter, not every feature will be enabled on the SysUI form factor including the base
+module, so the recommendation is to have an `@BindsOptionalOf` for the interface, and have the
+actual implementation provided in the form-factor specific module (ie. `WMShellModule`).
+
 ## Overriding base components
 
 In some rare cases, there are base components that can change behavior depending on which
-product it runs on.  If there are hooks that can be added to the component, that is the
+product it runs on. If there are hooks that can be added to the component, that is the
 preferable approach.
 
-The alternative is to use the [@DynamicOverride](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java)
+The alternative is to use
+the [@DynamicOverride](/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/DynamicOverride.java)
 annotation to allow the product module to provide an implementation that the base module can
-reference.  This is most useful if the existence of the entire component is controlled by the
-product and the override implementation is optional (there is a default implementation).  More
-details can be found in the class's javadoc.
\ No newline at end of file
+reference. This is most useful if the existence of the entire component is controlled by the
+product and the override implementation is optional (there is a default implementation). More
+details can be found in the class's javadoc.
+
+## Starting up Shell components aren't dependencies for other components
+
+With Dagger, objects are created in dependency order and individual components can register with
+`ShellInit` (see [Component initialization](changes.md#component-initialization)) to initialize in
+dependency order as well. However, if there is code that needs to run on startup but has nothing
+dependent on it (imagine a background error detector for example), then
+`provideIndependentShellComponentsToCreate()` can serve as the artificial dependent object (itself
+a dependency for `ShellInterface`) to trigger creation of such a component.
+
+This can be declared within each module, so if a product includes `WMShellModule`, all the
+components in `provideIndependentShellComponentsToCreate()` for both it and `WMShellBaseModule` will
+be created.
+
+Note that long term we are looking to move to a `CoreStartable` like infrastructure.
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 04f0336..0966110 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -70,6 +70,7 @@
 import android.view.Display;
 import android.view.Surface;
 import android.view.SurfaceControl;
+import android.window.DesktopModeFlags;
 import android.window.DisplayAreaInfo;
 import android.window.TaskOrganizer;
 import android.window.TaskSnapshot;
@@ -78,7 +79,6 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.protolog.ProtoLog;
-import com.android.window.flags.Flags;
 import com.android.wm.shell.R;
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.ShellTaskOrganizer;
@@ -781,7 +781,7 @@
     // TODO(b/377581840): Update this check to include non-minimized cases, e.g. split to PiP etc.
     private boolean isPipExitingToDesktopMode() {
         DesktopRepository currentRepo = getCurrentRepo();
-        return Flags.enableDesktopWindowingPip() && currentRepo != null
+        return DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue() && currentRepo != null
                 && (currentRepo.isAnyDeskActive(mTaskInfo.displayId)
                     || isDisplayInFreeform());
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
index 242f7fa..5706f19 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipResizeGestureHandler.java
@@ -39,11 +39,11 @@
 import android.view.InputMonitor;
 import android.view.MotionEvent;
 import android.view.ViewConfiguration;
+import android.window.DesktopModeFlags;
 
 import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.policy.TaskResizingAlgorithm;
-import com.android.window.flags.Flags;
 import com.android.wm.shell.R;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
@@ -183,7 +183,7 @@
     private void reloadResources() {
         final Resources res = mContext.getResources();
         mDelta = res.getDimensionPixelSize(R.dimen.pip_resize_edge_size);
-        mEnableDragCornerResize = Flags.enableDesktopWindowingPip();
+        mEnableDragCornerResize = DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue();
         mTouchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java
index a033b824..7918a21 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/animation/PipAlphaAnimator.java
@@ -131,9 +131,10 @@
     }
 
     private void onAlphaAnimationUpdate(float alpha, SurfaceControl.Transaction tx) {
+        // only set shadow radius on fade in
         tx.setAlpha(mLeash, alpha)
                 .setCornerRadius(mLeash, mCornerRadius)
-                .setShadowRadius(mLeash, mShadowRadius);
+                .setShadowRadius(mLeash, mDirection == FADE_IN ? mShadowRadius : 0f);
         tx.apply();
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
index 6012fe6..119763f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipController.java
@@ -238,7 +238,10 @@
             @Override
             public void onActivityRestartAttempt(ActivityManager.RunningTaskInfo task,
                     boolean homeTaskVisible, boolean clearedTask, boolean wasVisible) {
-                if (task.getWindowingMode() != WINDOWING_MODE_PINNED) {
+                ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
+                        "onActivityRestartAttempt: topActivity=%s, wasVisible=%b",
+                        task.topActivity, wasVisible);
+                if (task.getWindowingMode() != WINDOWING_MODE_PINNED || !wasVisible) {
                     return;
                 }
                 mPipScheduler.scheduleExitPipViaExpand();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInteractionHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInteractionHandler.java
new file mode 100644
index 0000000..3219524
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipInteractionHandler.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pip2.phone;
+
+import static com.android.internal.jank.Cuj.CUJ_PIP_TRANSITION;
+
+import android.annotation.IntDef;
+import android.content.Context;
+import android.os.Handler;
+import android.view.SurfaceControl;
+
+import com.android.internal.jank.InteractionJankMonitor;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Helps track PIP CUJ interactions
+ */
+public class PipInteractionHandler {
+    @IntDef(prefix = {"INTERACTION_"}, value = {
+            INTERACTION_EXIT_PIP,
+            INTERACTION_EXIT_PIP_TO_SPLIT
+    })
+
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface Interaction {}
+
+    public static final int INTERACTION_EXIT_PIP = 0;
+    public static final int INTERACTION_EXIT_PIP_TO_SPLIT = 1;
+
+    private final Context mContext;
+    private final Handler mHandler;
+    private final InteractionJankMonitor mInteractionJankMonitor;
+
+    public PipInteractionHandler(Context context, Handler handler,
+            InteractionJankMonitor interactionJankMonitor) {
+        mContext = context;
+        mHandler = handler;
+        mInteractionJankMonitor = interactionJankMonitor;
+    }
+
+    /**
+     * Begin tracking PIP CUJ.
+     *
+     * @param leash PIP leash.
+     * @param interaction Tag for interaction.
+     */
+    public void begin(SurfaceControl leash, @Interaction int interaction) {
+        mInteractionJankMonitor.begin(leash, mContext, mHandler, CUJ_PIP_TRANSITION,
+                pipInteractionToString(interaction));
+    }
+
+    /**
+     * End tracking CUJ.
+     */
+    public void end() {
+        mInteractionJankMonitor.end(CUJ_PIP_TRANSITION);
+    }
+
+    /**
+     * Converts an interaction to a string representation used for tagging.
+     *
+     * @param interaction Interaction to track.
+     * @return String representation of the interaction.
+     */
+    public static String pipInteractionToString(@Interaction int interaction) {
+        return switch (interaction) {
+            case INTERACTION_EXIT_PIP -> "EXIT_PIP";
+            case INTERACTION_EXIT_PIP_TO_SPLIT -> "EXIT_PIP_TO_SPLIT";
+            default -> "";
+        };
+    }
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
index 91fbd45..9bb2e38 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransition.java
@@ -113,6 +113,7 @@
     private final DisplayController mDisplayController;
     private final PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;
     private final PipDesktopState mPipDesktopState;
+    private final PipInteractionHandler mPipInteractionHandler;
 
     //
     // Transition caches
@@ -154,7 +155,8 @@
             PipUiStateChangeController pipUiStateChangeController,
             DisplayController displayController,
             Optional<SplitScreenController> splitScreenControllerOptional,
-            PipDesktopState pipDesktopState) {
+            PipDesktopState pipDesktopState,
+            PipInteractionHandler pipInteractionHandler) {
         super(shellInit, shellTaskOrganizer, transitions, pipBoundsState, pipMenuController,
                 pipBoundsAlgorithm);
 
@@ -168,9 +170,11 @@
         mDisplayController = displayController;
         mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(mContext);
         mPipDesktopState = pipDesktopState;
+        mPipInteractionHandler = pipInteractionHandler;
 
         mExpandHandler = new PipExpandHandler(mContext, pipBoundsState, pipBoundsAlgorithm,
-                pipTransitionState, pipDisplayLayoutState, splitScreenControllerOptional);
+                pipTransitionState, pipDisplayLayoutState, pipInteractionHandler,
+                splitScreenControllerOptional);
     }
 
     @Override
@@ -770,7 +774,7 @@
         // Since opening a new task while in Desktop Mode always first open in Fullscreen
         // until DesktopMode Shell code resolves it to Freeform, PipTransition will get a
         // possibility to handle it also. In this case return false to not have it enter PiP.
-        if (mPipDesktopState.isPipEnteringInDesktopMode(pipTask)) {
+        if (mPipDesktopState.isPipInDesktopMode()) {
             return false;
         }
 
@@ -794,9 +798,26 @@
                 setEnterAnimationType(ANIM_TYPE_BOUNDS);
                 return true;
             }
-            // If the only change in the changes list is a opening type PiP task,
+
+            // Sometimes root PiP task can have TF children. These child containers can be collected
+            // even if they can promote to their parents: e.g. if they are marked as "organized".
+            // So we count the chain of containers under PiP task as one "real" changing target;
+            // iterate through changes bottom-to-top to properly identify parents.
+            int expectedTargetCount = 1;
+            WindowContainerToken lastPipChildToken = pipChange.getContainer();
+            for (int i = info.getChanges().size() - 1; i >= 0; --i) {
+                TransitionInfo.Change change = info.getChanges().get(i);
+                if (change == pipChange || change.getContainer() == null) continue;
+                if (change.getParent() != null && change.getParent().equals(lastPipChildToken)) {
+                    // Allow an extra change since our pinned root task has a child.
+                    ++expectedTargetCount;
+                    lastPipChildToken = change.getContainer();
+                }
+            }
+
+            // If the only root task change in the changes list is a opening type PiP task,
             // then this is legacy-enter PiP.
-            return info.getChanges().size() == 1
+            return info.getChanges().size() == expectedTargetCount
                     && TransitionUtil.isOpeningMode(pipChange.getMode());
         }
         return false;
@@ -930,14 +951,6 @@
                         "Unexpected bundle for " + mPipTransitionState);
                 break;
             case PipTransitionState.EXITED_PIP:
-                if (mPipDesktopState.shouldExitPipExitDesktopMode()) {
-                    mTransitions.startTransition(
-                            TRANSIT_TO_BACK,
-                            mPipDesktopState.getWallpaperActivityTokenWct(
-                                    mPipTransitionState.getPipTaskInfo().getDisplayId()),
-                            null /* firstHandler */
-                    );
-                }
                 mPipTransitionState.setPinnedTaskLeash(null);
                 mPipTransitionState.setPipTaskInfo(null);
                 mPendingRemoveWithFadeout = false;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
index 18c9a70..9e2fbfe 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/PipTransitionState.java
@@ -26,9 +26,11 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
 
 import com.android.internal.protolog.ProtoLog;
 import com.android.internal.util.Preconditions;
+import com.android.wm.shell.common.pip.PipDesktopState;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.shared.annotations.ShellMainThread;
 
@@ -123,6 +125,8 @@
     @ShellMainThread
     private final Handler mMainHandler;
 
+    private final PipDesktopState mPipDesktopState;
+
     //
     // Swipe up to enter PiP related state
     //
@@ -172,8 +176,9 @@
 
     private final List<PipTransitionStateChangedListener> mCallbacks = new ArrayList<>();
 
-    public PipTransitionState(@ShellMainThread Handler handler) {
+    public PipTransitionState(@ShellMainThread Handler handler, PipDesktopState pipDesktopState) {
         mMainHandler = handler;
+        mPipDesktopState = pipDesktopState;
     }
 
     /**
@@ -384,12 +389,16 @@
         return ++mPrevCustomState;
     }
 
-    private boolean shouldTransitionToState(@TransitionState int newState) {
+    @VisibleForTesting
+    boolean shouldTransitionToState(@TransitionState int newState) {
         switch (newState) {
             case SCHEDULED_BOUNDS_CHANGE:
-                // Allow scheduling bounds change only while in PiP, except for if another bounds
-                // change was scheduled but hasn't started playing yet.
-                return isInPip();
+                // Allow scheduling bounds change only when both of these are true:
+                // - while in PiP, except for if another bounds change was scheduled but hasn't
+                //   started playing yet
+                // - there is no drag-to-desktop gesture in progress; otherwise the PiP resize
+                //   transition will block the drag-to-desktop transitions from finishing
+                return isInPip() && !mPipDesktopState.isDragToDesktopInProgress();
             default:
                 return true;
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandler.java
index db4942b..3274f4a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandler.java
@@ -45,6 +45,7 @@
 import com.android.wm.shell.common.pip.PipBoundsState;
 import com.android.wm.shell.common.pip.PipDisplayLayoutState;
 import com.android.wm.shell.pip2.animation.PipExpandAnimator;
+import com.android.wm.shell.pip2.phone.PipInteractionHandler;
 import com.android.wm.shell.pip2.phone.PipTransitionState;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.splitscreen.SplitScreenController;
@@ -58,6 +59,7 @@
     private final PipBoundsAlgorithm mPipBoundsAlgorithm;
     private final PipTransitionState mPipTransitionState;
     private final PipDisplayLayoutState mPipDisplayLayoutState;
+    private final PipInteractionHandler mPipInteractionHandler;
     private final Optional<SplitScreenController> mSplitScreenControllerOptional;
 
     @Nullable
@@ -72,12 +74,14 @@
             PipBoundsAlgorithm pipBoundsAlgorithm,
             PipTransitionState pipTransitionState,
             PipDisplayLayoutState pipDisplayLayoutState,
+            PipInteractionHandler pipInteractionHandler,
             Optional<SplitScreenController> splitScreenControllerOptional) {
         mContext = context;
         mPipBoundsState = pipBoundsState;
         mPipBoundsAlgorithm = pipBoundsAlgorithm;
         mPipTransitionState = pipTransitionState;
         mPipDisplayLayoutState = pipDisplayLayoutState;
+        mPipInteractionHandler = pipInteractionHandler;
         mSplitScreenControllerOptional = splitScreenControllerOptional;
 
         mPipExpandAnimatorSupplier = PipExpandAnimator::new;
@@ -183,6 +187,8 @@
         PipExpandAnimator animator = mPipExpandAnimatorSupplier.get(mContext, pipLeash,
                 startTransaction, finishTransaction, endBounds, startBounds, endBounds,
                 sourceRectHint, delta);
+        animator.setAnimationStartCallback(() -> mPipInteractionHandler.begin(pipLeash,
+                PipInteractionHandler.INTERACTION_EXIT_PIP));
         animator.setAnimationEndCallback(() -> {
             if (parentBeforePip != null) {
                 // TODO b/377362511: Animate local leash instead to also handle letterbox case.
@@ -190,6 +196,7 @@
                 finishTransaction.setCrop(pipLeash, null);
             }
             finishTransition();
+            mPipInteractionHandler.end();
         });
         cacheAndStartTransitionAnimator(animator);
         saveReentryState();
@@ -248,6 +255,8 @@
             splitController.finishEnterSplitScreen(finishTransaction);
         });
 
+        animator.setAnimationStartCallback(() -> mPipInteractionHandler.begin(pipLeash,
+                PipInteractionHandler.INTERACTION_EXIT_PIP_TO_SPLIT));
         animator.setAnimationEndCallback(() -> {
             if (parentBeforePip == null) {
                 // After PipExpandAnimator is done modifying finishTransaction, we need to make
@@ -256,6 +265,7 @@
                 finishTransaction.setPosition(pipLeash, 0, 0);
             }
             finishTransition();
+            mPipInteractionHandler.end();
         });
         cacheAndStartTransitionAnimator(animator);
         saveReentryState();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
index fed336b..65fa9b4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenTransitions.java
@@ -52,6 +52,7 @@
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.shared.TransactionPool;
 import com.android.wm.shell.shared.TransitionUtil;
+import com.android.wm.shell.shared.split.SplitScreenConstants;
 import com.android.wm.shell.transition.OneShotRemoteHandler;
 import com.android.wm.shell.transition.Transitions;
 
@@ -362,7 +363,8 @@
             WindowContainerTransaction wct,
             @Nullable RemoteTransition remoteTransition,
             Transitions.TransitionHandler handler,
-            int extraTransitType, boolean resizeAnim) {
+            int extraTransitType, boolean resizeAnim,
+            @SplitScreenConstants.PersistentSnapPosition int snapPosition) {
         if (mPendingEnter != null) {
             ProtoLog.v(WM_SHELL_TRANSITIONS, "  splitTransition "
                     + " skip to start enter split transition since it already exist. ");
@@ -373,16 +375,18 @@
                     .onSplitAnimationInvoked(true /*animationRunning*/));
         }
         final IBinder transition = mTransitions.startTransition(transitType, wct, handler);
-        setEnterTransition(transition, remoteTransition, extraTransitType, resizeAnim);
+        setEnterTransition(transition, remoteTransition, extraTransitType, resizeAnim,
+                snapPosition);
         return transition;
     }
 
     /** Sets a transition to enter split. */
     void setEnterTransition(@NonNull IBinder transition,
             @Nullable RemoteTransition remoteTransition,
-            int extraTransitType, boolean resizeAnim) {
+            int extraTransitType, boolean resizeAnim,
+            int snapPosition) {
         mPendingEnter = new EnterSession(
-                transition, remoteTransition, extraTransitType, resizeAnim);
+                transition, remoteTransition, extraTransitType, resizeAnim, snapPosition);
 
         ProtoLog.v(WM_SHELL_TRANSITIONS, "  splitTransition "
                 + " deduced Enter split screen");
@@ -675,13 +679,16 @@
     /** Bundled information of enter transition. */
     class EnterSession extends TransitSession {
         final boolean mResizeAnim;
+        /** The starting snap position we'll enter into with this transition. */
+        final @SplitScreenConstants.PersistentSnapPosition int mEnteringPosition;
 
         EnterSession(IBinder transition,
                 @Nullable RemoteTransition remoteTransition,
-                int extraTransitType, boolean resizeAnim) {
+                int extraTransitType, boolean resizeAnim, int snapPosition) {
             super(transition, null /* consumedCallback */, null /* finishedCallback */,
                     remoteTransition, extraTransitType);
             this.mResizeAnim = resizeAnim;
+            this.mEnteringPosition = snapPosition;
         }
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index a3a808d..7472b0e 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -653,7 +653,7 @@
                 null, this,
                 isSplitScreenVisible()
                         ? TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE : TRANSIT_SPLIT_SCREEN_PAIR_OPEN,
-                !mIsDropEntering);
+                !mIsDropEntering, SNAP_TO_2_50_50);
 
         // Due to drag already pip task entering split by this method so need to reset flag here.
         mIsDropEntering = false;
@@ -787,7 +787,7 @@
         prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering, index);
 
         mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct, null, this,
-                extraTransitType, !mIsDropEntering);
+                extraTransitType, !mIsDropEntering, SNAP_TO_2_50_50);
     }
 
     /**
@@ -833,7 +833,7 @@
         prepareEnterSplitScreen(wct, null /* taskInfo */, position, !mIsDropEntering, index);
 
         mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct, null, this,
-                extraTransitType, !mIsDropEntering);
+                extraTransitType, !mIsDropEntering, SNAP_TO_2_50_50);
     }
 
     /**
@@ -848,6 +848,27 @@
                 "startTasks: task1=%d task2=%d position=%d snapPosition=%d",
                 taskId1, taskId2, splitPosition, snapPosition);
         final WindowContainerTransaction wct = new WindowContainerTransaction();
+
+        // If the two tasks are already in split screen on external display, only reparent the
+        // split root to the default display if the app pair is clicked on default display.
+        // TODO(b/393217881): cover more cases and extract this to a new method when split screen
+        //  in connected display is fully supported.
+        if (enableNonDefaultDisplaySplit()) {
+            DisplayAreaInfo displayAreaInfo = mRootTDAOrganizer.getDisplayAreaInfo(DEFAULT_DISPLAY);
+            ActivityManager.RunningTaskInfo taskInfo1 = mTaskOrganizer.getRunningTaskInfo(taskId1);
+            ActivityManager.RunningTaskInfo taskInfo2 = mTaskOrganizer.getRunningTaskInfo(taskId2);
+
+            if (displayAreaInfo != null && taskInfo1 != null && taskInfo2 != null
+                    && getStageOfTask(taskId1) != STAGE_TYPE_UNDEFINED
+                    && getStageOfTask(taskId2) != STAGE_TYPE_UNDEFINED
+                    && taskInfo1.displayId != DEFAULT_DISPLAY
+                    && taskInfo1.displayId == taskInfo2.displayId) {
+                wct.reparent(mRootTaskInfo.token, displayAreaInfo.token, true);
+                mTaskOrganizer.applyTransaction(wct);
+                return;
+            }
+        }
+
         if (taskId2 == INVALID_TASK_ID) {
             startSingleTask(taskId1, options1, wct, remoteTransition);
             return;
@@ -1029,7 +1050,7 @@
             mPausingTasks.clear();
         }
         mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct, remoteTransition, this,
-                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false);
+                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false, snapPosition);
         setEnterInstanceId(instanceId);
     }
 
@@ -1119,7 +1140,7 @@
         }
 
         mSplitTransitions.startEnterTransition(TRANSIT_TO_FRONT, wct, remoteTransition, this,
-                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false);
+                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false, snapPosition);
         setEnterInstanceId(instanceId);
     }
 
@@ -1624,6 +1645,14 @@
         grantFocusToStage(stageToFocus);
     }
 
+    private void grantFocusForSnapPosition(@PersistentSnapPosition int enteringPosition) {
+        switch (enteringPosition) {
+            case SNAP_TO_2_90_10 -> grantFocusToPosition(true /*leftOrTop*/);
+            case SNAP_TO_2_10_90 -> grantFocusToPosition(false /*leftOrTop*/);
+            default -> { /*no-op*/ }
+        }
+    }
+
     private void clearRequestIfPresented() {
         ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "clearRequestIfPresented");
         if (mSideStage.mVisible && mSideStage.mHasChildren
@@ -2890,7 +2919,7 @@
                     // split, prepare to enter split screen.
                     prepareEnterSplitScreen(out);
                     mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
-                            TRANSIT_SPLIT_SCREEN_PAIR_OPEN, !mIsDropEntering);
+                            TRANSIT_SPLIT_SCREEN_PAIR_OPEN, !mIsDropEntering, SNAP_TO_2_50_50);
                 } else if (isSplitScreenVisible() && isOpening) {
                     // launching into an existing split stage; possibly launchAdjacent
                     // If we're replacing a pip-able app, we need to let mixed handler take care of
@@ -2899,7 +2928,8 @@
                         // updated layout will get applied in startAnimation pendingResize
                         mSplitTransitions.setEnterTransition(transition,
                                 request.getRemoteTransition(),
-                                TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, true /*resizeAnim*/);
+                                TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, true /*resizeAnim*/,
+                                SNAP_TO_2_50_50);
                     }
                 } else if (inFullscreen && isSplitScreenVisible()) {
                     // If the trigger task is in fullscreen and in split, exit split and place
@@ -2977,14 +3007,15 @@
                 out = new WindowContainerTransaction();
                 prepareEnterSplitScreen(out);
                 mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
-                        TRANSIT_SPLIT_SCREEN_PAIR_OPEN, !mIsDropEntering);
+                        TRANSIT_SPLIT_SCREEN_PAIR_OPEN, !mIsDropEntering, SNAP_TO_2_50_50);
                 return out;
             }
             ProtoLog.d(WM_SHELL_SPLIT_SCREEN, "handleRequest: transition=%d "
                     + "restoring to split", request.getDebugId());
             out = new WindowContainerTransaction();
             mSplitTransitions.setEnterTransition(transition, request.getRemoteTransition(),
-                    TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, false /* resizeAnim */);
+                    TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, false /* resizeAnim */,
+                    SNAP_TO_2_50_50);
         }
         return out;
     }
@@ -3171,7 +3202,8 @@
                 if (keepSplitWithPip) {
                     // Set an enter transition for when startAnimation gets called again
                     mSplitTransitions.setEnterTransition(transition, /*remoteTransition*/ null,
-                            TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, /*resizeAnim*/ false);
+                            TRANSIT_SPLIT_SCREEN_OPEN_TO_SIDE, /*resizeAnim*/ false,
+                            SNAP_TO_2_50_50);
                 } else {
                     int finalClosingTaskId = closingSplitTaskId;
                     mRecentTasks.ifPresent(recentTasks ->
@@ -3556,6 +3588,9 @@
                 }
             });
             mPausingTasks.clear();
+            if (enableFlexibleTwoAppSplit()) {
+                grantFocusForSnapPosition(enterTransition.mEnteringPosition);
+            }
         });
 
         if (info.getType() == TRANSIT_CHANGE && !isSplitActive()
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
index 7ef1a93..ffb81f8 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java
@@ -17,11 +17,9 @@
 package com.android.wm.shell.windowdecor;
 
 import static android.app.ActivityTaskManager.INVALID_TASK_ID;
-import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
-import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
 import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
 import static android.view.MotionEvent.ACTION_CANCEL;
 import static android.view.MotionEvent.ACTION_HOVER_ENTER;
@@ -79,7 +77,6 @@
 import android.view.View;
 import android.view.ViewConfiguration;
 import android.view.ViewRootImpl;
-import android.view.WindowManager;
 import android.window.DesktopModeFlags;
 import android.window.TaskSnapshot;
 import android.window.WindowContainerToken;
@@ -121,7 +118,6 @@
 import com.android.wm.shell.desktopmode.DesktopTasksController.SnapPosition;
 import com.android.wm.shell.desktopmode.DesktopTasksLimiter;
 import com.android.wm.shell.desktopmode.DesktopUserRepositories;
-import com.android.wm.shell.desktopmode.DesktopWallpaperActivity;
 import com.android.wm.shell.desktopmode.WindowDecorCaptionHandleRepository;
 import com.android.wm.shell.desktopmode.common.ToggleTaskSizeInteraction;
 import com.android.wm.shell.desktopmode.common.ToggleTaskSizeUtilsKt;
@@ -146,6 +142,7 @@
 import com.android.wm.shell.transition.FocusTransitionObserver;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration.ExclusionRegionListener;
+import com.android.wm.shell.windowdecor.common.AppHandleAndHeaderVisibilityHelper;
 import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader;
 import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost;
 import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier;
@@ -207,6 +204,7 @@
     private final Optional<DesktopTasksLimiter> mDesktopTasksLimiter;
     private final AppHandleEducationController mAppHandleEducationController;
     private final AppToWebEducationController mAppToWebEducationController;
+    private final AppHandleAndHeaderVisibilityHelper mAppHandleAndHeaderVisibilityHelper;
     private final AppHeaderViewHolder.Factory mAppHeaderViewHolderFactory;
     private boolean mTransitionDragActive;
 
@@ -294,6 +292,7 @@
             Optional<DesktopTasksLimiter> desktopTasksLimiter,
             AppHandleEducationController appHandleEducationController,
             AppToWebEducationController appToWebEducationController,
+            AppHandleAndHeaderVisibilityHelper appHandleAndHeaderVisibilityHelper,
             WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
             Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
             FocusTransitionObserver focusTransitionObserver,
@@ -338,6 +337,7 @@
                 desktopTasksLimiter,
                 appHandleEducationController,
                 appToWebEducationController,
+                appHandleAndHeaderVisibilityHelper,
                 windowDecorCaptionHandleRepository,
                 activityOrientationChangeHandler,
                 new TaskPositionerFactory(),
@@ -386,6 +386,7 @@
             Optional<DesktopTasksLimiter> desktopTasksLimiter,
             AppHandleEducationController appHandleEducationController,
             AppToWebEducationController appToWebEducationController,
+            AppHandleAndHeaderVisibilityHelper appHandleAndHeaderVisibilityHelper,
             WindowDecorCaptionHandleRepository windowDecorCaptionHandleRepository,
             Optional<DesktopActivityOrientationChangeHandler> activityOrientationChangeHandler,
             TaskPositionerFactory taskPositionerFactory,
@@ -431,6 +432,7 @@
         mDesktopTasksLimiter = desktopTasksLimiter;
         mAppHandleEducationController = appHandleEducationController;
         mAppToWebEducationController = appToWebEducationController;
+        mAppHandleAndHeaderVisibilityHelper = appHandleAndHeaderVisibilityHelper;
         mWindowDecorCaptionHandleRepository = windowDecorCaptionHandleRepository;
         mActivityOrientationChangeHandler = activityOrientationChangeHandler;
         mAssistContentRequester = assistContentRequester;
@@ -528,6 +530,7 @@
     @Override
     public void setSplitScreenController(SplitScreenController splitScreenController) {
         mSplitScreenController = splitScreenController;
+        mAppHandleAndHeaderVisibilityHelper.setSplitScreenController(splitScreenController);
     }
 
     @Override
@@ -1717,32 +1720,7 @@
     }
 
     private boolean shouldShowWindowDecor(RunningTaskInfo taskInfo) {
-        if (mDisplayController.getDisplay(taskInfo.displayId) == null) {
-            // If DisplayController doesn't have it tracked, it could be a private/managed display.
-            return false;
-        }
-        if (taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) return true;
-        if (mSplitScreenController != null
-                && mSplitScreenController.isTaskRootOrStageRoot(taskInfo.taskId)) {
-            return false;
-        }
-        if (mDesktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing(taskInfo)) {
-            return false;
-        }
-        final boolean isOnLargeScreen =
-                mDisplayController.getDisplay(taskInfo.displayId).getMinSizeDimensionDp()
-                        >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP;
-        if (!DesktopModeStatus.canEnterDesktopMode(mContext)
-                && DesktopModeStatus.overridesShowAppHandle(mContext) && !isOnLargeScreen) {
-            // Devices with multiple screens may enable the app handle but it should not show on
-            // small screens
-            return false;
-        }
-        return DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(mContext)
-                && !DesktopWallpaperActivity.isWallpaperTask(taskInfo)
-                && taskInfo.getWindowingMode() != WINDOWING_MODE_PINNED
-                && taskInfo.getActivityType() == ACTIVITY_TYPE_STANDARD
-                && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop();
+        return mAppHandleAndHeaderVisibilityHelper.shouldShowAppHandleOrHeader(taskInfo);
     }
 
     private void createWindowDecoration(
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
index 30e5c2a..2a53157 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecoration.java
@@ -1702,6 +1702,7 @@
         mExclusionRegionListener.onExclusionRegionDismissed(mTaskInfo.taskId);
         disposeResizeVeil();
         disposeStatusBarInputLayer();
+        mWindowDecorViewHolder.close();
         mWindowDecorViewHolder = null;
         if (canEnterDesktopMode(mContext) && isEducationEnabled()) {
             notifyNoCaptionHandle();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
index d36fc12..a9df4bd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DragDetector.java
@@ -28,6 +28,7 @@
 
 import android.annotation.NonNull;
 import android.graphics.PointF;
+import android.util.Log;
 import android.view.MotionEvent;
 import android.view.View;
 
@@ -43,6 +44,8 @@
  * All touch events must be passed through this class to track a drag event.
  */
 public class DragDetector {
+    private static final String TAG = "DragDetector";
+
     private final MotionEventHandler mEventHandler;
 
     private final PointF mInputDownPoint = new PointF();
@@ -109,8 +112,12 @@
                     return mResultOfDownAction;
                 }
                 final int dragPointerIndex = ev.findPointerIndex(mDragPointerId);
+                // TODO(b/400635953): Separate the app header and its buttons'
+                // touch listeners so they're not handled by the same DragDetector.
                 if (dragPointerIndex == -1) {
-                    throw new IllegalStateException("Failed to find primary pointer!");
+                    Log.w(TAG, "Invalid pointer index on ACTION_MOVE. Drag"
+                        + " pointer id: " + mDragPointerId);
+                    return mResultOfDownAction;
                 }
                 if (!mIsDragEvent) {
                     float dx = ev.getRawX(dragPointerIndex) - mInputDownPoint.x;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
index ad2e23c..ce78617 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/HandleMenu.kt
@@ -471,32 +471,20 @@
         val rootView = LayoutInflater.from(context)
             .inflate(R.layout.desktop_mode_window_decor_handle_menu, null /* root */) as View
 
-        private val windowingButtonRippleRadius = context.resources
-            .getDimensionPixelSize(R.dimen.desktop_mode_handle_menu_windowing_action_ripple_radius)
-        private val windowingButtonDrawableInsets = DrawableInsets(
-            vertical = context.resources
-                .getDimensionPixelSize(
-                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_base),
-            horizontal = context.resources
-                .getDimensionPixelSize(
-                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_base)
-        )
-        private val windowingButtonDrawableInsetsLeft = DrawableInsets(
-            vertical = context.resources
-                .getDimensionPixelSize(
-                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_base),
-            horizontalLeft = context.resources
-                .getDimensionPixelSize(
-                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_shift),
-        )
-        private val windowingButtonDrawableInsetsRight = DrawableInsets(
-            vertical = context.resources
-                .getDimensionPixelSize(
-                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_base),
-            horizontalRight = context.resources
-                .getDimensionPixelSize(
-                    R.dimen.desktop_mode_handle_menu_windowing_action_ripple_inset_shift)
-        )
+        // Insets for ripple effect of App Info Pill. and Windowing Pill. buttons
+        val iconButtondrawableShiftInset = context.resources.getDimensionPixelSize(
+            R.dimen.desktop_mode_handle_menu_icon_button_ripple_inset_shift)
+        val iconButtondrawableBaseInset = context.resources.getDimensionPixelSize(
+            R.dimen.desktop_mode_handle_menu_icon_button_ripple_inset_base)
+        private val iconButtonRippleRadius = context.resources.getDimensionPixelSize(
+            R.dimen.desktop_mode_handle_menu_icon_button_ripple_radius)
+        private val iconButtonDrawableInsetsBase = DrawableInsets(t=iconButtondrawableBaseInset,
+            b=iconButtondrawableBaseInset, l=iconButtondrawableBaseInset,
+            r=iconButtondrawableBaseInset)
+        private val iconButtonDrawableInsetsLeft = DrawableInsets(t=iconButtondrawableBaseInset,
+            b=iconButtondrawableBaseInset, l=iconButtondrawableShiftInset, r=0)
+        private val iconButtonDrawableInsetsRight = DrawableInsets(t=iconButtondrawableBaseInset,
+            b=iconButtondrawableBaseInset, l=0, r=iconButtondrawableShiftInset)
 
         // App Info Pill.
         private val appInfoPill = rootView.requireViewById<View>(R.id.app_info_pill)
@@ -713,6 +701,12 @@
             collapseMenuButton.apply {
                 imageTintList = ColorStateList.valueOf(style.textColor)
                 this.taskInfo = this@HandleMenuView.taskInfo
+
+                background = createRippleDrawable(
+                    color = style.textColor,
+                    cornerRadius = iconButtonRippleRadius,
+                    drawableInsets = iconButtonDrawableInsetsBase
+                )
             }
             appNameView.setTextColor(style.textColor)
             appNameView.startMarquee()
@@ -740,21 +734,15 @@
             desktopBtn.isEnabled = !taskInfo.isFreeform
             desktopBtn.imageTintList = style.windowingButtonColor
 
-            val startInsets = if (context.isRtl) {
-                windowingButtonDrawableInsetsRight
-            } else {
-                windowingButtonDrawableInsetsLeft
-            }
-            val endInsets = if (context.isRtl) {
-                windowingButtonDrawableInsetsLeft
-            } else {
-                windowingButtonDrawableInsetsRight
-            }
+            val startInsets = if (context.isRtl) iconButtonDrawableInsetsRight
+                else iconButtonDrawableInsetsLeft
+            val endInsets = if (context.isRtl) iconButtonDrawableInsetsLeft
+                else iconButtonDrawableInsetsRight
 
             fullscreenBtn.apply {
                 background = createRippleDrawable(
                     color = style.textColor,
-                    cornerRadius = windowingButtonRippleRadius,
+                    cornerRadius = iconButtonRippleRadius,
                     drawableInsets = startInsets
                 )
             }
@@ -762,23 +750,23 @@
             splitscreenBtn.apply {
                 background = createRippleDrawable(
                     color = style.textColor,
-                    cornerRadius = windowingButtonRippleRadius,
-                    drawableInsets = windowingButtonDrawableInsets
+                    cornerRadius = iconButtonRippleRadius,
+                    drawableInsets = iconButtonDrawableInsetsBase
                 )
             }
 
             floatingBtn.apply {
                 background = createRippleDrawable(
                     color = style.textColor,
-                    cornerRadius = windowingButtonRippleRadius,
-                    drawableInsets = windowingButtonDrawableInsets
+                    cornerRadius = iconButtonRippleRadius,
+                    drawableInsets = iconButtonDrawableInsetsBase
                 )
             }
 
             desktopBtn.apply {
                 background = createRippleDrawable(
                     color = style.textColor,
-                    cornerRadius = windowingButtonRippleRadius,
+                    cornerRadius = iconButtonRippleRadius,
                     drawableInsets = endInsets
                 )
             }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
index bdde096d..e8aac39 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/MaximizeButtonView.kt
@@ -22,7 +22,7 @@
 import android.content.Context
 import android.content.res.ColorStateList
 import android.graphics.Color
-import android.graphics.drawable.RippleDrawable
+import android.graphics.drawable.Drawable
 import android.util.AttributeSet
 import android.view.LayoutInflater
 import android.view.View
@@ -30,11 +30,11 @@
 import android.widget.FrameLayout
 import android.widget.ImageButton
 import android.widget.ProgressBar
+import android.window.DesktopModeFlags
 import androidx.core.animation.doOnEnd
 import androidx.core.animation.doOnStart
 import androidx.core.content.ContextCompat
 import com.android.wm.shell.R
-import android.window.DesktopModeFlags
 
 private const val OPEN_MAXIMIZE_MENU_DELAY_ON_HOVER_MS = 350
 private const val MAX_DRAWABLE_ALPHA = 255
@@ -109,14 +109,14 @@
         darkMode: Boolean,
         iconForegroundColor: ColorStateList? = null,
         baseForegroundColor: Int? = null,
-        rippleDrawable: RippleDrawable? = null
+        backgroundDrawable: Drawable? = null
     ) {
         if (DesktopModeFlags.ENABLE_THEMED_APP_HEADERS.isTrue()) {
             requireNotNull(iconForegroundColor) { "Icon foreground color must be non-null" }
             requireNotNull(baseForegroundColor) { "Base foreground color must be non-null" }
-            requireNotNull(rippleDrawable) { "Ripple drawable must be non-null" }
+            requireNotNull(backgroundDrawable) { "Background drawable must be non-null" }
             maximizeWindow.imageTintList = iconForegroundColor
-            maximizeWindow.background = rippleDrawable
+            maximizeWindow.background = backgroundDrawable
             stubProgressBarContainer.setOnInflateListener { _, inflated ->
                 val progressBar = (inflated as FrameLayout)
                     .requireViewById(R.id.progress_bar) as ProgressBar
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/AppHandleAndHeaderVisibilityHelper.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/AppHandleAndHeaderVisibilityHelper.kt
new file mode 100644
index 0000000..39ccf5b
--- /dev/null
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/AppHandleAndHeaderVisibilityHelper.kt
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.windowdecor.common
+
+import android.app.ActivityManager
+import android.app.WindowConfiguration
+import android.content.Context
+import android.view.WindowManager
+import android.window.DesktopExperienceFlags.ENABLE_BUG_FIXES_FOR_SECONDARY_DISPLAY
+import com.android.wm.shell.common.DisplayController
+import com.android.wm.shell.desktopmode.DesktopWallpaperActivity.Companion.isWallpaperTask
+import com.android.wm.shell.shared.desktopmode.DesktopModeCompatPolicy
+import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
+import com.android.wm.shell.splitscreen.SplitScreenController
+
+/**
+ * Resolves whether, given a task and its associated display that it is currently on, to show the
+ * app handle/header or not.
+ */
+class AppHandleAndHeaderVisibilityHelper (
+    private val context: Context,
+    private val displayController: DisplayController,
+    private val desktopModeCompatPolicy: DesktopModeCompatPolicy
+) {
+    var splitScreenController: SplitScreenController? = null
+
+    /**
+     * Returns, given a task's attribute and its display attribute, whether the app
+     * handle/header should show or not for this task.
+     */
+    fun shouldShowAppHandleOrHeader(taskInfo: ActivityManager.RunningTaskInfo): Boolean {
+        if (!ENABLE_BUG_FIXES_FOR_SECONDARY_DISPLAY.isTrue) {
+            return allowedForTask(taskInfo)
+        }
+        return allowedForTask(taskInfo) && allowedForDisplay(taskInfo.displayId)
+    }
+
+    private fun allowedForTask(taskInfo: ActivityManager.RunningTaskInfo): Boolean {
+        // TODO (b/382023296): Remove once we no longer rely on
+        //  Flags.enableBugFixesForSecondaryDisplay as it is taken care of in #allowedForDisplay
+        if (displayController.getDisplay(taskInfo.displayId) == null) {
+            // If DisplayController doesn't have it tracked, it could be a private/managed display.
+            return false
+        }
+        if (taskInfo.windowingMode == WindowConfiguration.WINDOWING_MODE_FREEFORM) return true
+        if (splitScreenController?.isTaskRootOrStageRoot(taskInfo.taskId) == true) {
+            return false
+        }
+
+        if (desktopModeCompatPolicy.isTopActivityExemptFromDesktopWindowing(taskInfo)) {
+            return false
+        }
+
+        // TODO (b/382023296): Remove once we no longer rely on
+        //  Flags.enableBugFixesForSecondaryDisplay as it is taken care of in #allowedForDisplay
+        val isOnLargeScreen =
+            displayController.getDisplay(taskInfo.displayId).minSizeDimensionDp >=
+                    WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
+        if (!DesktopModeStatus.canEnterDesktopMode(context)
+            && DesktopModeStatus.overridesShowAppHandle(context)
+            && !isOnLargeScreen
+        ) {
+            // Devices with multiple screens may enable the app handle but it should not show on
+            // small screens
+            return false
+        }
+        return DesktopModeStatus.canEnterDesktopModeOrShowAppHandle(context)
+                && !isWallpaperTask(taskInfo)
+                && taskInfo.windowingMode != WindowConfiguration.WINDOWING_MODE_PINNED
+                && taskInfo.activityType == WindowConfiguration.ACTIVITY_TYPE_STANDARD
+                && !taskInfo.configuration.windowConfiguration.isAlwaysOnTop
+    }
+
+    private fun allowedForDisplay(displayId: Int): Boolean {
+        // If DisplayController doesn't have it tracked, it could be a private/managed display.
+        val display = displayController.getDisplay(displayId)
+        if (display == null) return false
+
+        if (DesktopModeStatus.isDesktopModeSupportedOnDisplay(context, display)) {
+            return true
+        }
+        // If on default display and on Large Screen (unfolded), show app handle
+        return DesktopModeStatus.overridesShowAppHandle(context)
+                && display.minSizeDimensionDp >= WindowManager.LARGE_SCREEN_SMALLEST_SCREEN_WIDTH_DP
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ButtonBackgroundDrawableUtils.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ButtonBackgroundDrawableUtils.kt
index e18239d..f44b15a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ButtonBackgroundDrawableUtils.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/common/ButtonBackgroundDrawableUtils.kt
@@ -16,14 +16,13 @@
 package com.android.wm.shell.windowdecor.common
 
 import android.annotation.ColorInt
+import android.content.res.ColorStateList
 import android.graphics.Color
+import android.graphics.drawable.Drawable
 import android.graphics.drawable.LayerDrawable
 import android.graphics.drawable.RippleDrawable
 import android.graphics.drawable.ShapeDrawable
 import android.graphics.drawable.shapes.RoundRectShape
-import com.android.wm.shell.windowdecor.common.OPACITY_11
-import com.android.wm.shell.windowdecor.common.OPACITY_15
-import android.content.res.ColorStateList
 
 /**
  * Represents drawable insets, specifying the number of pixels to inset a drawable from its bounds.
@@ -52,9 +51,9 @@
  * Creates a RippleDrawable with specified color, corner radius, and insets.
  */
 fun createRippleDrawable(
-            @ColorInt color: Int,
-            cornerRadius: Int,
-            drawableInsets: DrawableInsets,
+    @ColorInt color: Int,
+    cornerRadius: Int,
+    drawableInsets: DrawableInsets,
 ): RippleDrawable {
     return RippleDrawable(
         ColorStateList(
@@ -86,3 +85,32 @@
         }
     )
 }
+
+/**
+ * Creates a background drawable with specified color, corner radius, and insets.
+ */
+fun createBackgroundDrawable(
+    @ColorInt color: Int, cornerRadius: Int, drawableInsets: DrawableInsets
+): Drawable = LayerDrawable(arrayOf(
+    ShapeDrawable().apply {
+        shape = RoundRectShape(
+            FloatArray(8) { cornerRadius.toFloat() },
+            /* inset= */ null,
+            /* innerRadii= */ null
+        )
+        setTintList(ColorStateList(
+            arrayOf(
+                intArrayOf(android.R.attr.state_hovered),
+                intArrayOf(android.R.attr.state_pressed),
+            ),
+            intArrayOf(
+                replaceColorAlpha(color, OPACITY_11),
+                replaceColorAlpha(color, OPACITY_15),
+            )
+        ))
+    }
+)).apply {
+    require(numberOfLayers == 1) { "Must only contain one layer" }
+    setLayerInset(/* index= */ 0,
+        drawableInsets.l, drawableInsets.t, drawableInsets.r, drawableInsets.b)
+}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
index cb45c17..57f8046 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManager.kt
@@ -16,6 +16,9 @@
 
 package com.android.wm.shell.windowdecor.tiling
 
+import android.animation.Animator
+import android.animation.AnimatorListenerAdapter
+import android.animation.ValueAnimator
 import android.content.Context
 import android.content.res.Configuration
 import android.graphics.Path
@@ -144,7 +147,6 @@
      * @param relativeLeash the task leash that the TilingDividerView should be shown on top of.
      */
     fun generateViewHost(relativeLeash: SurfaceControl) {
-        val t = transactionSupplier.get()
         val surfaceControlViewHost =
             SurfaceControlViewHost(context, context.display, this, "DesktopTilingManager")
         val dividerView =
@@ -155,22 +157,40 @@
         val tmpDividerBounds = Rect()
         getDividerBounds(tmpDividerBounds)
         dividerView.setup(this, tmpDividerBounds, handleRegionSize, isDarkMode)
-        t.setRelativeLayer(leash, relativeLeash, 1)
-            .setPosition(
-                leash,
-                dividerBounds.left.toFloat() - maxRoundedCornerRadius,
-                dividerBounds.top.toFloat(),
-            )
-            .show(leash)
-        syncQueue.runInSync { transaction ->
-            transaction.merge(t)
-            t.close()
-        }
-        dividerShown = true
+        val dividerAnimatorT = transactionSupplier.get()
+        val dividerAnimator =
+            ValueAnimator.ofFloat(0f, 1f).apply {
+                duration = DIVIDER_FADE_IN_ALPHA_DURATION
+                addUpdateListener {
+                    dividerAnimatorT.setAlpha(leash, animatedValue as Float).apply()
+                }
+                addListener(
+                    object : AnimatorListenerAdapter() {
+                        override fun onAnimationStart(animation: Animator) {
+                            dividerAnimatorT
+                                .setRelativeLayer(leash, relativeLeash, 1)
+                                .setPosition(
+                                    leash,
+                                    dividerBounds.left.toFloat() - maxRoundedCornerRadius,
+                                    dividerBounds.top.toFloat(),
+                                )
+                                .setAlpha(leash, 0f)
+                                .show(leash)
+                                .apply()
+                        }
+
+                        override fun onAnimationEnd(animation: Animator) {
+                            dividerAnimatorT.setAlpha(leash, 1f).apply()
+                            dividerShown = true
+                        }
+                    }
+                )
+            }
+        dividerAnimator.start()
         viewHost = surfaceControlViewHost
-        dividerView.addOnLayoutChangeListener(this)
         tilingDividerView = dividerView
         updateTouchRegion()
+        dividerView.addOnLayoutChangeListener(this)
     }
 
     /** Changes divider colour if dark/light mode is toggled. */
@@ -311,4 +331,8 @@
             )
             .maxOf { position -> display.getRoundedCorner(position)?.getRadius() ?: 0 }
     }
+
+    companion object {
+        private const val DIVIDER_FADE_IN_ALPHA_DURATION = 300L
+    }
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
index a45df04..c3d15df 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecoration.kt
@@ -133,10 +133,10 @@
         isDarkMode = isTaskInDarkMode(taskInfo)
         // Observe drag resizing to break tiling if a task is drag resized.
         desktopModeWindowDecoration.addDragResizeListener(this)
-
+        val callback = { initTilingForDisplayIfNeeded(taskInfo.configuration, isFirstTiledApp) }
         if (isTiled) {
             val wct = WindowContainerTransaction().setBounds(taskInfo.token, destinationBounds)
-            toggleResizeDesktopTaskTransitionHandler.startTransition(wct, currentBounds)
+            toggleResizeDesktopTaskTransitionHandler.startTransition(wct, currentBounds, callback)
         } else {
             // Handle the case where we attempt to snap resize when already snap resized: the task
             // position won't need to change but we want to animate the surface going back to the
@@ -147,10 +147,10 @@
                     resizeMetadata.getLeash(),
                     startBounds = currentBounds,
                     endBounds = destinationBounds,
+                    callback,
                 )
             }
         }
-        initTilingForDisplayIfNeeded(taskInfo.configuration, isFirstTiledApp)
         return isTiled
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
index 2948fda..d9df899f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHandleViewHolder.kt
@@ -274,4 +274,6 @@
             }
         animator.start()
     }
+
+    override fun close() {}
 }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
index eb8b617..c3f5b3f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/AppHeaderViewHolder.kt
@@ -23,10 +23,6 @@
 import android.graphics.Bitmap
 import android.graphics.Color
 import android.graphics.Rect
-import android.graphics.drawable.LayerDrawable
-import android.graphics.drawable.RippleDrawable
-import android.graphics.drawable.ShapeDrawable
-import android.graphics.drawable.shapes.RoundRectShape
 import android.os.Bundle
 import android.view.View
 import android.view.View.OnLongClickListener
@@ -55,14 +51,12 @@
 import com.android.wm.shell.R
 import com.android.wm.shell.windowdecor.MaximizeButtonView
 import com.android.wm.shell.windowdecor.common.DecorThemeUtil
+import com.android.wm.shell.windowdecor.common.DrawableInsets
 import com.android.wm.shell.windowdecor.common.OPACITY_100
-import com.android.wm.shell.windowdecor.common.OPACITY_11
-import com.android.wm.shell.windowdecor.common.OPACITY_15
 import com.android.wm.shell.windowdecor.common.OPACITY_55
 import com.android.wm.shell.windowdecor.common.OPACITY_65
 import com.android.wm.shell.windowdecor.common.Theme
-import com.android.wm.shell.windowdecor.common.DrawableInsets
-import com.android.wm.shell.windowdecor.common.createRippleDrawable
+import com.android.wm.shell.windowdecor.common.createBackgroundDrawable
 import com.android.wm.shell.windowdecor.extension.isLightCaptionBarAppearance
 import com.android.wm.shell.windowdecor.extension.isTransparentCaptionBarAppearance
 
@@ -385,7 +379,7 @@
         val colorStateList = ColorStateList.valueOf(foregroundColor).withAlpha(foregroundAlpha)
         // App chip.
         openMenuButton.apply {
-            background = createRippleDrawable(
+            background = createBackgroundDrawable(
                 color = foregroundColor,
                 cornerRadius = headerButtonsRippleRadius,
                 drawableInsets = appChipDrawableInsets,
@@ -396,11 +390,12 @@
                 setTextColor(colorStateList)
             }
             appIconImageView.imageAlpha = foregroundAlpha
+            defaultFocusHighlightEnabled = false
         }
         // Minimize button.
         minimizeWindowButton.apply {
             imageTintList = colorStateList
-            background = createRippleDrawable(
+            background = createBackgroundDrawable(
                 color = foregroundColor,
                 cornerRadius = headerButtonsRippleRadius,
                 drawableInsets = minimizeDrawableInsets
@@ -413,7 +408,7 @@
                 darkMode = header.appTheme == Theme.DARK,
                 iconForegroundColor = colorStateList,
                 baseForegroundColor = foregroundColor,
-                rippleDrawable = createRippleDrawable(
+                backgroundDrawable = createBackgroundDrawable(
                     color = foregroundColor,
                     cornerRadius = headerButtonsRippleRadius,
                     drawableInsets = maximizeDrawableInsets
@@ -451,7 +446,7 @@
         // Close button.
         closeWindowButton.apply {
             imageTintList = colorStateList
-            background = createRippleDrawable(
+            background = createBackgroundDrawable(
                 color = foregroundColor,
                 cornerRadius = headerButtonsRippleRadius,
                 drawableInsets = closeDrawableInsets
@@ -725,6 +720,11 @@
                 Configuration.UI_MODE_NIGHT_YES
     }
 
+    override fun close() {
+        // Should not fire long press events after closing the window decoration.
+        maximizeWindowButton.cancelLongPress()
+    }
+
     companion object {
         private const val TAG = "DesktopModeAppControlsWindowDecorationViewHolder"
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/WindowDecorationViewHolder.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/WindowDecorationViewHolder.kt
index 1fe743d..cd202bf 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/WindowDecorationViewHolder.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/viewholder/WindowDecorationViewHolder.kt
@@ -24,7 +24,7 @@
  * Encapsulates the root [View] of a window decoration and its children to facilitate looking up
  * children (via findViewById) and updating to the latest data from [RunningTaskInfo].
  */
-abstract class WindowDecorationViewHolder<T : Data>(rootView: View) {
+abstract class WindowDecorationViewHolder<T : Data>(rootView: View) : AutoCloseable {
   val context: Context = rootView.context
 
   /**
@@ -39,6 +39,9 @@
   /** Callback when the handle menu is closed. */
   abstract fun onHandleMenuClosed()
 
+  /** Callback when the window decoration is destroyed. */
+  abstract override fun close()
+
   /** Data clas that contains the information needed to update the view holder. */
   abstract class Data
 }
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
index d73d08c..c3abe73 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/DesktopModeFlickerScenarios.kt
@@ -19,6 +19,7 @@
 import android.tools.PlatformConsts.DESKTOP_MODE_MINIMUM_WINDOW_HEIGHT
 import android.tools.PlatformConsts.DESKTOP_MODE_MINIMUM_WINDOW_WIDTH
 import android.tools.flicker.AssertionInvocationGroup
+import android.tools.flicker.assertors.assertions.AppLayerCoversFullScreenAtEnd
 import android.tools.flicker.assertors.assertions.ResizeVeilKeepsIncreasingInSize
 import android.tools.flicker.assertors.assertions.AppLayerIsInvisibleAtEnd
 import android.tools.flicker.assertors.assertions.AppLayerIsVisibleAlways
@@ -99,6 +100,59 @@
                             .associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
             )
 
+        val ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT =
+            FlickerConfigEntry(
+                scenarioId = ScenarioId("ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT"),
+                extractor =
+                ShellTransitionScenarioExtractor(
+                    transitionMatcher =
+                    object : ITransitionMatcher {
+                        override fun findAll(
+                            transitions: Collection<Transition>
+                        ): Collection<Transition> =
+                            transitions.filter {
+                                it.type == TransitionType.ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT
+                            }
+                    }
+                ),
+                assertions =
+                AssertionTemplates.COMMON_ASSERTIONS +
+                        listOf(
+                            AppLayerIsVisibleAlways(DESKTOP_MODE_APP),
+                            AppWindowOnTopAtEnd(DESKTOP_MODE_APP),
+                            AppWindowHasDesktopModeInitialBoundsAtTheEnd(DESKTOP_MODE_APP),
+                            AppWindowBecomesVisible(DESKTOP_WALLPAPER)
+                        )
+                            .associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
+            )
+
+        val EXIT_DESKTOP_FROM_KEYBOARD_SHORTCUT =
+            FlickerConfigEntry(
+                scenarioId = ScenarioId("EXIT_DESKTOP_FROM_KEYBOARD_SHORTCUT"),
+                extractor =
+                ShellTransitionScenarioExtractor(
+                    transitionMatcher =
+                    object : ITransitionMatcher {
+                        override fun findAll(
+                            transitions: Collection<Transition>
+                        ): Collection<Transition> =
+                            transitions.filter {
+                                it.type == TransitionType.EXIT_DESKTOP_MODE_KEYBOARD_SHORTCUT
+                            }
+                    }
+                ),
+                assertions =
+                AssertionTemplates.COMMON_ASSERTIONS +
+                        listOf(
+                            AppLayerIsVisibleAlways(DESKTOP_MODE_APP),
+                            AppLayerCoversFullScreenAtEnd(DESKTOP_MODE_APP),
+                            AppWindowOnTopAtStart(DESKTOP_MODE_APP),
+                            AppWindowOnTopAtEnd(DESKTOP_MODE_APP),
+                            AppWindowBecomesInvisible(DESKTOP_WALLPAPER)
+                        )
+                            .associateBy({ it }, { AssertionInvocationGroup.BLOCKING }),
+            )
+
         // Use this scenario for closing an app in desktop windowing, except the last app. For the
         // last app use CLOSE_LAST_APP scenario
         val CLOSE_APP =
@@ -361,11 +415,10 @@
                     object : ITransitionMatcher {
                         override fun findAll(
                             transitions: Collection<Transition>
-                        ): Collection<Transition> {
-                            return transitions.filter {
+                        ): Collection<Transition> =
+                            transitions.filter {
                                 it.type == TransitionType.DESKTOP_MODE_TOGGLE_RESIZE
                             }
-                        }
                     }
                 ),
                 assertions = AssertionTemplates.DESKTOP_MODE_APP_VISIBILITY_ASSERTIONS +
@@ -385,11 +438,10 @@
                     object : ITransitionMatcher {
                         override fun findAll(
                             transitions: Collection<Transition>
-                        ): Collection<Transition> {
-                            return transitions.filter {
+                        ): Collection<Transition> =
+                            transitions.filter {
                                 it.type == TransitionType.DESKTOP_MODE_TOGGLE_RESIZE
                             }
-                        }
                     }
                 ),
                 assertions =
@@ -410,11 +462,10 @@
                             object : ITransitionMatcher {
                                 override fun findAll(
                                     transitions: Collection<Transition>
-                                ): Collection<Transition> {
-                                    return transitions.filter {
+                                ): Collection<Transition> =
+                                    transitions.filter {
                                         it.type == TransitionType.TO_FRONT
                                     }
-                                }
                             }
                     ),
                 assertions =
@@ -434,9 +485,8 @@
                     object : ITransitionMatcher {
                         override fun findAll(
                             transitions: Collection<Transition>
-                        ): Collection<Transition> {
-                                return transitions.filter { it.type == TransitionType.OPEN }
-                        }
+                        ): Collection<Transition> =
+                                transitions.filter { it.type == TransitionType.OPEN }
                     }
                 ),
                 assertions =
@@ -512,9 +562,8 @@
                     object : ITransitionMatcher {
                         override fun findAll(
                             transitions: Collection<Transition>
-                        ): Collection<Transition> {
-                                return transitions.filter { it.type == TransitionType.OPEN }
-                        }
+                        ): Collection<Transition> =
+                                transitions.filter { it.type == TransitionType.OPEN }
                     }
                 ),
                 assertions =
@@ -553,11 +602,10 @@
                     object : ITransitionMatcher {
                         override fun findAll(
                             transitions: Collection<Transition>
-                        ): Collection<Transition> {
-                                return listOf(transitions
+                        ): Collection<Transition> =
+                                listOf(transitions
                                     .filter { it.type == TransitionType.OPEN }
                                     .maxByOrNull { it.id }!!)
-                        }
                     }
                 ),
                 assertions =
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/EnterDesktopWithKeyboardShortcut.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/EnterDesktopWithKeyboardShortcut.kt
new file mode 100644
index 0000000..4603e4e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/EnterDesktopWithKeyboardShortcut.kt
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT
+import com.android.wm.shell.scenarios.EnterDesktopFromKeyboardShortcut
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class EnterDesktopWithKeyboardShortcut : EnterDesktopFromKeyboardShortcut() {
+    @ExpectedScenarios(["ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT"])
+    @Test
+    override fun enterDesktopFromKeyboardShortcut() = super.enterDesktopFromKeyboardShortcut()
+
+    companion object {
+
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+                .use(ENTER_DESKTOP_FROM_KEYBOARD_SHORTCUT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ExitDesktopToFullScreenWithKeyboardShortcut.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ExitDesktopToFullScreenWithKeyboardShortcut.kt
new file mode 100644
index 0000000..d9fd339
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/ExitDesktopToFullScreenWithKeyboardShortcut.kt
@@ -0,0 +1,44 @@
+/*
+ * 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.flicker
+
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.EXIT_DESKTOP_FROM_KEYBOARD_SHORTCUT
+import com.android.wm.shell.scenarios.ExitDesktopFromKeyboardShortcut
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class ExitDesktopToFullScreenWithKeyboardShortcut : ExitDesktopFromKeyboardShortcut() {
+    @ExpectedScenarios(["EXIT_DESKTOP_FROM_KEYBOARD_SHORTCUT"])
+    @Test
+    override fun exitDesktopToFullScreenFromKeyboardShortcut() =
+        super.exitDesktopToFullScreenFromKeyboardShortcut()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT)
+                .use(EXIT_DESKTOP_FROM_KEYBOARD_SHORTCUT)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppDoubleTapAppHeaderLandscape.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppDoubleTapAppHeaderLandscape.kt
new file mode 100644
index 0000000..32df049
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppDoubleTapAppHeaderLandscape.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.tools.Rotation.ROTATION_90
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper.MaximizeDesktopAppTrigger
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MAXIMIZE_APP
+import com.android.wm.shell.scenarios.MaximizeAppWindow
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Maximize app window by double tapping on the app header.
+ *
+ * Assert that the app window keeps the same increases in size, filling the vertical and horizontal
+ * stable display bounds.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class MaximizeAppDoubleTapAppHeaderLandscape : MaximizeAppWindow(
+    rotation = ROTATION_90,
+    trigger = MaximizeDesktopAppTrigger.DOUBLE_TAP_APP_HEADER
+) {
+    @ExpectedScenarios(["MAXIMIZE_APP"])
+    @Test
+    override fun maximizeAppWindow() = super.maximizeAppWindow()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MAXIMIZE_APP)
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppDoubleTapAppHeaderPortrait.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppDoubleTapAppHeaderPortrait.kt
new file mode 100644
index 0000000..977846e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppDoubleTapAppHeaderPortrait.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.tools.Rotation.ROTATION_0
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper.MaximizeDesktopAppTrigger
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MAXIMIZE_APP
+import com.android.wm.shell.scenarios.MaximizeAppWindow
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Maximize app window by double tapping on the app header in portrait mode.
+ *
+ * Assert that the app window keeps the same increases in size, filling the vertical and horizontal
+ * stable display bounds.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class MaximizeAppDoubleTapAppHeaderPortrait : MaximizeAppWindow(
+    rotation = ROTATION_0,
+    trigger = MaximizeDesktopAppTrigger.DOUBLE_TAP_APP_HEADER
+) {
+    @ExpectedScenarios(["MAXIMIZE_APP"])
+    @Test
+    override fun maximizeAppWindow() = super.maximizeAppWindow()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MAXIMIZE_APP)
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppViaHeaderMenuLandscape.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppViaHeaderMenuLandscape.kt
new file mode 100644
index 0000000..7031926
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppViaHeaderMenuLandscape.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.tools.Rotation.ROTATION_90
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper.MaximizeDesktopAppTrigger
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MAXIMIZE_APP
+import com.android.wm.shell.scenarios.MaximizeAppWindow
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Maximize app window by tapping on the maximize button within the app header maximize menu.
+ *
+ * Assert that the app window keeps the same increases in size, filling the vertical and horizontal
+ * stable display bounds.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class MaximizeAppViaHeaderMenuLandscape : MaximizeAppWindow(
+    rotation = ROTATION_90,
+    trigger = MaximizeDesktopAppTrigger.MAXIMIZE_BUTTON_IN_MENU
+) {
+    @ExpectedScenarios(["MAXIMIZE_APP"])
+    @Test
+    override fun maximizeAppWindow() = super.maximizeAppWindow()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MAXIMIZE_APP)
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppViaHeaderMenuPortrait.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppViaHeaderMenuPortrait.kt
new file mode 100644
index 0000000..4c7eb8d
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppViaHeaderMenuPortrait.kt
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.flicker
+
+import android.tools.Rotation.ROTATION_0
+import android.tools.flicker.FlickerConfig
+import android.tools.flicker.annotation.ExpectedScenarios
+import android.tools.flicker.annotation.FlickerConfigProvider
+import android.tools.flicker.config.FlickerConfig
+import android.tools.flicker.config.FlickerServiceConfig
+import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper.MaximizeDesktopAppTrigger
+import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MAXIMIZE_APP
+import com.android.wm.shell.scenarios.MaximizeAppWindow
+import org.junit.Test
+import org.junit.runner.RunWith
+
+/**
+ * Maximize app window by tapping on the maximize button within the app header maximize menu.
+ *
+ * Assert that the app window keeps the same increases in size, filling the vertical and horizontal
+ * stable display bounds.
+ */
+@RunWith(FlickerServiceJUnit4ClassRunner::class)
+class MaximizeAppViaHeaderMenuPortrait : MaximizeAppWindow(
+    rotation = ROTATION_0,
+    trigger = MaximizeDesktopAppTrigger.MAXIMIZE_BUTTON_IN_MENU
+) {
+    @ExpectedScenarios(["MAXIMIZE_APP"])
+    @Test
+    override fun maximizeAppWindow() = super.maximizeAppWindow()
+
+    companion object {
+        @JvmStatic
+        @FlickerConfigProvider
+        fun flickerConfigProvider(): FlickerConfig =
+            FlickerConfig().use(FlickerServiceConfig.DEFAULT).use(MAXIMIZE_APP)
+    }
+}
\ No newline at end of file
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWithKeyboard.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWithKeyboard.kt
index b399e9b..3f8a28f 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWithKeyboard.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/flicker-service/src/com/android/wm/shell/flicker/MaximizeAppWithKeyboard.kt
@@ -23,6 +23,7 @@
 import android.tools.flicker.config.FlickerConfig
 import android.tools.flicker.config.FlickerServiceConfig
 import android.tools.flicker.junit.FlickerServiceJUnit4ClassRunner
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper.MaximizeDesktopAppTrigger
 import com.android.wm.shell.flicker.DesktopModeFlickerScenarios.Companion.MAXIMIZE_APP
 import com.android.wm.shell.scenarios.MaximizeAppWindow
 import org.junit.Test
@@ -35,7 +36,10 @@
  * stable display bounds.
  */
 @RunWith(FlickerServiceJUnit4ClassRunner::class)
-class MaximizeAppWithKeyboard : MaximizeAppWindow(rotation = ROTATION_90, usingKeyboard = true) {
+class MaximizeAppWithKeyboard : MaximizeAppWindow(
+    rotation = ROTATION_90,
+    trigger = MaximizeDesktopAppTrigger.KEYBOARD_SHORTCUT
+) {
     @ExpectedScenarios(["MAXIMIZE_APP"])
     @Test
     override fun maximizeAppWindow() = super.maximizeAppWindow()
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopFromKeyboardShortcut.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopFromKeyboardShortcut.kt
new file mode 100644
index 0000000..9cbc46b
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/EnterDesktopFromKeyboardShortcut.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.platform.test.annotations.Postsubmit
+import android.app.Instrumentation
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.window.flags.Flags
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class EnterDesktopFromKeyboardShortcut {
+
+    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val tapl = LauncherInstrumentation()
+    private val wmHelper = WindowManagerStateHelper(instrumentation)
+    private val simpleAppHelper = SimpleAppHelper(instrumentation)
+    private val testApp = DesktopModeAppHelper(simpleAppHelper)
+
+    @Before
+    fun setup() {
+        Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+    }
+
+    @Test
+    open fun enterDesktopFromKeyboardShortcut() {
+        simpleAppHelper.launchViaIntent(wmHelper)
+        testApp.enterDesktopModeViaKeyboard(wmHelper)
+    }
+
+    @After
+    fun teardown() {
+        testApp.exit(wmHelper)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopFromKeyboardShortcut.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopFromKeyboardShortcut.kt
new file mode 100644
index 0000000..1b1f1cf
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/ExitDesktopFromKeyboardShortcut.kt
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.scenarios
+
+import android.platform.test.annotations.Postsubmit
+import android.app.Instrumentation
+import android.tools.traces.parsers.WindowManagerStateHelper
+import androidx.test.platform.app.InstrumentationRegistry
+import androidx.test.uiautomator.UiDevice
+import com.android.launcher3.tapl.LauncherInstrumentation
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.SimpleAppHelper
+import com.android.window.flags.Flags
+import org.junit.After
+import org.junit.Assume
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.junit.runners.BlockJUnit4ClassRunner
+
+@RunWith(BlockJUnit4ClassRunner::class)
+@Postsubmit
+open class ExitDesktopFromKeyboardShortcut {
+
+    private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
+    private val tapl = LauncherInstrumentation()
+    private val wmHelper = WindowManagerStateHelper(instrumentation)
+    private val device = UiDevice.getInstance(instrumentation)
+    private val simpleAppHelper = SimpleAppHelper(instrumentation)
+    private val testApp = DesktopModeAppHelper(simpleAppHelper)
+
+    @Before
+    fun setup() {
+        Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
+        simpleAppHelper.launchViaIntent(wmHelper)
+        testApp.enterDesktopMode(wmHelper, device)
+    }
+
+    @Test
+    open fun exitDesktopToFullScreenFromKeyboardShortcut() {
+        testApp.exitDesktopModeToFullScreenViaKeyboard(wmHelper)
+    }
+
+    @After
+    fun teardown() {
+        testApp.exit(wmHelper)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt
index 7855698..92fe40d 100644
--- a/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt
+++ b/libs/WindowManager/Shell/tests/e2e/desktopmode/scenarios/src/com/android/wm/shell/scenarios/MaximizeAppWindow.kt
@@ -26,6 +26,7 @@
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.server.wm.flicker.helpers.DesktopModeAppHelper
+import com.android.server.wm.flicker.helpers.DesktopModeAppHelper.MaximizeDesktopAppTrigger
 import com.android.server.wm.flicker.helpers.NonResizeableAppHelper
 import com.android.server.wm.flicker.helpers.SimpleAppHelper
 import com.android.window.flags.Flags
@@ -38,11 +39,10 @@
 import org.junit.Test
 
 @Ignore("Test Base Class")
-abstract class MaximizeAppWindow
-constructor(
+abstract class MaximizeAppWindow(
     private val rotation: Rotation = Rotation.ROTATION_0,
     isResizable: Boolean = true,
-    private val usingKeyboard: Boolean = false
+    private val trigger: MaximizeDesktopAppTrigger = MaximizeDesktopAppTrigger.MAXIMIZE_MENU,
 ) {
     private val instrumentation: Instrumentation = InstrumentationRegistry.getInstrumentation()
     private val tapl = LauncherInstrumentation()
@@ -59,7 +59,7 @@
     @Before
     fun setup() {
         Assume.assumeTrue(Flags.enableDesktopWindowingMode() && tapl.isTablet)
-        if (usingKeyboard) {
+        if (trigger == MaximizeDesktopAppTrigger.KEYBOARD_SHORTCUT) {
             Assume.assumeTrue(DesktopModeFlags.ENABLE_TASK_RESIZING_KEYBOARD_SHORTCUTS.isTrue)
         }
         tapl.setEnableRotation(true)
@@ -70,7 +70,7 @@
 
     @Test
     open fun maximizeAppWindow() {
-        testApp.maximiseDesktopApp(wmHelper, device, usingKeyboard = usingKeyboard)
+        testApp.maximiseDesktopApp(wmHelper, device, trigger)
     }
 
     @After
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
index 6a6aa1a..fa9864b 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/flicker-legacy/src/com/android/wm/shell/flicker/splitscreen/benchmark/SwitchAppByDoubleTapDividerBenchmark.kt
@@ -17,15 +17,15 @@
 package com.android.wm.shell.flicker.splitscreen.benchmark
 
 import android.tools.NavBar
-import android.tools.Rotation
 import android.tools.flicker.junit.FlickerParametersRunnerFactory
 import android.tools.flicker.legacy.FlickerBuilder
 import android.tools.flicker.legacy.LegacyFlickerTest
 import android.tools.flicker.legacy.LegacyFlickerTestFactory
-import android.tools.helpers.WindowUtils
 import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.filters.RequiresDevice
+import androidx.test.uiautomator.UiDevice
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils.isLeftRightSplit
 import org.junit.FixMethodOrder
 import org.junit.runner.RunWith
 import org.junit.runners.MethodSorters
@@ -37,6 +37,8 @@
 @FixMethodOrder(MethodSorters.NAME_ASCENDING)
 abstract class SwitchAppByDoubleTapDividerBenchmark(override val flicker: LegacyFlickerTest) :
     SplitScreenBase(flicker) {
+    private val device = UiDevice.getInstance(instrumentation)
+
     protected val thisTransition: FlickerBuilder.() -> Unit
         get() = {
             setup {
@@ -73,7 +75,8 @@
                     }
                         ?: return@add false
 
-                if (isLandscape(flicker.scenario.endRotation)) {
+                if (isLeftRightSplit(instrumentation.context, flicker.scenario.endRotation,
+                        device.displaySizeDp)) {
                     return@add if (flicker.scenario.isTablet) {
                         secondaryAppWindow.frame.right <= primaryAppWindow.frame.left
                     } else {
@@ -109,7 +112,8 @@
                 val secondaryVisibleRegion =
                     secondaryAppLayer.visibleRegion?.bounds ?: return@add false
 
-                if (isLandscape(flicker.scenario.endRotation)) {
+                if (isLeftRightSplit(instrumentation.context, flicker.scenario.endRotation,
+                        device.displaySizeDp)) {
                     return@add if (flicker.scenario.isTablet) {
                         secondaryVisibleRegion.right <= primaryVisibleRegion.left
                     } else {
@@ -126,11 +130,6 @@
             .waitForAndVerify()
     }
 
-    private fun isLandscape(rotation: Rotation): Boolean {
-        val displayBounds = WindowUtils.getDisplayBounds(rotation)
-        return displayBounds.width() > displayBounds.height()
-    }
-
     companion object {
         @Parameterized.Parameters(name = "{0}")
         @JvmStatic
diff --git a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/SwitchAppByDoubleTapDivider.kt b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/SwitchAppByDoubleTapDivider.kt
index 26203d4..3fd93d3 100644
--- a/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/SwitchAppByDoubleTapDivider.kt
+++ b/libs/WindowManager/Shell/tests/e2e/splitscreen/scenarios/src/com/android/wm/shell/scenarios/SwitchAppByDoubleTapDivider.kt
@@ -17,16 +17,16 @@
 package com.android.wm.shell.scenarios
 
 import android.app.Instrumentation
-import android.graphics.Point
 import android.tools.NavBar
 import android.tools.Rotation
-import android.tools.helpers.WindowUtils
 import android.tools.traces.parsers.WindowManagerStateHelper
 import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.UiDevice
 import com.android.launcher3.tapl.LauncherInstrumentation
 import com.android.wm.shell.Utils
 import com.android.wm.shell.flicker.utils.SplitScreenUtils
+import com.android.wm.shell.flicker.utils.SplitScreenUtils.isLeftRightSplit
+import com.android.wm.shell.flicker.utils.SplitScreenUtils.isTablet
 import org.junit.After
 import org.junit.Before
 import org.junit.Ignore
@@ -89,14 +89,14 @@
                     }
                         ?: return@add false
 
-                if (isLandscape(rotation)) {
-                    return@add if (isTablet()) {
+                if (isLeftRightSplit(instrumentation.context, rotation, device.displaySizeDp)) {
+                    return@add if (isTablet(device.displaySizeDp)) {
                         secondaryAppWindow.frame.right <= primaryAppWindow.frame.left
                     } else {
                         primaryAppWindow.frame.right <= secondaryAppWindow.frame.left
                     }
                 } else {
-                    return@add if (isTablet()) {
+                    return@add if (isTablet(device.displaySizeDp)) {
                         primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
                     } else {
                         primaryAppWindow.frame.bottom <= secondaryAppWindow.frame.top
@@ -125,14 +125,14 @@
                 val secondaryVisibleRegion =
                     secondaryAppLayer.visibleRegion?.bounds ?: return@add false
 
-                if (isLandscape(rotation)) {
-                    return@add if (isTablet()) {
+                if (isLeftRightSplit(instrumentation.context, rotation, device.displaySizeDp)) {
+                    return@add if (isTablet(device.displaySizeDp)) {
                         secondaryVisibleRegion.right <= primaryVisibleRegion.left
                     } else {
                         primaryVisibleRegion.right <= secondaryVisibleRegion.left
                     }
                 } else {
-                    return@add if (isTablet()) {
+                    return@add if (isTablet(device.displaySizeDp)) {
                         primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
                     } else {
                         primaryVisibleRegion.bottom <= secondaryVisibleRegion.top
@@ -141,15 +141,4 @@
             }
             .waitForAndVerify()
     }
-
-    private fun isLandscape(rotation: Rotation): Boolean {
-        val displayBounds = WindowUtils.getDisplayBounds(rotation)
-        return displayBounds.width() > displayBounds.height()
-    }
-
-    private fun isTablet(): Boolean {
-        val sizeDp: Point = device.displaySizeDp
-        val LARGE_SCREEN_DP_THRESHOLD = 600
-        return sizeDp.x >= LARGE_SCREEN_DP_THRESHOLD && sizeDp.y >= LARGE_SCREEN_DP_THRESHOLD
-    }
 }
diff --git a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
index feb3edc..49d6877 100644
--- a/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
+++ b/libs/WindowManager/Shell/tests/flicker/src/com/android/wm/shell/flicker/utils/SplitScreenUtils.kt
@@ -17,12 +17,14 @@
 package com.android.wm.shell.flicker.utils
 
 import android.app.Instrumentation
+import android.content.Context
 import android.graphics.Point
 import android.os.SystemClock
 import android.tools.Rotation
 import android.tools.device.apphelpers.IStandardAppHelper
 import android.tools.device.apphelpers.StandardAppHelper
 import android.tools.flicker.rules.ChangeDisplayOrientationRule
+import android.tools.helpers.WindowUtils
 import android.tools.traces.component.ComponentNameMatcher
 import android.tools.traces.component.IComponentMatcher
 import android.tools.traces.component.IComponentNameMatcher
@@ -393,4 +395,24 @@
             error("Fail to copy content in split")
         }
     }
+
+    fun isLeftRightSplit(context: Context, rotation: Rotation, displaySizeDp: Point): Boolean {
+        val allowLeftRightSplit = context.resources.getBoolean(
+            com.android.internal.R.bool.config_leftRightSplitInPortrait)
+        val displayBounds = WindowUtils.getDisplayBounds(rotation)
+        val isLandscape = displayBounds.width() > displayBounds.height()
+        if (allowLeftRightSplit && isTablet(displaySizeDp)) {
+            // Certain devices allow left/right split in portrait, so they end up with top/bottom
+            // split in landscape
+            return !isLandscape
+        } else {
+            return isLandscape
+        }
+    }
+
+    fun isTablet(displaySizeDp: Point): Boolean {
+        val LARGE_SCREEN_DP_THRESHOLD = 600
+        return displaySizeDp.x >= LARGE_SCREEN_DP_THRESHOLD
+                && displaySizeDp.y >= LARGE_SCREEN_DP_THRESHOLD
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java
index 42310ca..3c79ea7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/BubbleTransitionsTest.java
@@ -25,6 +25,7 @@
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.ArgumentMatchers.isNull;
@@ -35,6 +36,7 @@
 import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
+import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.IBinder;
 import android.view.SurfaceControl;
@@ -138,13 +140,14 @@
         return taskInfo;
     }
 
-    private TransitionInfo setupFullscreenTaskTransition(ActivityManager.RunningTaskInfo taskInfo) {
+    private TransitionInfo setupFullscreenTaskTransition(ActivityManager.RunningTaskInfo taskInfo,
+            SurfaceControl taskLeash, SurfaceControl snapshot) {
         final TransitionInfo info = new TransitionInfo(TRANSIT_CONVERT_TO_BUBBLE, 0);
-        final TransitionInfo.Change chg = new TransitionInfo.Change(taskInfo.token,
-                mock(SurfaceControl.class));
+        final TransitionInfo.Change chg = new TransitionInfo.Change(taskInfo.token, taskLeash);
         chg.setTaskInfo(taskInfo);
         chg.setMode(TRANSIT_CHANGE);
         chg.setStartAbsBounds(new Rect(0, 0, FULLSCREEN_TASK_WIDTH, FULLSCREEN_TASK_HEIGHT));
+        chg.setSnapshot(snapshot, /* luma= */ 0f);
         info.addChange(chg);
         info.addRoot(new TransitionInfo.Root(0, mock(SurfaceControl.class), 0, 0));
         return info;
@@ -172,7 +175,9 @@
         // Ensure we are communicating with the taskviewtransitions queue
         assertTrue(mTaskViewTransitions.hasPending());
 
-        final TransitionInfo info = setupFullscreenTaskTransition(taskInfo);
+        SurfaceControl taskLeash = new SurfaceControl.Builder().setName("taskLeash").build();
+        SurfaceControl snapshot = new SurfaceControl.Builder().setName("snapshot").build();
+        final TransitionInfo info = setupFullscreenTaskTransition(taskInfo, taskLeash, snapshot);
         SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
         SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
         final boolean[] finishCalled = new boolean[]{false};
@@ -183,7 +188,8 @@
         ctb.startAnimation(ctb.mTransition, info, startT, finishT, finishCb);
         assertFalse(mTaskViewTransitions.hasPending());
 
-        verify(startT).setPosition(any(), eq(0f), eq(0f));
+        verify(startT).setPosition(taskLeash, 0, 0);
+        verify(startT).setPosition(snapshot, 0, 0);
 
         verify(mBubbleData).notificationEntryUpdated(eq(mBubble), anyBoolean(), anyBoolean());
 
@@ -194,7 +200,7 @@
         // Check that preparing transition is not reset before continueExpand is called
         verify(mBubble, never()).setPreparingTransition(any());
         ArgumentCaptor<Runnable> animCb = ArgumentCaptor.forClass(Runnable.class);
-        verify(mLayerView).animateConvert(any(), any(), any(), any(), animCb.capture());
+        verify(mLayerView).animateConvert(any(), any(), anyFloat(), any(), any(), animCb.capture());
 
         // continueExpand is now called, check that preparing transition is cleared
         ctb.continueExpand();
@@ -209,14 +215,14 @@
     public void testConvertToBubble_drag() {
         ActivityManager.RunningTaskInfo taskInfo = setupBubble();
 
-        Rect draggedTaskBounds = new Rect(10, 20, 30, 40);
         WindowContainerTransaction pendingWct = new WindowContainerTransaction();
         WindowContainerToken pendingDragOpToken = createMockToken();
         pendingWct.reorder(pendingDragOpToken, /* onTop= */ false);
 
+        PointF dragPosition = new PointF(10f, 20f);
         BubbleTransitions.DragData dragData = new BubbleTransitions.DragData(
-                draggedTaskBounds, pendingWct, /* releasedOnLeft= */ false
-        );
+                /* releasedOnLeft= */ false, /* taskScale= */ 0.5f, dragPosition,
+                pendingWct);
 
         final BubbleTransitions.BubbleTransition bt = mBubbleTransitions.startConvertToBubble(
                 mBubble, taskInfo, mExpandedViewManager, mTaskViewFactory, mBubblePositioner,
@@ -234,15 +240,19 @@
                 == WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER
                 && op.getContainer() == pendingDragOpToken.asBinder())).isTrue();
 
-        final TransitionInfo info = setupFullscreenTaskTransition(taskInfo);
+        SurfaceControl taskLeash = new SurfaceControl.Builder().setName("taskLeash").build();
+        SurfaceControl snapshot = new SurfaceControl.Builder().setName("snapshot").build();
+        final TransitionInfo info = setupFullscreenTaskTransition(taskInfo, taskLeash, snapshot);
         SurfaceControl.Transaction startT = mock(SurfaceControl.Transaction.class);
         SurfaceControl.Transaction finishT = mock(SurfaceControl.Transaction.class);
         Transitions.TransitionFinishCallback finishCb = wct -> {};
         ctb.startAnimation(ctb.mTransition, info, startT, finishT, finishCb);
 
-        // Verify that dragged task bounds are used for the position
-        verify(startT).setPosition(any(), eq((float) draggedTaskBounds.left),
-                eq((float) draggedTaskBounds.top));
+        // Verify that snapshot and task are placed at where the drag ended
+        verify(startT).setPosition(taskLeash, dragPosition.x, dragPosition.y);
+        verify(startT).setPosition(snapshot, dragPosition.x, dragPosition.y);
+        // Snapshot has the scale of the dragged task
+        verify(startT).setScale(snapshot, dragData.getTaskScale(), dragData.getTaskScale());
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
index 60f1d271..d829c6a 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/bubbles/animation/ExpandedAnimationControllerTest.java
@@ -104,6 +104,7 @@
     @Test
     public void testExpansionAndCollapse() throws Exception {
         expand();
+        waitForAnimation();
         testBubblesInCorrectExpandedPositions();
         waitForMainThread();
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipDesktopStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipDesktopStateTest.java
index e85d30f..4cdb1e5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipDesktopStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/common/pip/PipDesktopStateTest.java
@@ -41,7 +41,7 @@
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer;
 import com.android.wm.shell.desktopmode.DesktopRepository;
 import com.android.wm.shell.desktopmode.DesktopUserRepositories;
-import com.android.wm.shell.desktopmode.desktopwallpaperactivity.DesktopWallpaperActivityTokenProvider;
+import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -62,11 +62,12 @@
 public class PipDesktopStateTest {
     @Mock private PipDisplayLayoutState mMockPipDisplayLayoutState;
     @Mock private Optional<DesktopUserRepositories> mMockDesktopUserRepositoriesOptional;
-    @Mock private Optional<DesktopWallpaperActivityTokenProvider>
-            mMockDesktopWallpaperActivityTokenProviderOptional;
     @Mock private DesktopUserRepositories mMockDesktopUserRepositories;
-    @Mock private DesktopWallpaperActivityTokenProvider mMockDesktopWallpaperActivityTokenProvider;
     @Mock private DesktopRepository mMockDesktopRepository;
+    @Mock
+    private Optional<DragToDesktopTransitionHandler> mMockDragToDesktopTransitionHandlerOptional;
+    @Mock private DragToDesktopTransitionHandler mMockDragToDesktopTransitionHandler;
+
     @Mock private RootTaskDisplayAreaOrganizer mMockRootTaskDisplayAreaOrganizer;
     @Mock private ActivityManager.RunningTaskInfo mMockTaskInfo;
 
@@ -78,11 +79,12 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mMockDesktopUserRepositoriesOptional.get()).thenReturn(mMockDesktopUserRepositories);
-        when(mMockDesktopWallpaperActivityTokenProviderOptional.get()).thenReturn(
-                mMockDesktopWallpaperActivityTokenProvider);
         when(mMockDesktopUserRepositories.getCurrent()).thenReturn(mMockDesktopRepository);
         when(mMockDesktopUserRepositoriesOptional.isPresent()).thenReturn(true);
-        when(mMockDesktopWallpaperActivityTokenProviderOptional.isPresent()).thenReturn(true);
+
+        when(mMockDragToDesktopTransitionHandlerOptional.get()).thenReturn(
+                mMockDragToDesktopTransitionHandler);
+        when(mMockDragToDesktopTransitionHandlerOptional.isPresent()).thenReturn(true);
 
         when(mMockTaskInfo.getDisplayId()).thenReturn(DISPLAY_ID);
         when(mMockPipDisplayLayoutState.getDisplayId()).thenReturn(DISPLAY_ID);
@@ -93,7 +95,7 @@
 
         mPipDesktopState = new PipDesktopState(mMockPipDisplayLayoutState,
                 mMockDesktopUserRepositoriesOptional,
-                mMockDesktopWallpaperActivityTokenProviderOptional,
+                mMockDragToDesktopTransitionHandlerOptional,
                 mMockRootTaskDisplayAreaOrganizer);
     }
 
@@ -110,8 +112,8 @@
     }
 
     @Test
-    public void isDesktopWindowingPipEnabled_desktopWallpaperEmpty_returnsFalse() {
-        when(mMockDesktopWallpaperActivityTokenProviderOptional.isPresent()).thenReturn(false);
+    public void isDesktopWindowingPipEnabled_dragToDesktopTransitionHandlerEmpty_returnsFalse() {
+        when(mMockDragToDesktopTransitionHandlerOptional.isPresent()).thenReturn(false);
 
         assertFalse(mPipDesktopState.isDesktopWindowingPipEnabled());
     }
@@ -123,59 +125,7 @@
     }
 
     @Test
-    public void isPipEnteringInDesktopMode_visibleCountZero_minimizedPipPresent_returnsTrue() {
-        when(mMockDesktopRepository.isAnyDeskActive(DISPLAY_ID)).thenReturn(false);
-        when(mMockDesktopRepository.isMinimizedPipPresentInDisplay(DISPLAY_ID)).thenReturn(true);
-
-        assertTrue(mPipDesktopState.isPipEnteringInDesktopMode(mMockTaskInfo));
-    }
-
-    @Test
-    public void isPipEnteringInDesktopMode_visibleCountNonzero_minimizedPipAbsent_returnsTrue() {
-        when(mMockDesktopRepository.isAnyDeskActive(DISPLAY_ID)).thenReturn(true);
-        when(mMockDesktopRepository.isMinimizedPipPresentInDisplay(DISPLAY_ID)).thenReturn(false);
-
-        assertTrue(mPipDesktopState.isPipEnteringInDesktopMode(mMockTaskInfo));
-    }
-
-    @Test
-    public void isPipEnteringInDesktopMode_visibleCountZero_minimizedPipAbsent_returnsFalse() {
-        when(mMockDesktopRepository.isAnyDeskActive(DISPLAY_ID)).thenReturn(false);
-        when(mMockDesktopRepository.isMinimizedPipPresentInDisplay(DISPLAY_ID)).thenReturn(false);
-
-        assertFalse(mPipDesktopState.isPipEnteringInDesktopMode(mMockTaskInfo));
-    }
-
-    @Test
-    public void shouldExitPipExitDesktopMode_visibleCountZero_wallpaperInvisible_returnsFalse() {
-        when(mMockDesktopRepository.isAnyDeskActive(DISPLAY_ID)).thenReturn(false);
-        when(mMockDesktopWallpaperActivityTokenProvider.isWallpaperActivityVisible(
-                DISPLAY_ID)).thenReturn(false);
-
-        assertFalse(mPipDesktopState.shouldExitPipExitDesktopMode());
-    }
-
-    @Test
-    public void shouldExitPipExitDesktopMode_visibleCountNonzero_wallpaperVisible_returnsFalse() {
-        when(mMockDesktopRepository.isAnyDeskActive(DISPLAY_ID)).thenReturn(true);
-        when(mMockDesktopWallpaperActivityTokenProvider.isWallpaperActivityVisible(
-                DISPLAY_ID)).thenReturn(true);
-
-        assertFalse(mPipDesktopState.shouldExitPipExitDesktopMode());
-    }
-
-    @Test
-    public void shouldExitPipExitDesktopMode_visibleCountZero_wallpaperVisible_returnsTrue() {
-        when(mMockDesktopRepository.isAnyDeskActive(DISPLAY_ID)).thenReturn(false);
-        when(mMockDesktopWallpaperActivityTokenProvider.isWallpaperActivityVisible(
-                DISPLAY_ID)).thenReturn(true);
-
-        assertTrue(mPipDesktopState.shouldExitPipExitDesktopMode());
-    }
-
-    @Test
     public void getOutPipWindowingMode_exitToDesktop_displayFreeform_returnsUndefined() {
-        // Set visible task count to 1 so isPipExitingToDesktopMode returns true
         when(mMockDesktopRepository.isAnyDeskActive(DISPLAY_ID)).thenReturn(true);
         setDisplayWindowingMode(WINDOWING_MODE_FREEFORM);
 
@@ -184,7 +134,6 @@
 
     @Test
     public void getOutPipWindowingMode_exitToDesktop_displayFullscreen_returnsFreeform() {
-        // Set visible task count to 1 so isPipExitingToDesktopMode returns true
         when(mMockDesktopRepository.isAnyDeskActive(DISPLAY_ID)).thenReturn(true);
         setDisplayWindowingMode(WINDOWING_MODE_FULLSCREEN);
 
@@ -198,6 +147,20 @@
         assertEquals(WINDOWING_MODE_UNDEFINED, mPipDesktopState.getOutPipWindowingMode());
     }
 
+    @Test
+    public void isDragToDesktopInProgress_inProgress_returnsTrue() {
+        when(mMockDragToDesktopTransitionHandler.getInProgress()).thenReturn(true);
+
+        assertTrue(mPipDesktopState.isDragToDesktopInProgress());
+    }
+
+    @Test
+    public void isDragToDesktopInProgress_notInProgress_returnsFalse() {
+        when(mMockDragToDesktopTransitionHandler.getInProgress()).thenReturn(false);
+
+        assertFalse(mPipDesktopState.isDragToDesktopInProgress());
+    }
+
     private void setDisplayWindowingMode(int windowingMode) {
         mDefaultTda.configuration.windowConfiguration.setWindowingMode(windowingMode);
     }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt
index 70a30a3..d58f8a3 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopActivityOrientationChangeHandlerTest.kt
@@ -188,7 +188,7 @@
             SCREEN_ORIENTATION_LANDSCAPE,
         )
 
-        verify(resizeTransitionHandler, never()).startTransition(any(), any())
+        verify(resizeTransitionHandler, never()).startTransition(any(), any(), any())
     }
 
     @Test
@@ -209,7 +209,7 @@
             SCREEN_ORIENTATION_LANDSCAPE,
         )
 
-        verify(resizeTransitionHandler, never()).startTransition(any(), any())
+        verify(resizeTransitionHandler, never()).startTransition(any(), any(), any())
     }
 
     @Test
@@ -225,7 +225,7 @@
 
         handler.handleActivityOrientationChange(task, newTask)
 
-        verify(resizeTransitionHandler, never()).startTransition(any(), any())
+        verify(resizeTransitionHandler, never()).startTransition(any(), any(), any())
     }
 
     @Test
@@ -240,7 +240,7 @@
             SCREEN_ORIENTATION_LANDSCAPE,
         )
 
-        verify(resizeTransitionHandler, never()).startTransition(any(), any())
+        verify(resizeTransitionHandler, never()).startTransition(any(), any(), any())
     }
 
     @Test
@@ -318,7 +318,7 @@
         val arg: ArgumentCaptor<WindowContainerTransaction> =
             ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
         verify(resizeTransitionHandler, atLeastOnce())
-            .startTransition(capture(arg), eq(currentBounds))
+            .startTransition(capture(arg), eq(currentBounds), isNull())
         return arg.value
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandlerTest.kt
new file mode 100644
index 0000000..fbc9406
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeMoveToDisplayTransitionHandlerTest.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.wm.shell.desktopmode
+
+import android.testing.AndroidTestingRunner
+import android.testing.TestableLooper.RunWithLooper
+import android.view.WindowManager
+import android.window.TransitionInfo
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.util.StubTransaction
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+
+@SmallTest
+@RunWithLooper
+@RunWith(AndroidTestingRunner::class)
+class DesktopModeMoveToDisplayTransitionHandlerTest : ShellTestCase() {
+    private lateinit var handler: DesktopModeMoveToDisplayTransitionHandler
+
+    @Before
+    fun setUp() {
+        handler = DesktopModeMoveToDisplayTransitionHandler(StubTransaction())
+    }
+
+    @Test
+    fun handleRequest_returnsNull() {
+        assertNull(handler.handleRequest(mock(), mock()))
+    }
+
+    @Test
+    fun startAnimation_changeWithinDisplay_returnsFalse() {
+        val animates =
+            handler.startAnimation(
+                transition = mock(),
+                info =
+                    TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply {
+                        addChange(
+                            TransitionInfo.Change(mock(), mock()).apply { setDisplayId(1, 1) }
+                        )
+                    },
+                startTransaction = StubTransaction(),
+                finishTransaction = StubTransaction(),
+                finishCallback = mock(),
+            )
+
+        assertFalse("Should not animate open transition", animates)
+    }
+
+    @Test
+    fun startAnimation_changeMoveToDisplay_returnsTrue() {
+        val animates =
+            handler.startAnimation(
+                transition = mock(),
+                info =
+                    TransitionInfo(WindowManager.TRANSIT_CHANGE, /* flags= */ 0).apply {
+                        addChange(
+                            TransitionInfo.Change(mock(), mock()).apply { setDisplayId(1, 2) }
+                        )
+                    },
+                startTransaction = StubTransaction(),
+                finishTransaction = StubTransaction(),
+                finishCallback = mock(),
+            )
+
+        assertTrue("Should animate display change transition", animates)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
index dcc9e24..fe1dc29 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeVisualIndicatorTest.kt
@@ -20,6 +20,7 @@
 import android.app.ActivityManager.RunningTaskInfo
 import android.graphics.PointF
 import android.graphics.Rect
+import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
@@ -28,6 +29,7 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.policy.SystemBarUtils
 import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
+import com.android.window.flags.Flags.FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX
 import com.android.wm.shell.R
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
 import com.android.wm.shell.ShellTestCase
@@ -45,6 +47,8 @@
 import org.mockito.ArgumentMatchers.anyInt
 import org.mockito.Mock
 import org.mockito.kotlin.any
+import org.mockito.kotlin.never
+import org.mockito.kotlin.verify
 import org.mockito.kotlin.whenever
 
 /**
@@ -345,6 +349,38 @@
         assertThat(visualIndicator.indicatorBounds).isEqualTo(dropTargetBounds)
     }
 
+    @Test
+    @DisableFlags(FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX)
+    fun createIndicator_inTransitionFlagDisabled_isAttachedToDisplayArea() {
+        createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN)
+
+        verify(taskDisplayAreaOrganizer).attachToDisplayArea(anyInt(), any())
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX)
+    fun createIndicator_fromFreeform_inTransitionFlagEnabled_isAttachedToDisplayArea() {
+        createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FREEFORM)
+
+        verify(taskDisplayAreaOrganizer).attachToDisplayArea(anyInt(), any())
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX)
+    fun createIndicator_fromFullscreen_inTransitionFlagEnabled_notAttachedToDisplayArea() {
+        createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_FULLSCREEN)
+
+        verify(taskDisplayAreaOrganizer, never()).attachToDisplayArea(anyInt(), any())
+    }
+
+    @Test
+    @EnableFlags(FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX)
+    fun createIndicator_fromSplit_inTransitionFlagEnabled_notAttachedToDisplayArea() {
+        createVisualIndicator(DesktopModeVisualIndicator.DragStartState.FROM_SPLIT)
+
+        verify(taskDisplayAreaOrganizer, never()).attachToDisplayArea(anyInt(), any())
+    }
+
     private fun createVisualIndicator(dragStartState: DesktopModeVisualIndicator.DragStartState) {
         visualIndicator =
             DesktopModeVisualIndicator(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
index a43b4dd..de92d39 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopRepositoryTest.kt
@@ -26,7 +26,6 @@
 import androidx.test.filters.SmallTest
 import com.android.window.flags.Flags
 import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PERSISTENCE
-import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP
 import com.android.window.flags.Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.TestShellExecutor
@@ -89,7 +88,7 @@
         datastoreScope = CoroutineScope(Dispatchers.Unconfined + SupervisorJob())
         shellInit = spy(ShellInit(testExecutor))
 
-        repo = DesktopRepository(persistentRepository, datastoreScope, DEFAULT_USER_ID)
+        repo = spy(DesktopRepository(persistentRepository, datastoreScope, DEFAULT_USER_ID))
         whenever(runBlocking { persistentRepository.readDesktop(any(), any()) })
             .thenReturn(Desktop.getDefaultInstance())
         shellInit.init()
@@ -1172,6 +1171,7 @@
 
         val tasksBeforeRemoval = repo.removeDesk(deskId = DEFAULT_DISPLAY)
 
+        verify(repo, times(1)).notifyVisibleTaskListeners(DEFAULT_DISPLAY, visibleTasksCount = 0)
         assertThat(tasksBeforeRemoval).containsExactly(1, 2, 3).inOrder()
         assertThat(repo.getActiveTasks(displayId = DEFAULT_DISPLAY)).isEmpty()
     }
@@ -1185,6 +1185,7 @@
 
         repo.removeDesk(deskId = 3)
 
+        verify(repo, times(1)).notifyVisibleTaskListeners(DEFAULT_DISPLAY, visibleTasksCount = 0)
         assertThat(repo.getDeskIds(displayId = DEFAULT_DISPLAY)).doesNotContain(3)
     }
 
@@ -1197,6 +1198,7 @@
 
         repo.removeDesk(deskId = 2)
 
+        verify(repo, times(1)).notifyVisibleTaskListeners(DEFAULT_DISPLAY, visibleTasksCount = 0)
         assertThat(repo.getDeskIds(displayId = DEFAULT_DISPLAY)).doesNotContain(2)
     }
 
@@ -1242,39 +1244,6 @@
     }
 
     @Test
-    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
-    fun setPipShouldKeepDesktopActive_shouldKeepDesktopActive() {
-        assertThat(repo.shouldDesktopBeActiveForPip(DEFAULT_DESKTOP_ID)).isFalse()
-
-        repo.setTaskInPip(DEFAULT_DESKTOP_ID, taskId = 1, enterPip = true)
-        repo.setPipShouldKeepDesktopActive(DEFAULT_DESKTOP_ID, keepActive = true)
-
-        assertThat(repo.shouldDesktopBeActiveForPip(DEFAULT_DESKTOP_ID)).isTrue()
-    }
-
-    @Test
-    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
-    fun setPipShouldNotKeepDesktopActive_shouldNotKeepDesktopActive() {
-        repo.setTaskInPip(DEFAULT_DESKTOP_ID, taskId = 1, enterPip = true)
-        assertThat(repo.shouldDesktopBeActiveForPip(DEFAULT_DESKTOP_ID)).isTrue()
-
-        repo.setPipShouldKeepDesktopActive(DEFAULT_DESKTOP_ID, keepActive = false)
-
-        assertThat(repo.shouldDesktopBeActiveForPip(DEFAULT_DESKTOP_ID)).isFalse()
-    }
-
-    @Test
-    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
-    fun removeTaskInPip_shouldNotKeepDesktopActive() {
-        repo.setTaskInPip(DEFAULT_DESKTOP_ID, taskId = 1, enterPip = true)
-        assertThat(repo.shouldDesktopBeActiveForPip(DEFAULT_DESKTOP_ID)).isTrue()
-
-        repo.setTaskInPip(DEFAULT_DESKTOP_ID, taskId = 1, enterPip = false)
-
-        assertThat(repo.shouldDesktopBeActiveForPip(DEFAULT_DESKTOP_ID)).isFalse()
-    }
-
-    @Test
     @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
     fun addTask_deskDoesNotExists_createsDesk() {
         repo.addTask(displayId = 999, taskId = 6, isVisible = true)
@@ -1458,6 +1427,7 @@
         repo.removeDesk(deskId = 1)
         executor.flushAll()
 
+        verify(repo, times(1)).notifyVisibleTaskListeners(DEFAULT_DISPLAY, visibleTasksCount = 0)
         val lastRemoval = assertNotNull(listener.lastRemoval)
         assertThat(lastRemoval.displayId).isEqualTo(0)
         assertThat(lastRemoval.deskId).isEqualTo(1)
@@ -1474,6 +1444,7 @@
         repo.removeDesk(deskId = 2)
         executor.flushAll()
 
+        verify(repo, times(0)).notifyVisibleTaskListeners(DEFAULT_DISPLAY, visibleTasksCount = 0)
         assertThat(listener.lastRemoval).isNull()
     }
 
@@ -1489,6 +1460,7 @@
         repo.removeDesk(deskId = 1)
         executor.flushAll()
 
+        verify(repo, times(1)).notifyVisibleTaskListeners(DEFAULT_DISPLAY, visibleTasksCount = 0)
         val lastActivationChange = assertNotNull(listener.lastActivationChange)
         assertThat(lastActivationChange.displayId).isEqualTo(0)
         assertThat(lastActivationChange.oldActive).isEqualTo(1)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
index 6b0ee5b..4ace1b2 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt
@@ -119,9 +119,8 @@
     }
 
     @Test
-    fun onTaskChanging_freeformTask_nonActiveTaskInDesktopRepo_addsTaskToDesktopRepo() {
+    fun onTaskChanging_freeformTask_addsTaskToDesktopRepo() {
         val task = createFreeformTask().apply { isVisible = true }
-        whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(false)
 
         desktopTaskChangeListener.onTaskChanging(task)
 
@@ -129,28 +128,6 @@
     }
 
     @Test
-    fun onTaskChanging_freeformTask_activeVisibleTaskInDesktopRepo_updatesTaskVisibility() {
-        val task = createFreeformTask().apply { isVisible = true }
-        whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true)
-
-        desktopTaskChangeListener.onTaskChanging(task)
-
-        verify(desktopUserRepositories.current)
-            .updateTask(task.displayId, task.taskId, task.isVisible)
-    }
-
-    @Test
-    fun onTaskChanging_freeformTask_activeNonVisibleTask_updatesTaskVisibility() {
-        val task = createFreeformTask().apply { isVisible = false }
-        whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true)
-
-        desktopTaskChangeListener.onTaskChanging(task)
-
-        verify(desktopUserRepositories.current)
-            .updateTask(task.displayId, task.taskId, task.isVisible)
-    }
-
-    @Test
     fun onTaskMovingToFront_fullscreenTask_activeTaskInDesktopRepo_removesTaskFromRepo() {
         val task = createFullscreenTask().apply { isVisible = true }
         whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true)
@@ -180,6 +157,28 @@
     }
 
     @Test
+    fun onTaskMovingToBack_activeTaskInRepo_updatesTask() {
+        val task = createFreeformTask().apply { isVisible = true }
+        whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true)
+
+        desktopTaskChangeListener.onTaskMovingToBack(task)
+
+        verify(desktopUserRepositories.current)
+            .updateTask(task.displayId, task.taskId, /* isVisible= */ false)
+    }
+
+    @Test
+    fun onTaskMovingToBack_nonActiveTaskInRepo_noop() {
+        val task = createFreeformTask().apply { isVisible = true }
+        whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(false)
+
+        desktopTaskChangeListener.onTaskMovingToBack(task)
+
+        verify(desktopUserRepositories.current, never())
+            .updateTask(task.displayId, task.taskId, /* isVisible= */ false)
+    }
+
+    @Test
     @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
     fun onTaskClosing_backNavEnabled_nonClosingTask_minimizesTaskInRepo() {
         val task = createFreeformTask().apply { isVisible = true }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index 63bf6841..8f499c9 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -87,7 +87,6 @@
 import com.android.internal.jank.InteractionJankMonitor
 import com.android.window.flags.Flags
 import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
-import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_PIP
 import com.android.window.flags.Flags.FLAG_ENABLE_DISPLAY_FOCUS_IN_SHELL_TRANSITIONS
 import com.android.window.flags.Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP
 import com.android.window.flags.Flags.FLAG_ENABLE_MOVE_TO_NEXT_DISPLAY_SHORTCUT
@@ -264,6 +263,8 @@
     @Mock private lateinit var packageManager: PackageManager
     @Mock private lateinit var mockDisplayContext: Context
     @Mock private lateinit var dragToDisplayTransitionHandler: DragToDisplayTransitionHandler
+    @Mock
+    private lateinit var moveToDisplayTransitionHandler: DesktopModeMoveToDisplayTransitionHandler
 
     private lateinit var controller: DesktopTasksController
     private lateinit var shellInit: ShellInit
@@ -446,6 +447,7 @@
             userProfileContexts,
             desktopModeCompatPolicy,
             dragToDisplayTransitionHandler,
+            moveToDisplayTransitionHandler,
         )
 
     @After
@@ -656,38 +658,6 @@
     }
 
     @Test
-    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
-    fun isDesktopModeShowing_minimizedPipTask_wallpaperVisible_returnsTrue() {
-        val pipTask = setUpPipTask(autoEnterEnabled = true)
-        whenever(desktopWallpaperActivityTokenProvider.isWallpaperActivityVisible())
-            .thenReturn(true)
-
-        taskRepository.setTaskInPip(DEFAULT_DISPLAY, pipTask.taskId, enterPip = true)
-
-        assertThat(controller.isDesktopModeShowing(displayId = DEFAULT_DISPLAY)).isTrue()
-    }
-
-    @Test
-    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
-    fun isDesktopModeShowing_minimizedPipTask_wallpaperNotVisible_returnsFalse() {
-        val pipTask = setUpPipTask(autoEnterEnabled = true)
-        whenever(desktopWallpaperActivityTokenProvider.isWallpaperActivityVisible())
-            .thenReturn(false)
-
-        taskRepository.setTaskInPip(DEFAULT_DISPLAY, pipTask.taskId, enterPip = true)
-
-        assertThat(controller.isDesktopModeShowing(displayId = DEFAULT_DISPLAY)).isFalse()
-    }
-
-    @Test
-    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
-    fun isDesktopModeShowing_pipTaskNotMinimizedNorVisible_returnsFalse() {
-        setUpPipTask(autoEnterEnabled = true)
-
-        assertThat(controller.isDesktopModeShowing(displayId = DEFAULT_DISPLAY)).isFalse()
-    }
-
-    @Test
     @EnableFlags(
         Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
         Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY,
@@ -2554,7 +2524,7 @@
         whenever(rootTaskDisplayAreaOrganizer.displayIds).thenReturn(intArrayOf(DEFAULT_DISPLAY))
         val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
         controller.moveToNextDisplay(task.taskId)
-        verifyWCTNotExecuted()
+        verify(transitions, never()).startTransition(anyInt(), any(), anyOrNull())
     }
 
     @Test
@@ -2572,9 +2542,12 @@
         controller.moveToNextDisplay(task.taskId)
 
         val taskChange =
-            getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find {
-                it.container == task.token.asBinder() && it.isReparent
-            }
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .hierarchyOps
+                .find { it.container == task.token.asBinder() && it.isReparent }
         assertNotNull(taskChange)
         assertThat(taskChange.newParent).isEqualTo(secondDisplayArea.token.asBinder())
         assertThat(taskChange.toTop).isTrue()
@@ -2595,9 +2568,12 @@
         controller.moveToNextDisplay(task.taskId)
 
         val taskChange =
-            getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find {
-                it.container == task.token.asBinder() && it.isReparent
-            }
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .hierarchyOps
+                .find { it.container == task.token.asBinder() && it.isReparent }
         assertNotNull(taskChange)
         assertThat(taskChange.newParent).isEqualTo(defaultDisplayArea.token.asBinder())
         assertThat(taskChange.toTop).isTrue()
@@ -2622,7 +2598,12 @@
 
         controller.moveToNextDisplay(task.taskId)
 
-        with(getLatestWct(type = TRANSIT_CHANGE)) {
+        with(
+            getLatestWct(
+                type = TRANSIT_CHANGE,
+                handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+            )
+        ) {
             val wallpaperChange =
                 hierarchyOps.find { op -> op.container == wallpaperToken.asBinder() }
             assertNotNull(wallpaperChange)
@@ -2648,9 +2629,12 @@
         controller.moveToNextDisplay(task.taskId)
 
         val wallpaperChange =
-            getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find { op ->
-                op.container == wallpaperToken.asBinder()
-            }
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .hierarchyOps
+                .find { op -> op.container == wallpaperToken.asBinder() }
         assertNotNull(wallpaperChange)
         assertThat(wallpaperChange.type).isEqualTo(HIERARCHY_OP_TYPE_REMOVE_TASK)
     }
@@ -2682,7 +2666,12 @@
 
         controller.moveToNextDisplay(task.taskId)
 
-        val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()]
+        val taskChange =
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .changes[task.token.asBinder()]
         assertNotNull(taskChange)
         // To preserve DP size, pixel size is changed to 320x240. The ratio of the left margin
         // to the right margin and the ratio of the top margin to bottom margin are also
@@ -2719,7 +2708,12 @@
 
         controller.moveToNextDisplay(task.taskId)
 
-        val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()]
+        val taskChange =
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .changes[task.token.asBinder()]
         assertNotNull(taskChange)
         assertThat(taskChange.configuration.windowConfiguration.bounds)
             .isEqualTo(Rect(960, 480, 1280, 720))
@@ -2750,7 +2744,12 @@
 
         controller.moveToNextDisplay(task.taskId)
 
-        val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()]
+        val taskChange =
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .changes[task.token.asBinder()]
         assertNotNull(taskChange)
         // DP size is preserved. The window is centered in the destination display.
         assertThat(taskChange.configuration.windowConfiguration.bounds)
@@ -2788,7 +2787,12 @@
 
         controller.moveToNextDisplay(task.taskId)
 
-        val taskChange = getLatestWct(type = TRANSIT_CHANGE).changes[task.token.asBinder()]
+        val taskChange =
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .changes[task.token.asBinder()]
         assertNotNull(taskChange)
         assertThat(taskChange.configuration.windowConfiguration.bounds.left).isAtLeast(0)
         assertThat(taskChange.configuration.windowConfiguration.bounds.top).isAtLeast(0)
@@ -2815,9 +2819,14 @@
         controller.moveToNextDisplay(task.taskId)
 
         val taskChange =
-            getLatestWct(type = TRANSIT_CHANGE).hierarchyOps.find {
-                it.container == task.token.asBinder() && it.type == HIERARCHY_OP_TYPE_REORDER
-            }
+            getLatestWct(
+                    type = TRANSIT_CHANGE,
+                    handlerClass = DesktopModeMoveToDisplayTransitionHandler::class.java,
+                )
+                .hierarchyOps
+                .find {
+                    it.container == task.token.asBinder() && it.type == HIERARCHY_OP_TYPE_REORDER
+                }
         assertNotNull(taskChange)
         assertThat(taskChange.toTop).isTrue()
         assertThat(taskChange.includingParents()).isTrue()
@@ -2918,11 +2927,10 @@
         verify(desksOrganizer).activateDesk(any(), eq(targetDeskId))
         verify(desksTransitionsObserver)
             .addPendingTransition(
-                DeskTransition.ActiveDeskWithTask(
+                DeskTransition.ActivateDesk(
                     token = transition,
                     displayId = SECOND_DISPLAY,
                     deskId = targetDeskId,
-                    enterTaskId = task.taskId,
                 )
             )
     }
@@ -3103,42 +3111,6 @@
     }
 
     @Test
-    @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_PIP)
-    fun onDesktopWindowClose_minimizedPipPresent_doesNotExitDesktop() {
-        val freeformTask = setUpFreeformTask().apply { isFocused = true }
-        val pipTask = setUpPipTask(autoEnterEnabled = true)
-
-        taskRepository.setTaskInPip(DEFAULT_DISPLAY, pipTask.taskId, enterPip = true)
-        val wct = WindowContainerTransaction()
-        controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, freeformTask)
-
-        verifyExitDesktopWCTNotExecuted()
-    }
-
-    @Test
-    @EnableFlags(
-        FLAG_ENABLE_DESKTOP_WINDOWING_PIP,
-        Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
-    )
-    fun onDesktopWindowClose_minimizedPipNotPresent_exitDesktop() {
-        val freeformTask = setUpFreeformTask()
-        val pipTask = setUpPipTask(autoEnterEnabled = true)
-        val handler = mock(TransitionHandler::class.java)
-        whenever(transitions.dispatchRequest(any(), any(), anyOrNull()))
-            .thenReturn(android.util.Pair(handler, WindowContainerTransaction()))
-
-        controller.minimizeTask(pipTask, MinimizeReason.MINIMIZE_BUTTON)
-        verifyExitDesktopWCTNotExecuted()
-
-        taskRepository.setTaskInPip(DEFAULT_DISPLAY, pipTask.taskId, enterPip = false)
-        val wct = WindowContainerTransaction()
-        controller.onDesktopWindowClose(wct, displayId = DEFAULT_DISPLAY, freeformTask)
-
-        // Moves wallpaper activity to back when leaving desktop
-        wct.assertReorder(wallpaperToken, toTop = false)
-    }
-
-    @Test
     @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
     fun onDesktopWindowClose_lastWindow_deactivatesDesk() {
         val task = setUpFreeformTask()
@@ -3267,26 +3239,6 @@
     }
 
     @Test
-    fun onPipTaskMinimize_doesntRemoveWallpaper() {
-        val task = setUpPipTask(autoEnterEnabled = true)
-        val handler = mock(TransitionHandler::class.java)
-        whenever(transitions.dispatchRequest(any(), any(), anyOrNull()))
-            .thenReturn(android.util.Pair(handler, WindowContainerTransaction()))
-
-        controller.minimizeTask(task, MinimizeReason.MINIMIZE_BUTTON)
-
-        val captor = argumentCaptor<WindowContainerTransaction>()
-        verify(freeformTaskTransitionStarter).startPipTransition(captor.capture())
-        assertThat(
-                captor.firstValue.hierarchyOps.none { hop ->
-                    hop.type == HIERARCHY_OP_TYPE_REMOVE_TASK &&
-                        hop.container == wallpaperToken.asBinder()
-                }
-            )
-            .isTrue()
-    }
-
-    @Test
     fun onDesktopWindowMinimize_singleActiveTask_noWallpaperActivityToken_doesntRemoveWallpaper() {
         val task = setUpFreeformTask(active = true)
         val transition = Binder()
@@ -3614,9 +3566,15 @@
         val wct = controller.handleRequest(Binder(), createTransition(fullscreenTask))
 
         // Make sure we reorder the new task to top, and the back task to the bottom
-        assertThat(wct!!.hierarchyOps.size).isEqualTo(9)
+        assertThat(wct!!.hierarchyOps.size).isEqualTo(8)
         wct.assertReorderAt(0, fullscreenTask, toTop = true)
-        wct.assertReorderAt(8, freeformTasks[0], toTop = false)
+        // Oldest task that needs to minimized is never reordered to top over Home.
+        val taskToMinimize = freeformTasks[0]
+        wct.assertWithoutHop { hop ->
+            hop.container == taskToMinimize.token &&
+                hop.type == HIERARCHY_OP_TYPE_REORDER &&
+                hop.toTop == true
+        }
     }
 
     @Test
@@ -3631,12 +3589,18 @@
 
         val wct = controller.handleRequest(Binder(), createTransition(fullscreenTask))
 
-        assertThat(wct!!.hierarchyOps.size).isEqualTo(10)
+        assertThat(wct!!.hierarchyOps.size).isEqualTo(9)
         wct.assertReorderAt(0, fullscreenTask, toTop = true)
         // Make sure we reorder the home task to the top, desktop tasks to top of them and minimized
         // task is under the home task.
         wct.assertReorderAt(1, homeTask, toTop = true)
-        wct.assertReorderAt(9, freeformTasks[0], toTop = false)
+        // Oldest task that needs to minimized is never reordered to top over Home.
+        val taskToMinimize = freeformTasks[0]
+        wct.assertWithoutHop { hop ->
+            hop.container == taskToMinimize.token &&
+                hop.type == HIERARCHY_OP_TYPE_REORDER &&
+                hop.toTop == true
+        }
     }
 
     @Test
@@ -4735,32 +4699,6 @@
     }
 
     @Test
-    @EnableFlags(
-        FLAG_ENABLE_DESKTOP_WINDOWING_PIP,
-        Flags.FLAG_ENABLE_DESKTOP_WALLPAPER_ACTIVITY_FOR_SYSTEM_USER,
-    )
-    fun moveFocusedTaskToFullscreen_minimizedPipPresent_removeWallpaperActivity() {
-        val freeformTask = setUpFreeformTask()
-        val pipTask = setUpPipTask(autoEnterEnabled = true)
-        val handler = mock(TransitionHandler::class.java)
-        whenever(transitions.dispatchRequest(any(), any(), anyOrNull()))
-            .thenReturn(android.util.Pair(handler, WindowContainerTransaction()))
-
-        controller.minimizeTask(pipTask, MinimizeReason.MINIMIZE_BUTTON)
-        verifyExitDesktopWCTNotExecuted()
-
-        freeformTask.isFocused = true
-        controller.enterFullscreen(DEFAULT_DISPLAY, transitionSource = UNKNOWN)
-
-        val wct = getLatestExitDesktopWct()
-        val taskChange = assertNotNull(wct.changes[freeformTask.token.asBinder()])
-        assertThat(taskChange.windowingMode)
-            .isEqualTo(WINDOWING_MODE_UNDEFINED) // inherited FULLSCREEN
-        // Moves wallpaper activity to back when leaving desktop
-        wct.assertReorder(wallpaperToken, toTop = false)
-    }
-
-    @Test
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION)
     @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
     fun removeDesk_multipleTasks_removesAll() {
@@ -5368,7 +5306,8 @@
         )
 
         // Assert that task is NOT updated via WCT
-        verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any())
+        verify(toggleResizeDesktopTaskTransitionHandler, never())
+            .startTransition(any(), any(), any())
         // Assert that task leash is updated via Surface Animations
         verify(mReturnToDragStartAnimator)
             .start(
@@ -5853,7 +5792,8 @@
             InputMethod.TOUCH,
         )
         // Assert that task is NOT updated via WCT
-        verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any())
+        verify(toggleResizeDesktopTaskTransitionHandler, never())
+            .startTransition(any(), any(), any())
 
         // Assert that task leash is updated via Surface Animations
         verify(mReturnToDragStartAnimator)
@@ -5950,7 +5890,8 @@
         )
 
         // Assert that task is NOT updated via WCT
-        verify(toggleResizeDesktopTaskTransitionHandler, never()).startTransition(any(), any())
+        verify(toggleResizeDesktopTaskTransitionHandler, never())
+            .startTransition(any(), any(), any())
         verify(mockToast).show()
     }
 
@@ -6877,8 +6818,7 @@
     }
 
     private fun setUpPipTask(autoEnterEnabled: Boolean): RunningTaskInfo =
-        // active = false marks the task as non-visible; PiP window doesn't count as visible tasks
-        setUpFreeformTask(active = false).apply {
+        setUpFreeformTask().apply {
             pictureInPictureParams =
                 PictureInPictureParams.Builder().setAutoEnterEnabled(autoEnterEnabled).build()
         }
@@ -7019,7 +6959,7 @@
     ): WindowContainerTransaction {
         val arg = argumentCaptor<WindowContainerTransaction>()
         verify(toggleResizeDesktopTaskTransitionHandler, atLeastOnce())
-            .startTransition(arg.capture(), eq(currentBounds))
+            .startTransition(arg.capture(), eq(currentBounds), isNull())
         return arg.lastValue
     }
 
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
index 62e3c54..7610364 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt
@@ -172,6 +172,20 @@
     }
 
     @Test
+    fun createDesktopTasksLimiter_withNoLimit_shouldSucceed() {
+        // Instantiation should succeed without an error.
+        DesktopTasksLimiter(
+            transitions,
+            userRepositories,
+            shellTaskOrganizer,
+            maxTasksLimit = null,
+            interactionJankMonitor,
+            mContext,
+            handler,
+        )
+    }
+
+    @Test
     fun addPendingMinimizeTransition_taskIsNotMinimized() {
         desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
         desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
index 5b0f94f..fd8842b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
@@ -340,51 +340,6 @@
     }
 
     @Test
-    fun transitOpenWallpaper_wallpaperActivityVisibilitySaved() {
-        val wallpaperTask = createWallpaperTaskInfo()
-
-        transitionObserver.onTransitionReady(
-            transition = mock(),
-            info = createOpenChangeTransition(wallpaperTask),
-            startTransaction = mock(),
-            finishTransaction = mock(),
-        )
-
-        verify(desktopWallpaperActivityTokenProvider)
-            .setWallpaperActivityIsVisible(isVisible = true, wallpaperTask.displayId)
-    }
-
-    @Test
-    fun transitToFrontWallpaper_wallpaperActivityVisibilitySaved() {
-        val wallpaperTask = createWallpaperTaskInfo()
-
-        transitionObserver.onTransitionReady(
-            transition = mock(),
-            info = createToFrontTransition(wallpaperTask),
-            startTransaction = mock(),
-            finishTransaction = mock(),
-        )
-
-        verify(desktopWallpaperActivityTokenProvider)
-            .setWallpaperActivityIsVisible(isVisible = true, wallpaperTask.displayId)
-    }
-
-    @Test
-    fun transitToBackWallpaper_wallpaperActivityVisibilitySaved() {
-        val wallpaperTask = createWallpaperTaskInfo()
-
-        transitionObserver.onTransitionReady(
-            transition = mock(),
-            info = createToBackTransition(wallpaperTask),
-            startTransaction = mock(),
-            finishTransaction = mock(),
-        )
-
-        verify(desktopWallpaperActivityTokenProvider)
-            .setWallpaperActivityIsVisible(isVisible = false, wallpaperTask.displayId)
-    }
-
-    @Test
     fun transitCloseWallpaper_wallpaperActivityVisibilitySaved() {
         val wallpaperTask = createWallpaperTaskInfo()
 
@@ -407,7 +362,7 @@
 
         transitionObserver.onTransitionReady(
             transition = pipTransition,
-            info = createOpenChangeTransition(task, TRANSIT_PIP),
+            info = createOpenChangeTransition(task, type = TRANSIT_PIP),
             startTransaction = mock(),
             finishTransaction = mock(),
         )
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
index de55db8..0871d38 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DragToDesktopTransitionHandlerTest.kt
@@ -11,6 +11,8 @@
 import android.graphics.Rect
 import android.os.IBinder
 import android.os.SystemProperties
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.view.SurfaceControl
@@ -23,6 +25,7 @@
 import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_HOLD
 import com.android.internal.jank.Cuj.CUJ_DESKTOP_MODE_ENTER_APP_HANDLE_DRAG_RELEASE
 import com.android.internal.jank.InteractionJankMonitor
+import com.android.window.flags.Flags
 import com.android.wm.shell.RootTaskDisplayAreaOrganizer
 import com.android.wm.shell.ShellTestCase
 import com.android.wm.shell.TestRunningTaskInfoBuilder
@@ -78,6 +81,7 @@
     @Mock private lateinit var homeTaskLeash: SurfaceControl
     @Mock private lateinit var desktopUserRepositories: DesktopUserRepositories
     @Mock private lateinit var bubbleController: BubbleController
+    @Mock private lateinit var visualIndicator: DesktopModeVisualIndicator
 
     private val transactionSupplier = Supplier { mock<SurfaceControl.Transaction>() }
 
@@ -740,11 +744,47 @@
         assertThat(fraction).isWithin(TOLERANCE).of(0f)
     }
 
+    @Test
+    @EnableFlags(Flags.FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX)
+    fun startDrag_indicatorFlagEnabled_attachesIndicatorToTransitionRoot() {
+        val task = createTask()
+        val rootLeash = mock<SurfaceControl>()
+        val startTransaction = mock<SurfaceControl.Transaction>()
+        startDrag(
+            defaultHandler,
+            task,
+            startTransaction = startTransaction,
+            transitionRootLeash = rootLeash,
+        )
+
+        verify(visualIndicator).reparentLeash(startTransaction, rootLeash)
+        verify(visualIndicator).fadeInIndicator()
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_ENABLE_VISUAL_INDICATOR_IN_TRANSITION_BUGFIX)
+    fun startDrag_indicatorFlagDisabled_doesNotAttachIndicatorToTransitionRoot() {
+        val task = createTask()
+        val rootLeash = mock<SurfaceControl>()
+        val startTransaction = mock<SurfaceControl.Transaction>()
+        startDrag(
+            defaultHandler,
+            task,
+            startTransaction = startTransaction,
+            transitionRootLeash = rootLeash,
+        )
+
+        verify(visualIndicator, never()).reparentLeash(any(), any())
+        verify(visualIndicator, never()).fadeInIndicator()
+    }
+
     private fun startDrag(
         handler: DragToDesktopTransitionHandler,
         task: RunningTaskInfo = createTask(),
+        startTransaction: SurfaceControl.Transaction = mock(),
         finishTransaction: SurfaceControl.Transaction = mock(),
         homeChange: TransitionInfo.Change? = createHomeChange(),
+        transitionRootLeash: SurfaceControl = mock(),
     ): IBinder {
         whenever(dragAnimator.position).thenReturn(PointF())
         // Simulate transition is started and is ready to animate.
@@ -756,8 +796,9 @@
                     type = TRANSIT_DESKTOP_MODE_START_DRAG_TO_DESKTOP,
                     draggedTask = task,
                     homeChange = homeChange,
+                    rootLeash = transitionRootLeash,
                 ),
-            startTransaction = mock(),
+            startTransaction = startTransaction,
             finishTransaction = finishTransaction,
             finishCallback = {},
         )
@@ -778,7 +819,7 @@
                 )
             )
             .thenReturn(token)
-        handler.startDragToDesktopTransition(task, dragAnimator)
+        handler.startDragToDesktopTransition(task, dragAnimator, visualIndicator)
         return token
     }
 
@@ -845,6 +886,7 @@
         type: Int,
         draggedTask: RunningTaskInfo,
         homeChange: TransitionInfo.Change? = createHomeChange(),
+        rootLeash: SurfaceControl = mock(),
     ) =
         TransitionInfo(type, /* flags= */ 0).apply {
             homeChange?.let { addChange(it) }
@@ -861,6 +903,7 @@
                     flags = flags or FLAG_IS_WALLPAPER
                 }
             )
+            addRootLeash(draggedTask.displayId, rootLeash, /* offsetLeft= */ 0, /* offsetTop= */ 0)
         }
 
     private fun createHomeChange() =
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainerTest.kt
index 4c8cb38..c7518d5 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/VisualIndicatorViewContainerTest.kt
@@ -25,6 +25,7 @@
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.view.Display
+import android.view.Display.DEFAULT_DISPLAY
 import android.view.SurfaceControl
 import android.view.SurfaceControlViewHost
 import android.view.View
@@ -49,6 +50,8 @@
 import org.mockito.kotlin.any
 import org.mockito.kotlin.anyOrNull
 import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.never
 import org.mockito.kotlin.spy
 import org.mockito.kotlin.verify
 import org.mockito.kotlin.verifyZeroInteractions
@@ -121,7 +124,7 @@
             DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
         )
         desktopExecutor.flushAll()
-        verify(spyViewContainer).fadeInIndicator(any(), any(), any(), any())
+        verify(spyViewContainer).fadeInIndicatorInternal(any(), any(), any(), any())
     }
 
     @Test
@@ -265,6 +268,35 @@
             )
     }
 
+    @Test
+    fun fadeInIndicator_callsFadeIn() {
+        val spyViewContainer = setupSpyViewContainer()
+
+        spyViewContainer.fadeInIndicator(
+            mock<DisplayLayout>(),
+            DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
+            DEFAULT_DISPLAY,
+        )
+        desktopExecutor.flushAll()
+
+        verify(spyViewContainer).fadeInIndicatorInternal(any(), any(), any(), any())
+    }
+
+    @Test
+    fun fadeInIndicator_alreadyReleased_doesntCallFadeIn() {
+        val spyViewContainer = setupSpyViewContainer()
+        spyViewContainer.releaseVisualIndicator()
+
+        spyViewContainer.fadeInIndicator(
+            mock<DisplayLayout>(),
+            DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR,
+            DEFAULT_DISPLAY,
+        )
+        desktopExecutor.flushAll()
+
+        verify(spyViewContainer, never()).fadeInIndicatorInternal(any(), any(), any(), any())
+    }
+
     private fun setupSpyViewContainer(): VisualIndicatorViewContainer {
         val viewContainer =
             VisualIndicatorViewContainer(
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipAlphaAnimatorTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipAlphaAnimatorTest.java
index 607e6a4..14f9ffc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipAlphaAnimatorTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/animation/PipAlphaAnimatorTest.java
@@ -22,6 +22,7 @@
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
@@ -126,7 +127,7 @@
     }
 
     @Test
-    public void onAnimationStart_setCornerAndShadowRadii() {
+    public void onAnimationStart_fadeInAnimator_setCornerAndShadowRadii() {
         mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
                 mMockFinishTransaction, PipAlphaAnimator.FADE_IN);
         mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory);
@@ -143,7 +144,26 @@
     }
 
     @Test
-    public void onAnimationUpdate_setCornerAndShadowRadii() {
+    public void onAnimationStart_fadeOutAnimator_setCornerNoShadowRadii() {
+        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
+                mMockFinishTransaction, PipAlphaAnimator.FADE_OUT);
+        mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory);
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            mPipAlphaAnimator.start();
+            mPipAlphaAnimator.pause();
+        });
+
+        verify(mMockStartTransaction, atLeastOnce())
+                .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+        verify(mMockStartTransaction, never())
+                .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
+        verify(mMockStartTransaction, atLeastOnce())
+                .setShadowRadius(eq(mTestLeash), eq(0f));
+    }
+
+    @Test
+    public void onAnimationUpdate_fadeInAnimator_setCornerAndShadowRadii() {
         mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
                 mMockFinishTransaction, PipAlphaAnimator.FADE_IN);
         mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory);
@@ -160,7 +180,26 @@
     }
 
     @Test
-    public void onAnimationEnd_setCornerAndShadowRadii() {
+    public void onAnimationUpdate_fadeOutAnimator_setCornerNoShadowRadii() {
+        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
+                mMockFinishTransaction, PipAlphaAnimator.FADE_OUT);
+        mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory);
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            mPipAlphaAnimator.start();
+            mPipAlphaAnimator.pause();
+        });
+
+        verify(mMockAnimateTransaction, atLeastOnce())
+                .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+        verify(mMockAnimateTransaction, never())
+                .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
+        verify(mMockAnimateTransaction, atLeastOnce())
+                .setShadowRadius(eq(mTestLeash), eq(0f));
+    }
+
+    @Test
+    public void onAnimationEnd_fadeInAnimator_setCornerAndShadowRadii() {
         mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
                 mMockFinishTransaction, PipAlphaAnimator.FADE_IN);
         mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory);
@@ -177,6 +216,25 @@
     }
 
     @Test
+    public void onAnimationEnd_fadeOutAnimator_setCornerNoShadowRadii() {
+        mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
+                mMockFinishTransaction, PipAlphaAnimator.FADE_OUT);
+        mPipAlphaAnimator.setSurfaceControlTransactionFactory(mMockFactory);
+
+        InstrumentationRegistry.getInstrumentation().runOnMainSync(() -> {
+            mPipAlphaAnimator.start();
+            mPipAlphaAnimator.end();
+        });
+
+        verify(mMockFinishTransaction, atLeastOnce())
+                .setCornerRadius(eq(mTestLeash), eq(TEST_CORNER_RADIUS));
+        verify(mMockFinishTransaction, never())
+                .setShadowRadius(eq(mTestLeash), eq(TEST_SHADOW_RADIUS));
+        verify(mMockFinishTransaction, atLeastOnce())
+                .setShadowRadius(eq(mTestLeash), eq(0f));
+    }
+
+    @Test
     public void onAnimationEnd_fadeInAnimator_leashVisibleAtEnd() {
         mPipAlphaAnimator = new PipAlphaAnimator(mMockContext, mTestLeash, mMockStartTransaction,
                 mMockFinishTransaction, PipAlphaAnimator.FADE_IN);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipInteractionHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipInteractionHandlerTest.java
new file mode 100644
index 0000000..9c0127e
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipInteractionHandlerTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.pip2.phone;
+
+import static com.android.internal.jank.Cuj.CUJ_PIP_TRANSITION;
+import static com.android.wm.shell.pip2.phone.PipInteractionHandler.INTERACTION_EXIT_PIP;
+import static com.android.wm.shell.pip2.phone.PipInteractionHandler.INTERACTION_EXIT_PIP_TO_SPLIT;
+
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.kotlin.VerificationKt.times;
+
+import android.content.Context;
+import android.os.Handler;
+import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper;
+import android.view.SurfaceControl;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.internal.jank.InteractionJankMonitor;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+/**
+ * Unit test against {@link PipInteractionHandler}.
+ */
+@SmallTest
+@TestableLooper.RunWithLooper
+@RunWith(AndroidTestingRunner.class)
+public class PipInteractionHandlerTest {
+    @Mock private Context mMockContext;
+    @Mock private Handler mMockHandler;
+    @Mock private InteractionJankMonitor mMockInteractionJankMonitor;
+
+    private SurfaceControl mTestLeash;
+
+    private PipInteractionHandler mPipInteractionHandler;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+
+        mPipInteractionHandler = new PipInteractionHandler(mMockContext, mMockHandler,
+                mMockInteractionJankMonitor);
+        mTestLeash = new SurfaceControl.Builder()
+                .setContainerLayer()
+                .setName("PipInteractionHandlerTest")
+                .setCallsite("PipInteractionHandlerTest")
+                .build();
+    }
+
+    @Test
+    public void begin_expand_startsTracking() {
+        mPipInteractionHandler.begin(mTestLeash, INTERACTION_EXIT_PIP);
+
+        verify(mMockInteractionJankMonitor, times(1)).begin(eq(mTestLeash),
+                eq(mMockContext), eq(mMockHandler), eq(CUJ_PIP_TRANSITION),
+                eq(PipInteractionHandler.pipInteractionToString(INTERACTION_EXIT_PIP)));
+    }
+
+    @Test
+    public void begin_expandToSplit_startsTracking() {
+        mPipInteractionHandler.begin(mTestLeash, INTERACTION_EXIT_PIP_TO_SPLIT);
+
+        verify(mMockInteractionJankMonitor, times(1)).begin(eq(mTestLeash),
+                eq(mMockContext), eq(mMockHandler), eq(CUJ_PIP_TRANSITION),
+                eq(PipInteractionHandler.pipInteractionToString(INTERACTION_EXIT_PIP_TO_SPLIT)));
+    }
+
+    @Test
+    public void end_stopsTracking() {
+        mPipInteractionHandler.end();
+
+        verify(mMockInteractionJankMonitor, times(1)).end(CUJ_PIP_TRANSITION);
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTransitionStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTransitionStateTest.java
index fa9b590..66b8ef1 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTransitionStateTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/PipTransitionStateTest.java
@@ -16,12 +16,15 @@
 
 package com.android.wm.shell.pip2.phone;
 
+import static org.mockito.Mockito.when;
+
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.Parcelable;
 import android.testing.AndroidTestingRunner;
 
 import com.android.wm.shell.ShellTestCase;
+import com.android.wm.shell.common.pip.PipDesktopState;
 
 import junit.framework.Assert;
 
@@ -45,9 +48,12 @@
     @Mock
     private Handler mMainHandler;
 
+    @Mock
+    private PipDesktopState mMockPipDesktopState;
+
     @Before
     public void setUp() {
-        mPipTransitionState = new PipTransitionState(mMainHandler);
+        mPipTransitionState = new PipTransitionState(mMainHandler, mMockPipDesktopState);
         mPipTransitionState.setState(PipTransitionState.UNDEFINED);
         mEmptyParcelable = new Bundle();
     }
@@ -128,4 +134,29 @@
         mPipTransitionState.setState(PipTransitionState.SCHEDULED_BOUNDS_CHANGE, extra);
         Assert.assertEquals(PipTransitionState.EXITING_PIP, mPipTransitionState.getState());
     }
+
+    @Test
+    public void testShouldTransitionToState_scheduledBoundsChange_inPip_returnsTrue() {
+        mPipTransitionState.setState(PipTransitionState.ENTERED_PIP);
+
+        Assert.assertTrue(mPipTransitionState.shouldTransitionToState(
+                PipTransitionState.SCHEDULED_BOUNDS_CHANGE));
+    }
+
+    @Test
+    public void testShouldTransitionToState_scheduledBoundsChange_notInPip_returnsFalse() {
+        mPipTransitionState.setState(PipTransitionState.EXITED_PIP);
+
+        Assert.assertFalse(mPipTransitionState.shouldTransitionToState(
+                PipTransitionState.SCHEDULED_BOUNDS_CHANGE));
+    }
+
+    @Test
+    public void testShouldTransitionToState_scheduledBoundsChange_dragToDesktop_returnsFalse() {
+        mPipTransitionState.setState(PipTransitionState.ENTERED_PIP);
+        when(mMockPipDesktopState.isDragToDesktopInProgress()).thenReturn(true);
+
+        Assert.assertFalse(mPipTransitionState.shouldTransitionToState(
+                PipTransitionState.SCHEDULED_BOUNDS_CHANGE));
+    }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandlerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandlerTest.java
index 2a22842..cc66f00 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandlerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip2/phone/transition/PipExpandHandlerTest.java
@@ -23,6 +23,7 @@
 import static com.android.wm.shell.transition.Transitions.TRANSIT_EXIT_PIP_TO_SPLIT;
 
 import static org.junit.Assert.assertNull;
+import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.when;
@@ -48,11 +49,13 @@
 import android.window.WindowContainerTransaction;
 
 import androidx.test.filters.SmallTest;
+import androidx.test.platform.app.InstrumentationRegistry;
 
 import com.android.wm.shell.common.pip.PipBoundsAlgorithm;
 import com.android.wm.shell.common.pip.PipBoundsState;
 import com.android.wm.shell.common.pip.PipDisplayLayoutState;
 import com.android.wm.shell.pip2.animation.PipExpandAnimator;
+import com.android.wm.shell.pip2.phone.PipInteractionHandler;
 import com.android.wm.shell.pip2.phone.PipTransitionState;
 import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.transition.TransitionInfoBuilder;
@@ -61,6 +64,8 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
@@ -79,6 +84,7 @@
     @Mock private PipBoundsAlgorithm mMockPipBoundsAlgorithm;
     @Mock private PipTransitionState mMockPipTransitionState;
     @Mock private PipDisplayLayoutState mMockPipDisplayLayoutState;
+    @Mock private PipInteractionHandler mMockPipInteractionHandler;
     @Mock private SplitScreenController mMockSplitScreenController;
 
     @Mock private IBinder mMockTransitionToken;
@@ -89,6 +95,8 @@
 
     @Mock private PipExpandAnimator mMockPipExpandAnimator;
 
+    @Captor private ArgumentCaptor<Runnable> mAnimatorCallbackArgumentCaptor;
+
     @Surface.Rotation
     private static final int DISPLAY_ROTATION = Surface.ROTATION_0;
 
@@ -108,7 +116,7 @@
 
         mPipExpandHandler = new PipExpandHandler(mMockContext, mMockPipBoundsState,
                 mMockPipBoundsAlgorithm, mMockPipTransitionState, mMockPipDisplayLayoutState,
-                Optional.of(mMockSplitScreenController));
+                mMockPipInteractionHandler, Optional.of(mMockSplitScreenController));
         mPipExpandHandler.setPipExpandAnimatorSupplier((context, leash, startTransaction,
                 finishTransaction, baseBounds, startBounds, endBounds,
                 sourceRectHint, rotation) -> mMockPipExpandAnimator);
@@ -138,6 +146,13 @@
 
         verify(mMockPipExpandAnimator, times(1)).start();
         verify(mMockPipBoundsState, times(1)).saveReentryState(SNAP_FRACTION);
+
+        verify(mMockPipExpandAnimator, times(1))
+                .setAnimationStartCallback(mAnimatorCallbackArgumentCaptor.capture());
+        InstrumentationRegistry.getInstrumentation()
+                .runOnMainSync(mAnimatorCallbackArgumentCaptor.getValue());
+        verify(mMockPipInteractionHandler, times(1)).begin(any(),
+                eq(PipInteractionHandler.INTERACTION_EXIT_PIP));
     }
 
     @Test
@@ -158,6 +173,13 @@
         verify(mMockSplitScreenController, times(1)).finishEnterSplitScreen(eq(mFinishT));
         verify(mMockPipExpandAnimator, times(1)).start();
         verify(mMockPipBoundsState, times(1)).saveReentryState(SNAP_FRACTION);
+
+        verify(mMockPipExpandAnimator, times(1))
+                .setAnimationStartCallback(mAnimatorCallbackArgumentCaptor.capture());
+        InstrumentationRegistry.getInstrumentation()
+                .runOnMainSync(mAnimatorCallbackArgumentCaptor.getValue());
+        verify(mMockPipInteractionHandler, times(1)).begin(any(),
+                eq(PipInteractionHandler.INTERACTION_EXIT_PIP_TO_SPLIT));
     }
 
     private TransitionInfo getExpandFromPipTransitionInfo(@WindowManager.TransitionType int type,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt
index 3f7f21e..95498cb 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/bubbles/DropTargetManagerTest.kt
@@ -65,7 +65,7 @@
         container = FrameLayout(context)
         dragZoneChangedListener = FakeDragZoneChangedListener()
         dropTargetManager =
-            DropTargetManager(context, container, isLayoutRtl = false, dragZoneChangedListener)
+            DropTargetManager(context, container, dragZoneChangedListener)
     }
 
     @Test
@@ -228,6 +228,22 @@
     }
 
     @Test
+    fun onDragEnded_dropTargetNotifies() {
+        dropTargetManager.onDragStarted(
+            DraggedObject.Bubble(BubbleBarLocation.LEFT),
+            listOf(bubbleLeftDragZone, bubbleRightDragZone, dismissDragZone)
+        )
+        InstrumentationRegistry.getInstrumentation().runOnMainSync {
+            dropTargetManager.onDragUpdated(
+                bubbleRightDragZone.bounds.centerX(),
+                bubbleRightDragZone.bounds.centerY()
+            )
+            dropTargetManager.onDragEnded()
+        }
+        assertThat(dragZoneChangedListener.endedDragZone).isEqualTo(bubbleRightDragZone)
+    }
+
+    @Test
     fun startNewDrag_beforeDropTargetRemoved() {
         dropTargetManager.onDragStarted(
             DraggedObject.Bubble(BubbleBarLocation.LEFT),
@@ -330,6 +346,7 @@
         var initialDragZone: DragZone? = null
         var fromDragZone: DragZone? = null
         var toDragZone: DragZone? = null
+        var endedDragZone: DragZone? = null
 
         override fun onInitialDragZoneSet(dragZone: DragZone) {
             initialDragZone = dragZone
@@ -339,5 +356,9 @@
             fromDragZone = from
             toDragZone = to
         }
+
+        override fun onDragEnded(zone: DragZone) {
+            endedDragZone = zone
+        }
     }
 }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
index fb62ba7..edf91fe 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/shared/desktopmode/DesktopModeStatusTest.kt
@@ -234,14 +234,25 @@
         assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse()
     }
 
+    @DisableFlags(Flags.FLAG_ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE)
     @Test
     fun isDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktopOff_returnsFalse() {
         doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported))
-        doReturn(false).whenever(mockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops))
+        doReturn(false).whenever(mockResources)
+            .getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops))
 
         assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isFalse()
     }
 
+    @EnableFlags(Flags.FLAG_ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE)
+    @Test
+    fun isPDDeviceEligibleForDesktopMode_configDEModeOnAndIntDispHostsDesktopOff_returnsTrue() {
+        doReturn(true).whenever(mockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported))
+        doReturn(false).whenever(mockResources).getBoolean(eq(R.bool.config_canInternalDisplayHostDesktops))
+
+        assertThat(DesktopModeStatus.isDeviceEligibleForDesktopMode(mockContext)).isTrue()
+    }
+
     @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE)
     @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_MODE_THROUGH_DEV_OPTION)
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index e5a6a6d..70603fa 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -27,6 +27,7 @@
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_CHILDREN_TASKS_REPARENT;
 import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REORDER;
 
+import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_2_50_50;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_MAIN;
 import static com.android.wm.shell.splitscreen.SplitScreen.STAGE_TYPE_SIDE;
 import static com.android.wm.shell.splitscreen.SplitScreenController.EXIT_REASON_APP_DOES_NOT_SUPPORT_MULTIWINDOW;
@@ -213,7 +214,7 @@
         IBinder transition = mSplitScreenTransitions.startEnterTransition(
                 TRANSIT_OPEN, new WindowContainerTransaction(),
                 new RemoteTransition(testRemote, "Test"), mStageCoordinator,
-                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false);
+                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false, SNAP_TO_2_50_50);
         mMainStage.onTaskAppeared(mMainChild, createMockSurface());
         mSideStage.onTaskAppeared(mSideChild, createMockSurface());
         boolean accepted = mStageCoordinator.startAnimation(transition, info,
@@ -239,7 +240,7 @@
         IBinder transition = mSplitScreenTransitions.startEnterTransition(
                 TRANSIT_OPEN, new WindowContainerTransaction(),
                 new RemoteTransition(testRemote, "Test"), mStageCoordinator,
-                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false);
+                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false, SNAP_TO_2_50_50);
         mMainStage.onTaskAppeared(mMainChild, createMockSurface());
         boolean accepted = mStageCoordinator.startAnimation(transition, info,
                 mock(SurfaceControl.Transaction.class),
@@ -262,7 +263,7 @@
         IBinder transition = mSplitScreenTransitions.startEnterTransition(
                 TRANSIT_OPEN, new WindowContainerTransaction(),
                 new RemoteTransition(testRemote, "Test"), mStageCoordinator,
-                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false);
+                TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false, SNAP_TO_2_50_50);
         mMainStage.onTaskAppeared(mMainChild, createMockSurface());
         mStageCoordinator.startAnimation(transition, info,
                 mock(SurfaceControl.Transaction.class),
@@ -524,7 +525,7 @@
         IBinder enterTransit = mSplitScreenTransitions.startEnterTransition(
                 TRANSIT_OPEN, new WindowContainerTransaction(),
                 new RemoteTransition(new TestRemoteTransition(), "Test"),
-                mStageCoordinator, TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false);
+                mStageCoordinator, TRANSIT_SPLIT_SCREEN_PAIR_OPEN, false, SNAP_TO_2_50_50);
         mMainStage.onTaskAppeared(mMainChild, createMockSurface());
         mSideStage.onTaskAppeared(mSideChild, createMockSurface());
         mStageCoordinator.startAnimation(enterTransit, enterInfo,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index e9c4c31..e246329 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -475,7 +475,7 @@
         mStageCoordinator.startTask(mTaskId, SPLIT_POSITION_TOP_OR_LEFT, null /*options*/,
                 null, SPLIT_INDEX_UNDEFINED);
         verify(mSplitScreenTransitions).startEnterTransition(anyInt(),
-                mWctCaptor.capture(), any(), any(), anyInt(), anyBoolean());
+                mWctCaptor.capture(), any(), any(), anyInt(), anyBoolean(), anyInt());
 
         int windowingMode = mWctCaptor.getValue().getChanges().get(mBinder).getWindowingMode();
         assertEquals(windowingMode, WINDOWING_MODE_UNDEFINED);
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
index e89a122..d69509f 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTests.kt
@@ -115,7 +115,8 @@
                 .spyStatic(DragPositioningCallbackUtility::class.java)
                 .startMocking()
 
-        doReturn(true).`when` { DesktopModeStatus.canInternalDisplayHostDesktops(Mockito.any()) }
+        doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupportedOnDisplay(Mockito.any(),
+            Mockito.any()) }
         doReturn(true).`when` { DesktopModeStatus.canEnterDesktopMode(Mockito.any()) }
         doReturn(false).`when` { DesktopModeStatus.overridesShowAppHandle(Mockito.any()) }
 
@@ -394,7 +395,7 @@
         whenever(DesktopModeStatus.enforceDeviceRestrictions()).thenReturn(true)
 
         val task = createTask(windowingMode = WINDOWING_MODE_FULLSCREEN)
-        doReturn(true).`when` { DesktopModeStatus.canInternalDisplayHostDesktops(any()) }
+        doReturn(true).`when` { DesktopModeStatus.isDesktopModeSupportedOnDisplay(any(), any()) }
         setUpMockDecorationsForTasks(task)
 
         onTaskOpening(task)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
index 81dfaed..a1f40fd 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModelTestsBase.kt
@@ -79,6 +79,7 @@
 import com.android.wm.shell.util.StubTransaction
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeKeyguardChangeListener
 import com.android.wm.shell.windowdecor.DesktopModeWindowDecorViewModel.DesktopModeOnInsetsChangedListener
+import com.android.wm.shell.windowdecor.common.AppHandleAndHeaderVisibilityHelper
 import com.android.wm.shell.windowdecor.common.WindowDecorTaskResourceLoader
 import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHost
 import com.android.wm.shell.windowdecor.common.viewhost.WindowDecorViewHostSupplier
@@ -174,6 +175,7 @@
     internal lateinit var desktopModeOnKeyguardChangedListener: DesktopModeKeyguardChangeListener
     protected lateinit var desktopModeWindowDecorViewModel: DesktopModeWindowDecorViewModel
     protected lateinit var desktopModeCompatPolicy: DesktopModeCompatPolicy
+    protected lateinit var appHandleAndHeaderVisibilityHelper: AppHandleAndHeaderVisibilityHelper
 
     fun setUpCommon() {
         spyContext = spy(mContext)
@@ -185,9 +187,13 @@
         whenever(mockDesktopUserRepositories.current).thenReturn(mockDesktopRepository)
         whenever(mockDisplayController.getDisplayContext(any())).thenReturn(spyContext)
         whenever(mockDisplayController.getDisplay(any())).thenReturn(display)
+        whenever(display.type).thenReturn(Display.TYPE_INTERNAL)
         whenever(mockDesktopUserRepositories.getProfile(anyInt()))
             .thenReturn(mockDesktopRepository)
         desktopModeCompatPolicy = DesktopModeCompatPolicy(spyContext)
+        appHandleAndHeaderVisibilityHelper =
+            AppHandleAndHeaderVisibilityHelper(spyContext, mockDisplayController,
+                desktopModeCompatPolicy)
         desktopModeWindowDecorViewModel = DesktopModeWindowDecorViewModel(
             spyContext,
             testShellExecutor,
@@ -222,6 +228,7 @@
             Optional.of(mockTasksLimiter),
             mockAppHandleEducationController,
             mockAppToWebEducationController,
+            appHandleAndHeaderVisibilityHelper,
             mockCaptionHandleRepository,
             Optional.of(mockActivityOrientationChangeHandler),
             mockTaskPositionerFactory,
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
index 8442056..42eab14 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingDividerWindowManagerTest.kt
@@ -70,6 +70,13 @@
         whenever(context.display).thenReturn(display)
         whenever(display.getRoundedCorner(any())).thenReturn(roundedCorner)
         whenever(roundedCorner.radius).thenReturn(CORNER_RADIUS)
+        whenever(transactionSupplierMock.get()).thenReturn(transaction)
+        whenever(transaction.show(any())).thenReturn(transaction)
+        whenever(transaction.setAlpha(any(), any())).thenReturn(transaction)
+        whenever(transaction.hide(any())).thenReturn(transaction)
+        whenever(transaction.setRelativeLayer(any(), any(), any())).thenReturn(transaction)
+        whenever(transaction.setPosition(any(), any(), any())).thenReturn(transaction)
+        whenever(transaction.remove(any())).thenReturn(transaction)
         desktopTilingWindowManager =
             DesktopTilingDividerWindowManager(
                 config,
@@ -88,12 +95,6 @@
     @Test
     @UiThreadTest
     fun testWindowManager_isInitialisedAndReleased() {
-        whenever(transactionSupplierMock.get()).thenReturn(transaction)
-        whenever(transaction.hide(any())).thenReturn(transaction)
-        whenever(transaction.setRelativeLayer(any(), any(), any())).thenReturn(transaction)
-        whenever(transaction.setPosition(any(), any(), any())).thenReturn(transaction)
-        whenever(transaction.remove(any())).thenReturn(transaction)
-
         desktopTilingWindowManager.generateViewHost(surfaceControl)
 
         // Ensure a surfaceControl transaction runs to show the divider.
@@ -102,18 +103,11 @@
         desktopTilingWindowManager.release()
         verify(transaction, times(1)).hide(any())
         verify(transaction, times(1)).remove(any())
-        verify(transaction, times(1)).apply()
     }
 
     @Test
     @UiThreadTest
     fun testWindowManager_accountsForRoundedCornerDimensions() {
-        whenever(transactionSupplierMock.get()).thenReturn(transaction)
-        whenever(transaction.setRelativeLayer(any(), any(), any())).thenReturn(transaction)
-        whenever(transaction.setRelativeLayer(any(), any(), any())).thenReturn(transaction)
-        whenever(transaction.setPosition(any(), any(), any())).thenReturn(transaction)
-        whenever(transaction.show(any())).thenReturn(transaction)
-
         desktopTilingWindowManager.generateViewHost(surfaceControl)
 
         // Ensure a surfaceControl transaction runs to show the divider.
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt
index 399a51e..bc8faed 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/windowdecor/tiling/DesktopTilingWindowDecorationTest.kt
@@ -114,6 +114,7 @@
     private val split_divider_width = 10
 
     @Captor private lateinit var wctCaptor: ArgumentCaptor<WindowContainerTransaction>
+    @Captor private lateinit var callbackCaptor: ArgumentCaptor<(() -> Unit)>
 
     @Before
     fun setUp() {
@@ -134,7 +135,7 @@
                 userRepositories,
                 desktopModeEventLogger,
                 focusTransitionObserver,
-                mainExecutor
+                mainExecutor,
             )
         whenever(context.createContextAsUser(any(), any())).thenReturn(context)
         whenever(userRepositories.current).thenReturn(desktopRepository)
@@ -158,7 +159,8 @@
             BOUNDS,
         )
 
-        verify(toggleResizeDesktopTaskTransitionHandler).startTransition(capture(wctCaptor), any())
+        verify(toggleResizeDesktopTaskTransitionHandler)
+            .startTransition(capture(wctCaptor), any(), any())
         for (change in wctCaptor.value.changes) {
             val bounds = change.value.configuration.windowConfiguration.bounds
             val leftBounds = getLeftTaskBounds()
@@ -185,7 +187,8 @@
             BOUNDS,
         )
 
-        verify(toggleResizeDesktopTaskTransitionHandler).startTransition(capture(wctCaptor), any())
+        verify(toggleResizeDesktopTaskTransitionHandler)
+            .startTransition(capture(wctCaptor), any(), any())
         for (change in wctCaptor.value.changes) {
             val bounds = change.value.configuration.windowConfiguration.bounds
             val leftBounds = getRightTaskBounds()
@@ -220,7 +223,7 @@
         )
 
         verify(toggleResizeDesktopTaskTransitionHandler, times(1))
-            .startTransition(capture(wctCaptor), any())
+            .startTransition(capture(wctCaptor), any(), any())
         verify(returnToDragStartAnimator, times(1)).start(any(), any(), any(), any(), anyOrNull())
         for (change in wctCaptor.value.changes) {
             val bounds = change.value.configuration.windowConfiguration.bounds
@@ -308,9 +311,13 @@
             DesktopTasksController.SnapPosition.LEFT,
             BOUNDS,
         )
+        verify(toggleResizeDesktopTaskTransitionHandler, times(2))
+            .startTransition(capture(wctCaptor), any(), capture(callbackCaptor))
+        (callbackCaptor.value).invoke()
         task1.isFocused = true
 
-        assertThat(tilingDecoration.moveTiledPairToFront(task1.taskId, isFocusedOnDisplay = true)).isTrue()
+        assertThat(tilingDecoration.moveTiledPairToFront(task1.taskId, isFocusedOnDisplay = true))
+            .isTrue()
         verify(transitions, times(1)).startTransition(eq(TRANSIT_TO_FRONT), any(), eq(null))
     }
 
@@ -341,6 +348,9 @@
         )
         task1.isFocused = true
         task3.isFocused = true
+        verify(toggleResizeDesktopTaskTransitionHandler, times(2))
+            .startTransition(capture(wctCaptor), any(), capture(callbackCaptor))
+        (callbackCaptor.value).invoke()
 
         assertThat(tilingDecoration.moveTiledPairToFront(task3.taskId, true)).isFalse()
         assertThat(tilingDecoration.moveTiledPairToFront(task1.taskId, true)).isTrue()
@@ -372,9 +382,14 @@
             DesktopTasksController.SnapPosition.LEFT,
             BOUNDS,
         )
+        verify(toggleResizeDesktopTaskTransitionHandler, times(2))
+            .startTransition(capture(wctCaptor), any(), capture(callbackCaptor))
+        (callbackCaptor.value).invoke()
 
-        assertThat(tilingDecoration.moveTiledPairToFront(task3.taskId, isFocusedOnDisplay = true)).isFalse()
-        assertThat(tilingDecoration.moveTiledPairToFront(task1.taskId, isFocusedOnDisplay = true)).isTrue()
+        assertThat(tilingDecoration.moveTiledPairToFront(task3.taskId, isFocusedOnDisplay = true))
+            .isFalse()
+        assertThat(tilingDecoration.moveTiledPairToFront(task1.taskId, isFocusedOnDisplay = true))
+            .isTrue()
         verify(transitions, times(1)).startTransition(eq(TRANSIT_TO_FRONT), any(), eq(null))
     }
 
@@ -482,27 +497,29 @@
         tilingDecoration.onDividerHandleDragStart(motionEvent)
         // Log start event for task1 and task2, but the tasks are the same in
         // this test, so we verify the same log twice.
-        verify(desktopModeEventLogger, times(2)).logTaskResizingStarted(
-            ResizeTrigger.TILING_DIVIDER,
-            DesktopModeEventLogger.Companion.InputMethod.UNKNOWN_INPUT_METHOD,
-            task1,
-            BOUNDS.width() / 2,
-            BOUNDS.height(),
-            displayController,
-        )
+        verify(desktopModeEventLogger, times(2))
+            .logTaskResizingStarted(
+                ResizeTrigger.TILING_DIVIDER,
+                DesktopModeEventLogger.Companion.InputMethod.UNKNOWN_INPUT_METHOD,
+                task1,
+                BOUNDS.width() / 2,
+                BOUNDS.height(),
+                displayController,
+            )
 
         tilingDecoration.onDividerHandleMoved(BOUNDS, transaction)
         tilingDecoration.onDividerHandleDragEnd(BOUNDS, transaction, motionEvent)
         // Log end event for task1 and task2, but the tasks are the same in
         // this test, so we verify the same log twice.
-        verify(desktopModeEventLogger, times(2)).logTaskResizingEnded(
-            ResizeTrigger.TILING_DIVIDER,
-            DesktopModeEventLogger.Companion.InputMethod.UNKNOWN_INPUT_METHOD,
-            task1,
-            BOUNDS.width(),
-            BOUNDS.height(),
-            displayController,
-        )
+        verify(desktopModeEventLogger, times(2))
+            .logTaskResizingEnded(
+                ResizeTrigger.TILING_DIVIDER,
+                DesktopModeEventLogger.Companion.InputMethod.UNKNOWN_INPUT_METHOD,
+                task1,
+                BOUNDS.width(),
+                BOUNDS.height(),
+                displayController,
+            )
     }
 
     @Test
diff --git a/libs/hwui/apex/LayoutlibLoader.cpp b/libs/hwui/apex/LayoutlibLoader.cpp
index 56191c0..87a43fc 100644
--- a/libs/hwui/apex/LayoutlibLoader.cpp
+++ b/libs/hwui/apex/LayoutlibLoader.cpp
@@ -29,6 +29,7 @@
 extern int register_android_graphics_Bitmap(JNIEnv*);
 extern int register_android_graphics_BitmapFactory(JNIEnv*);
 extern int register_android_graphics_BitmapRegionDecoder(JNIEnv*);
+extern int register_android_graphics_RuntimeXfermode(JNIEnv*);
 extern int register_android_graphics_ByteBufferStreamAdaptor(JNIEnv* env);
 extern int register_android_graphics_Camera(JNIEnv* env);
 extern int register_android_graphics_CreateJavaOutputStreamAdaptor(JNIEnv* env);
@@ -131,6 +132,7 @@
         {"android.graphics.RenderNode", REG_JNI(register_android_view_RenderNode)},
         {"android.graphics.Shader", REG_JNI(register_android_graphics_Shader)},
         {"android.graphics.RenderEffect", REG_JNI(register_android_graphics_RenderEffect)},
+        {"android.graphics.RuntimeXfermode", REG_JNI(register_android_graphics_RuntimeXfermode)},
         {"android.graphics.Typeface", REG_JNI(register_android_graphics_Typeface)},
         {"android.graphics.YuvImage", REG_JNI(register_android_graphics_YuvImage)},
         {"android.graphics.animation.NativeInterpolatorFactory",
diff --git a/media/java/android/media/MediaRoute2ProviderService.java b/media/java/android/media/MediaRoute2ProviderService.java
index 4ae8daa..6a33b37 100644
--- a/media/java/android/media/MediaRoute2ProviderService.java
+++ b/media/java/android/media/MediaRoute2ProviderService.java
@@ -759,12 +759,29 @@
 
     /**
      * Updates routes of the provider and notifies the system media router service.
+     *
+     * @throws IllegalArgumentException If {@code routes} contains a route that {@link
+     *     MediaRoute2Info#getSupportedRoutingTypes() supports} both system media routing and remote
+     *     routing but doesn't contain any {@link MediaRoute2Info#getDeduplicationIds()
+     *     deduplication ids}.
      */
     public final void notifyRoutes(@NonNull Collection<MediaRoute2Info> routes) {
         requireNonNull(routes, "routes must not be null");
         List<MediaRoute2Info> sanitizedRoutes = new ArrayList<>(routes.size());
 
         for (MediaRoute2Info route : routes) {
+            if (Flags.enableMirroringInMediaRouter2()
+                    && route.supportsRemoteRouting()
+                    && route.supportsSystemMediaRouting()
+                    && route.getDeduplicationIds().isEmpty()) {
+                String errorMessage =
+                        TextUtils.formatSimple(
+                                "Route with id='%s' name='%s' supports both system media and remote"
+                                    + " type routing, but doesn't contain a deduplication id, which"
+                                    + " it needs. You can add the route id as a deduplication id.",
+                                route.getOriginalId(), route.getName());
+                throw new IllegalArgumentException(errorMessage);
+            }
             if (route.isSystemRouteType()) {
                 Log.w(
                         TAG,
diff --git a/native/android/surface_control.cpp b/native/android/surface_control.cpp
index 2759724..f6dc41e 100644
--- a/native/android/surface_control.cpp
+++ b/native/android/surface_control.cpp
@@ -89,7 +89,7 @@
     CHECK_NOT_NULL(window);
     CHECK_NOT_NULL(debug_name);
 
-    sp<SurfaceComposerClient> client = new SurfaceComposerClient();
+    sp<SurfaceComposerClient> client = sp<SurfaceComposerClient>::make();
     if (client->initCheck() != NO_ERROR) {
         return nullptr;
     }
diff --git a/native/android/thermal.cpp b/native/android/thermal.cpp
index cefcaf7..93e6ed8 100644
--- a/native/android/thermal.cpp
+++ b/native/android/thermal.cpp
@@ -139,7 +139,12 @@
         mStatusListeners.clear();
         if (mServiceStatusListener != nullptr) {
             bool success = false;
-            mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
+            auto ret =
+                    mThermalSvc->unregisterThermalStatusListener(mServiceStatusListener, &success);
+            if (!success || !ret.isOk()) {
+                ALOGE("Failed in unregisterThermalStatusListener when AThermalManager is being "
+                      "destroyed %d", success);
+            }
             mServiceStatusListener = nullptr;
         }
     }
@@ -148,7 +153,12 @@
         mHeadroomListeners.clear();
         if (mServiceHeadroomListener != nullptr) {
             bool success = false;
-            mThermalSvc->unregisterThermalHeadroomListener(mServiceHeadroomListener, &success);
+            auto ret = mThermalSvc->unregisterThermalHeadroomListener(mServiceHeadroomListener,
+                                                                      &success);
+            if (!success || !ret.isOk()) {
+                ALOGE("Failed in unregisterThermalHeadroomListener when AThermalManager is being "
+                      "destroyed %d", success);
+            }
             mServiceHeadroomListener = nullptr;
         }
     }
diff --git a/packages/CompanionDeviceManager/res/values-af/strings.xml b/packages/CompanionDeviceManager/res/values-af/strings.xml
index b802d0f..8e5a2b7 100644
--- a/packages/CompanionDeviceManager/res/values-af/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-af/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Moenie toelaat nie"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Kanselleer"</string>
     <string name="consent_back" msgid="2560683030046918882">"Terug"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Rollees met die lys af"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Afwaartse pyl"</string>
     <string name="permission_expand" msgid="893185038020887411">"Vou <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> uit"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Vou <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> in"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Gee programme op &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; dieselfde toestemmings as op &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-am/strings.xml b/packages/CompanionDeviceManager/res/values-am/strings.xml
index d4d0b07..40472d2 100644
--- a/packages/CompanionDeviceManager/res/values-am/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-am/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"አትፍቀድ"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ይቅር"</string>
     <string name="consent_back" msgid="2560683030046918882">"ተመለስ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"በዝርዝሩ ላይ ወደታች ያሸብልሉ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"የአውርድ ቀስት"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ን ዘርጋ"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ን ሰብስብ"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"በ&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ላይ ላሉ መተግበሪያዎች በ&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ላይ ካሉት ጋር ተመሳሳይ ፈቃዶች ይሰጣቸው?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ar/strings.xml b/packages/CompanionDeviceManager/res/values-ar/strings.xml
index f4e1721..40c7dd1 100644
--- a/packages/CompanionDeviceManager/res/values-ar/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ar/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"عدم السماح"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"إلغاء"</string>
     <string name="consent_back" msgid="2560683030046918882">"رجوع"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"الانتقال لأسفل القائمة"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"سهم متّجه للأسفل"</string>
     <string name="permission_expand" msgid="893185038020887411">"توسيع <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"تصغير <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"‏هل تريد منح التطبيقات على &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; نفس الأذونات على &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;؟"</string>
diff --git a/packages/CompanionDeviceManager/res/values-as/strings.xml b/packages/CompanionDeviceManager/res/values-as/strings.xml
index 322d422..1f3ee73 100644
--- a/packages/CompanionDeviceManager/res/values-as/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-as/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"অনুমতি নিদিব"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"বাতিল কৰক"</string>
     <string name="consent_back" msgid="2560683030046918882">"উভতি যাওক"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"সূচীখনত তললৈ স্ক্ৰ’ল কৰক"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"তলমুৱা কাঁড়"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> বিস্তাৰ কৰক"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> সংকোচন কৰক"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"এপ্‌সমূহক &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ত দিয়াৰ দৰে &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;তো একে অনুমতি প্ৰদান কৰিবনে?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-az/strings.xml b/packages/CompanionDeviceManager/res/values-az/strings.xml
index 9f3ab2bd..aa4788a 100644
--- a/packages/CompanionDeviceManager/res/values-az/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-az/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"İcazə verməyin"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Ləğv edin"</string>
     <string name="consent_back" msgid="2560683030046918882">"Geriyə"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Siyahını aşağı sürüşdürün"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Aşağı ox"</string>
     <string name="permission_expand" msgid="893185038020887411">"Genişləndirin: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Yığcamlaşdırın: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; cihazındakı tətbiqlərə &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazındakılarla eyni icazələr verilsin?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
index d28b9b2..3dcb585 100644
--- a/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-b+sr+Latn/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ne dozvoli"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Otkaži"</string>
     <string name="consent_back" msgid="2560683030046918882">"Nazad"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Skrolujte nadole na listi"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Strelica nadole"</string>
     <string name="permission_expand" msgid="893185038020887411">"Proširi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Skupi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Aplikcijama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; dajete sve dozvole kao na uređaju &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-be/strings.xml b/packages/CompanionDeviceManager/res/values-be/strings.xml
index 14878c1..8ef80d34 100644
--- a/packages/CompanionDeviceManager/res/values-be/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-be/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Не дазваляць"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Скасаваць"</string>
     <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Прагартаць спіс уніз"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Стрэлка ўніз"</string>
     <string name="permission_expand" msgid="893185038020887411">"Разгарнуць <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Згарнуць <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Даць праграмам на прыладзе &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; такія самыя дазволы, што і на прыладзе &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bg/strings.xml b/packages/CompanionDeviceManager/res/values-bg/strings.xml
index 6e5b323..ebc2cf5 100644
--- a/packages/CompanionDeviceManager/res/values-bg/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bg/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Забраняване"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Отказ"</string>
     <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Превъртете списъка надолу"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Стрелка за надолу"</string>
     <string name="permission_expand" msgid="893185038020887411">"Разгъване на <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Свиване на <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Искате ли да дадете на приложенията на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; същите разрешения както на &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bn/strings.xml b/packages/CompanionDeviceManager/res/values-bn/strings.xml
index 214dc71..f5cf720 100644
--- a/packages/CompanionDeviceManager/res/values-bn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bn/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"অনুমতি দেবেন না"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"বাতিল করুন"</string>
     <string name="consent_back" msgid="2560683030046918882">"ফিরুন"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"তালিকা নিচের দিকে স্ক্রল করুন"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"নিম্নমুখী তীরচিহ্ন"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> বড় করুন"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> আড়াল করুন"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-এ যে অনুমতি দেওয়া আছে &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;-এও সেই একই অনুমতি দিতে চান?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-bs/strings.xml b/packages/CompanionDeviceManager/res/values-bs/strings.xml
index b23f600..a87ea18 100644
--- a/packages/CompanionDeviceManager/res/values-bs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-bs/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nemoj dozvoliti"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Otkaži"</string>
     <string name="consent_back" msgid="2560683030046918882">"Nazad"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Klizanje nadolje na listi"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Strelica nadolje"</string>
     <string name="permission_expand" msgid="893185038020887411">"Proširivanje stavke <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Sužavanje stavke <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dati aplikacijama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ista odobrenja kao na uređaju &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ca/strings.xml b/packages/CompanionDeviceManager/res/values-ca/strings.xml
index 21f3871..7ec2b8b 100644
--- a/packages/CompanionDeviceManager/res/values-ca/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ca/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"No permetis"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancel·la"</string>
     <string name="consent_back" msgid="2560683030046918882">"Enrere"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Desplaça la llista cap avall"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Fletxa avall"</string>
     <string name="permission_expand" msgid="893185038020887411">"Desplega <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Replega <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vols concedir a les aplicacions del dispositiu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; els mateixos permisos que tenen a &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-cs/strings.xml b/packages/CompanionDeviceManager/res/values-cs/strings.xml
index cd89130..a1ea39b 100644
--- a/packages/CompanionDeviceManager/res/values-cs/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-cs/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nepovolovat"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Zrušit"</string>
     <string name="consent_back" msgid="2560683030046918882">"Zpět"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Přejít v seznamu dolů"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Šipka dolů"</string>
     <string name="permission_expand" msgid="893185038020887411">"Rozbalit sekci <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Sbalit sekci <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Udělit aplikacím v zařízení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; stejné oprávnění, jako mají v zařízení &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-da/strings.xml b/packages/CompanionDeviceManager/res/values-da/strings.xml
index 6dc34e7..97e6fe56 100644
--- a/packages/CompanionDeviceManager/res/values-da/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-da/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Tillad ikke"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Annuller"</string>
     <string name="consent_back" msgid="2560683030046918882">"Tilbage"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Rul ned på listen"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Pil ned"</string>
     <string name="permission_expand" msgid="893185038020887411">"Udvid <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Skjul <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vil du give apps på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; de samme tilladelser som på &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-de/strings.xml b/packages/CompanionDeviceManager/res/values-de/strings.xml
index 4dc2929..fc0231f 100644
--- a/packages/CompanionDeviceManager/res/values-de/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-de/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nicht zulassen"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Abbrechen"</string>
     <string name="consent_back" msgid="2560683030046918882">"Zurück"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"In der Liste nach unten scrollen"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Abwärtspfeil"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> maximieren"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> minimieren"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Apps auf &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; die gleichen Berechtigungen geben wie auf &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-el/strings.xml b/packages/CompanionDeviceManager/res/values-el/strings.xml
index 1dc00dc..9ede684 100644
--- a/packages/CompanionDeviceManager/res/values-el/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-el/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Να μην επιτρέπεται"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Ακύρωση"</string>
     <string name="consent_back" msgid="2560683030046918882">"Πίσω"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Κύλιση προς τα κάτω στη λίστα"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Βέλος που δείχνει προς τα κάτω"</string>
     <string name="permission_expand" msgid="893185038020887411">"Ανάπτυξη <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Σύμπτυξη <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Παραχώρηση των ίδιων αδειών στις εφαρμογές στη συσκευή &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; όπως στη συσκευή &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;;"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
index bbd81bf..68c74e0 100644
--- a/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rAU/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancel"</string>
     <string name="consent_back" msgid="2560683030046918882">"Back"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Scroll down the list"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Downward arrow"</string>
     <string name="permission_expand" msgid="893185038020887411">"Expand <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Collapse <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the same permissions as on &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
index 8d73380..15d3042 100644
--- a/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rCA/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancel"</string>
     <string name="consent_back" msgid="2560683030046918882">"Back"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Scroll down the list"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Downward arrow"</string>
     <string name="permission_expand" msgid="893185038020887411">"Expand <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Collapse <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the same permissions as on &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
index bbd81bf..68c74e0 100644
--- a/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rGB/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancel"</string>
     <string name="consent_back" msgid="2560683030046918882">"Back"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Scroll down the list"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Downward arrow"</string>
     <string name="permission_expand" msgid="893185038020887411">"Expand <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Collapse <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the same permissions as on &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
index bbd81bf..68c74e0 100644
--- a/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-en-rIN/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Don\'t allow"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancel"</string>
     <string name="consent_back" msgid="2560683030046918882">"Back"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Scroll down the list"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Downward arrow"</string>
     <string name="permission_expand" msgid="893185038020887411">"Expand <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Collapse <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Give apps on &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the same permissions as on &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
index 50f7654..edcc4bd 100644
--- a/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es-rUS/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
     <string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Bajar por la lista"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Flecha hacia abajo"</string>
     <string name="permission_expand" msgid="893185038020887411">"Expandir <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Contraer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"¿Dar a las apps de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; los mismos permisos que tienen en &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-es/strings.xml b/packages/CompanionDeviceManager/res/values-es/strings.xml
index f8e2c74..d74b4f8 100644
--- a/packages/CompanionDeviceManager/res/values-es/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-es/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"No permitir"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
     <string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Desplazarse hacia abajo por la lista"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Flecha hacia abajo"</string>
     <string name="permission_expand" msgid="893185038020887411">"Desplegar <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Contraer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"¿Dar a las aplicaciones de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; los mismos permisos que &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-et/strings.xml b/packages/CompanionDeviceManager/res/values-et/strings.xml
index 0f390e1..3c83758 100644
--- a/packages/CompanionDeviceManager/res/values-et/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-et/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ära luba"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Tühista"</string>
     <string name="consent_back" msgid="2560683030046918882">"Tagasi"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Kerige loendis alla"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Allapoole suunatud nool"</string>
     <string name="permission_expand" msgid="893185038020887411">"Laienda: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Ahenda: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Kas anda rakendustele seadmes &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; samad load, mis seadmes &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fa/strings.xml b/packages/CompanionDeviceManager/res/values-fa/strings.xml
index fb36c46..cf4fe25 100644
--- a/packages/CompanionDeviceManager/res/values-fa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fa/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"اجازه ندادن"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"لغو"</string>
     <string name="consent_back" msgid="2560683030046918882">"برگشتن"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"پیمایش به‌پایین فهرست"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"جهت‌نمای پایین"</string>
     <string name="permission_expand" msgid="893185038020887411">"ازهم بازکردن <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"جمع کردن <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"‏به برنامه‌های موجود در &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; همان اجازه‌های &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; داده شود؟"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fi/strings.xml b/packages/CompanionDeviceManager/res/values-fi/strings.xml
index ff6cae1..4be6a5a 100644
--- a/packages/CompanionDeviceManager/res/values-fi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fi/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Älä salli"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Peruuta"</string>
     <string name="consent_back" msgid="2560683030046918882">"Takaisin"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Vieritä listaa alaspäin"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Alanuoli"</string>
     <string name="permission_expand" msgid="893185038020887411">"Laajenna <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Tiivistä <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Anna laitteen &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; sovelluksille samat luvat kuin laitteella &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
index 4d7de76..70beafb 100644
--- a/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr-rCA/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Annuler"</string>
     <string name="consent_back" msgid="2560683030046918882">"Retour"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Faire défiler la liste en bas"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Flèche vers le bas"</string>
     <string name="permission_expand" msgid="893185038020887411">"Développer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Réduire <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Accorder aux applis sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; les autorisations déjà accordées sur &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-fr/strings.xml b/packages/CompanionDeviceManager/res/values-fr/strings.xml
index d4c12fb..394efae 100644
--- a/packages/CompanionDeviceManager/res/values-fr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-fr/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ne pas autoriser"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Annuler"</string>
     <string name="consent_back" msgid="2560683030046918882">"Retour"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Faire défiler la liste vers le bas"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Flèche vers le bas"</string>
     <string name="permission_expand" msgid="893185038020887411">"Développer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Réduire <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Accorder les mêmes autorisations aux applis sur &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; que sur &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gl/strings.xml b/packages/CompanionDeviceManager/res/values-gl/strings.xml
index 999ab97..ce23be8 100644
--- a/packages/CompanionDeviceManager/res/values-gl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gl/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Non permitir"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
     <string name="consent_back" msgid="2560683030046918882">"Atrás"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Desprazarse abaixo na lista"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Frecha cara abaixo"</string>
     <string name="permission_expand" msgid="893185038020887411">"Despregar <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Contraer <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Queres darlles ás aplicacións de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; os mesmos permisos que teñen as de &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-gu/strings.xml b/packages/CompanionDeviceManager/res/values-gu/strings.xml
index 51d07c9..7956ba6 100644
--- a/packages/CompanionDeviceManager/res/values-gu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-gu/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"મંજૂરી આપશો નહીં"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"રદ કરો"</string>
     <string name="consent_back" msgid="2560683030046918882">"પાછળ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"સૂચિ પર નીચે સ્ક્રોલ કરો"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"નીચેની તરફ ઍરો"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ને મોટું કરો"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>ને નાનું કરો"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; પરની ઍપને &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; પર છે તે જ પરવાનગીઓ આપીએ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hi/strings.xml b/packages/CompanionDeviceManager/res/values-hi/strings.xml
index f7086c6..f204e94 100644
--- a/packages/CompanionDeviceManager/res/values-hi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hi/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"अनुमति न दें"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"रद्द करें"</string>
     <string name="consent_back" msgid="2560683030046918882">"वापस जाएं"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"सूची को नीचे की ओर स्क्रोल करें"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"डाउनवर्ड ऐरो"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> को बड़ा करें"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> को छोटा करें"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"क्या &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; पर ऐप्लिकेशन को वही अनुमतियां देनी हैं जो &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; पर दी हैं?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hr/strings.xml b/packages/CompanionDeviceManager/res/values-hr/strings.xml
index 04872e5..326564e 100644
--- a/packages/CompanionDeviceManager/res/values-hr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hr/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nemoj dopustiti"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Odustani"</string>
     <string name="consent_back" msgid="2560683030046918882">"Natrag"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Pomicanje po popisu"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Strelica prema dolje"</string>
     <string name="permission_expand" msgid="893185038020887411">"Proširi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Sažmi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dati jednaka dopuštenja aplikacijama na uređaju &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; kao i na uređaju &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hu/strings.xml b/packages/CompanionDeviceManager/res/values-hu/strings.xml
index 5d3b313..42702ca 100644
--- a/packages/CompanionDeviceManager/res/values-hu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hu/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Tiltás"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Mégse"</string>
     <string name="consent_back" msgid="2560683030046918882">"Vissza"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Görgetés a listában lefelé"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Lefelé mutató nyíl"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> kibontása"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> összecsukása"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Ugyanolyan engedélyeket ad a(z) &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; eszközön található alkalmazásoknak, mint a(z) &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; eszköz esetén?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-hy/strings.xml b/packages/CompanionDeviceManager/res/values-hy/strings.xml
index e7c7139..cbf1d8d 100644
--- a/packages/CompanionDeviceManager/res/values-hy/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-hy/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Չթույլատրել"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Չեղարկել"</string>
     <string name="consent_back" msgid="2560683030046918882">"Հետ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Թերթեք ներքև"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Ներքև սլաք"</string>
     <string name="permission_expand" msgid="893185038020887411">"Ծավալել «<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>» բաժինը"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Ծալել «<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>» բաժինը"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;-ում հավելվածներին տա՞լ նույն թույլտվությունները, ինչ &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ում"</string>
diff --git a/packages/CompanionDeviceManager/res/values-in/strings.xml b/packages/CompanionDeviceManager/res/values-in/strings.xml
index f582205..fe3406e 100644
--- a/packages/CompanionDeviceManager/res/values-in/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-in/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Jangan izinkan"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Batal"</string>
     <string name="consent_back" msgid="2560683030046918882">"Kembali"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Scroll daftar ke bawah"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Panah bawah"</string>
     <string name="permission_expand" msgid="893185038020887411">"Luaskan <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Ciutkan <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Berikan aplikasi di &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; izin yang sama seperti di &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-is/strings.xml b/packages/CompanionDeviceManager/res/values-is/strings.xml
index b66133c..9e366d6 100644
--- a/packages/CompanionDeviceManager/res/values-is/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-is/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ekki leyfa"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Hætta við"</string>
     <string name="consent_back" msgid="2560683030046918882">"Til baka"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Fletta niður listann"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Ör niður"</string>
     <string name="permission_expand" msgid="893185038020887411">"Stækka <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Minnka <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Veita forritum í &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; sömu heimildir og í &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-it/strings.xml b/packages/CompanionDeviceManager/res/values-it/strings.xml
index 3496718..b744542 100644
--- a/packages/CompanionDeviceManager/res/values-it/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-it/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Non consentire"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Annulla"</string>
     <string name="consent_back" msgid="2560683030046918882">"Indietro"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Scorri l\'elenco verso il basso"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Freccia verso il basso"</string>
     <string name="permission_expand" msgid="893185038020887411">"Espandi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Comprimi <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vuoi dare alle app su &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; le stesse autorizzazioni che hai dato su &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-iw/strings.xml b/packages/CompanionDeviceManager/res/values-iw/strings.xml
index 626ae7a..1e299b7 100644
--- a/packages/CompanionDeviceManager/res/values-iw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-iw/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"אין אישור"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ביטול"</string>
     <string name="consent_back" msgid="2560683030046918882">"חזרה"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"גלילה למטה ברשימה"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"חץ למטה"</string>
     <string name="permission_expand" msgid="893185038020887411">"הרחבה של <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"כיווץ של <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"‏האם לתת לאפליקציות ב-‎&lt;strong&gt;‎‏<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>‏‎&lt;/strong&gt;‎‏ את אותן הרשאות כמו ב-‏‎&lt;strong&gt;‎‏<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>‏‎&lt;/strong&gt;‎‏?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ja/strings.xml b/packages/CompanionDeviceManager/res/values-ja/strings.xml
index a8dc756..664d536 100644
--- a/packages/CompanionDeviceManager/res/values-ja/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ja/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"許可しない"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"キャンセル"</string>
     <string name="consent_back" msgid="2560683030046918882">"戻る"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"リストを下にスクロール"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"下矢印"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>を開く"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>を閉じる"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; のアプリに &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; の場合と同じ権限を付与しますか?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ka/strings.xml b/packages/CompanionDeviceManager/res/values-ka/strings.xml
index 97f3087..d0214ae 100644
--- a/packages/CompanionDeviceManager/res/values-ka/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ka/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"არ დაიშვას"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"გაუქმება"</string>
     <string name="consent_back" msgid="2560683030046918882">"უკან"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"გადაადგილება სიის ქვემოთ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ქვემოთ მიმართული ისარი"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>-ის გაფართოება"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>-ის ჩაკეცვა"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"გსურთ აპებს &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;-ზე იგივე ნებართვები მიანიჭოთ, როგორიც აქვს &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;-ზე?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kk/strings.xml b/packages/CompanionDeviceManager/res/values-kk/strings.xml
index 4d77c6c..e794415 100644
--- a/packages/CompanionDeviceManager/res/values-kk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kk/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Рұқсат бермеу"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Бас тарту"</string>
     <string name="consent_back" msgid="2560683030046918882">"Артқа"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Тізім соңына дейін айналдыру"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Төмен бағытталған перне"</string>
     <string name="permission_expand" msgid="893185038020887411">"\"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\" панелін жаю"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"\"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\" панелін жию"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; құрылғысындағы қолданбаларға &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; құрылғысындағыдай рұқсаттар берілсін бе?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-km/strings.xml b/packages/CompanionDeviceManager/res/values-km/strings.xml
index 9047b05..ddd4144 100644
--- a/packages/CompanionDeviceManager/res/values-km/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-km/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"មិនអនុញ្ញាត"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"បោះបង់"</string>
     <string name="consent_back" msgid="2560683030046918882">"ថយក្រោយ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"រំកិលបញ្ជីចុះក្រោម"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ព្រួញ​ចុះ​ក្រោម"</string>
     <string name="permission_expand" msgid="893185038020887411">"ពង្រីក <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"បង្រួម <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ផ្ដល់​ការអនុញ្ញាតឱ្យ​កម្មវិធីនៅលើ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ដូចនៅលើ &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ឬ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-kn/strings.xml b/packages/CompanionDeviceManager/res/values-kn/strings.xml
index 751ac1f..a957f48 100644
--- a/packages/CompanionDeviceManager/res/values-kn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-kn/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ಅನುಮತಿಸಬೇಡಿ"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ರದ್ದುಮಾಡಿ"</string>
     <string name="consent_back" msgid="2560683030046918882">"ಹಿಂದೆ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"ಪಟ್ಟಿಯನ್ನು ಕೆಳಗೆ ಸ್ಕ್ರಾಲ್ ಮಾಡಿ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ಕೆಳಮುಖ ಬಾಣ"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ಅನ್ನು ವಿಸ್ತರಿಸಿ"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ಅನ್ನು ಕುಗ್ಗಿಸಿ"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;/strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ನಲ್ಲಿನ ಅನುಮತಿಗಳನ್ನೇ &lt;/strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ನಲ್ಲಿನ ಆ್ಯಪ್‌ಗಳಿಗೆ ನೀಡಬೇಕೆ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ko/strings.xml b/packages/CompanionDeviceManager/res/values-ko/strings.xml
index a7a5dc1..d7d489af 100644
--- a/packages/CompanionDeviceManager/res/values-ko/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ko/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"허용 안함"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"취소"</string>
     <string name="consent_back" msgid="2560683030046918882">"뒤로"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"목록을 아래로 스크롤"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"아래쪽 화살표"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> 펼치기"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> 접기"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;에 설치된 앱에 &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;에 설치된 앱과 동일한 권한을 부여하시겠습니까?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ky/strings.xml b/packages/CompanionDeviceManager/res/values-ky/strings.xml
index 991fc9f..3f8c58a 100644
--- a/packages/CompanionDeviceManager/res/values-ky/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ky/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Уруксат берилбесин"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Жок"</string>
     <string name="consent_back" msgid="2560683030046918882">"Артка"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Тизменин ылдый жагына сыдыруу"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Ылдый караган жебе"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> жайып көрсөтүү"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> жыйыштыруу"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; түзмөгүнө да &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; түзмөгүнө берилген уруксаттар берилсинби?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lo/strings.xml b/packages/CompanionDeviceManager/res/values-lo/strings.xml
index 91399b6..457efdb 100644
--- a/packages/CompanionDeviceManager/res/values-lo/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lo/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ບໍ່ອະນຸຍາດ"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ຍົກເລີກ"</string>
     <string name="consent_back" msgid="2560683030046918882">"ກັບຄືນ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"ເລື່ອນລາຍຊື່ລົງ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ລູກສອນຊີ້ລົງ"</string>
     <string name="permission_expand" msgid="893185038020887411">"ຂະຫຍາຍ <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"ຫຍໍ້ <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ລົງ"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ໃຫ້ການອະນຸຍາດແອັບຢູ່ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ເປັນການອະນຸຍາດດຽວກັນກັບຢູ່ &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ບໍ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lt/strings.xml b/packages/CompanionDeviceManager/res/values-lt/strings.xml
index a3ac47b..09183bb 100644
--- a/packages/CompanionDeviceManager/res/values-lt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lt/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Neleisti"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Atšaukti"</string>
     <string name="consent_back" msgid="2560683030046918882">"Atgal"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Slinkti sąrašu žemyn"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Rodyklė žemyn"</string>
     <string name="permission_expand" msgid="893185038020887411">"Išskleisti „<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>“"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Sutraukti „<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>“"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Suteikti &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; esančioms programoms tuos pačius leidimus kaip &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; esančioms programoms?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-lv/strings.xml b/packages/CompanionDeviceManager/res/values-lv/strings.xml
index 35c7481..01c9ed5 100644
--- a/packages/CompanionDeviceManager/res/values-lv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-lv/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Neatļaut"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Atcelt"</string>
     <string name="consent_back" msgid="2560683030046918882">"Atpakaļ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Ritināt sarakstu lejup"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Lejupvērsta bultiņa"</string>
     <string name="permission_expand" msgid="893185038020887411">"Izvērst: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Sakļaut: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vai lietotnēm ierīcē &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; piešķirt tādas pašas atļaujas kā ierīcē &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mk/strings.xml b/packages/CompanionDeviceManager/res/values-mk/strings.xml
index 1eaf2d2..d9c8695 100644
--- a/packages/CompanionDeviceManager/res/values-mk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mk/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Не дозволувај"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Откажи"</string>
     <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Лизгај надолу по списокот"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Стрелка надолу"</string>
     <string name="permission_expand" msgid="893185038020887411">"Прошири <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Собери <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Дасе дадат исти дозволи на апликациите на &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; како на &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ml/strings.xml b/packages/CompanionDeviceManager/res/values-ml/strings.xml
index 52fcb1f..828b6cf 100644
--- a/packages/CompanionDeviceManager/res/values-ml/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ml/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"അനുവദിക്കരുത്"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"റദ്ദാക്കുക"</string>
     <string name="consent_back" msgid="2560683030046918882">"മടങ്ങുക"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"ലിസ്റ്റ് താഴേക്ക് സ്ക്രോൾ ചെയ്യൂ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"താഴേക്കുള്ള അമ്പടയാളം"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> വികസിപ്പിക്കുക"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ചുരുക്കുക"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; എന്നതിലെ അതേ അനുമതികൾ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; എന്നതിലെ ആപ്പുകൾക്ക് നൽകണോ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mn/strings.xml b/packages/CompanionDeviceManager/res/values-mn/strings.xml
index 5faf241..be6eb8e 100644
--- a/packages/CompanionDeviceManager/res/values-mn/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mn/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Бүү зөвшөөр"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Цуцлах"</string>
     <string name="consent_back" msgid="2560683030046918882">"Буцах"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Жагсаалтыг доош гүйлгэх"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Доош заасан сум"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>-г дэлгэх"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>-г хураах"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; дээрх аппуудад &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; дээрхтэй адил зөвшөөрөл өгөх үү?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-mr/strings.xml b/packages/CompanionDeviceManager/res/values-mr/strings.xml
index 94e49fe..99f59a6 100644
--- a/packages/CompanionDeviceManager/res/values-mr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-mr/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"अनुमती देऊ नका"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"रद्द करा"</string>
     <string name="consent_back" msgid="2560683030046918882">"मागे जा"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"सूचीवर खाली स्क्रोल करा"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"खालच्या दिशेचा अ‍ॅरो"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> चा विस्तार करा"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> कोलॅप्स करा"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; वरील अ‍ॅप्सना &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; प्रमाणेच परवानग्या द्यायच्या आहेत का?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ms/strings.xml b/packages/CompanionDeviceManager/res/values-ms/strings.xml
index 8b1170b..9c15c06 100644
--- a/packages/CompanionDeviceManager/res/values-ms/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ms/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Jangan benarkan"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Batal"</string>
     <string name="consent_back" msgid="2560683030046918882">"Kembali"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Tatal ke bawah senarai"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Anak panah ke bawah"</string>
     <string name="permission_expand" msgid="893185038020887411">"Kembangkan <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Kuncupkan <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Beri apl pada &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; kebenaran yang sama seperti pada &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-my/strings.xml b/packages/CompanionDeviceManager/res/values-my/strings.xml
index faca3e3..6068c43 100644
--- a/packages/CompanionDeviceManager/res/values-my/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-my/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ခွင့်မပြုပါ"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"မလုပ်တော့"</string>
     <string name="consent_back" msgid="2560683030046918882">"နောက်သို့"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"စာရင်းအောက်သို့ လှိမ့်ရန်"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"အောက်ညွှန်မြား"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ကို ပိုပြရန်"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ကို လျှော့ပြရန်"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"အက်ပ်များကို &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; တွင်ပေးထားသည့် ခွင့်ပြုချက်များအတိုင်း &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; တွင် ပေးမလား။"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nb/strings.xml b/packages/CompanionDeviceManager/res/values-nb/strings.xml
index 4188951..eb5e2e9 100644
--- a/packages/CompanionDeviceManager/res/values-nb/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nb/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ikke tillat"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Avbryt"</string>
     <string name="consent_back" msgid="2560683030046918882">"Tilbake"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Rull nedover i listen"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Nedoverpil"</string>
     <string name="permission_expand" msgid="893185038020887411">"Vis <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Skjul <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vil du gi apper på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; de samme tillatelsene som på &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ne/strings.xml b/packages/CompanionDeviceManager/res/values-ne/strings.xml
index 2cd4fef..f3b56de 100644
--- a/packages/CompanionDeviceManager/res/values-ne/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ne/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"अनुमति नदिनुहोस्"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"रद्द गर्नुहोस्"</string>
     <string name="consent_back" msgid="2560683030046918882">"पछाडि"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"सूचीको तलतिर स्क्रोल गर्नुहोस्"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"डाउनवार्ड एरो"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> एक्स्पान्ड गर्नुहोस्"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> कोल्याप्स गर्नुहोस्"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; मा भएका एपहरूलाई पनि &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; मा दिइएकै अनुमति दिने हो?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-nl/strings.xml b/packages/CompanionDeviceManager/res/values-nl/strings.xml
index 2f0fc9a..2bb4b9a 100644
--- a/packages/CompanionDeviceManager/res/values-nl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-nl/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Niet toestaan"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Annuleren"</string>
     <string name="consent_back" msgid="2560683030046918882">"Terug"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Omlaag scrollen in de lijst"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Pijl-omlaag"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> uitvouwen"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> samenvouwen"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Apps op de &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; dezelfde rechten geven als op de &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-or/strings.xml b/packages/CompanionDeviceManager/res/values-or/strings.xml
index 8298a5b..bd602e4 100644
--- a/packages/CompanionDeviceManager/res/values-or/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-or/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ଅନୁମତି ଦିଅନ୍ତୁ ନାହିଁ"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ବାତିଲ କରନ୍ତୁ"</string>
     <string name="consent_back" msgid="2560683030046918882">"ପଛକୁ ଫେରନ୍ତୁ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"ତାଲିକା ତଳକୁ ସ୍କ୍ରୋଲ କରନ୍ତୁ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ଡାଉନୱାର୍ଡ ତୀର"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>କୁ ବିସ୍ତାର କରନ୍ତୁ"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>କୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;ପରି &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;ରେ ଥିବା ଆପ୍ସକୁ ସମାନ ଅନୁମତିଗୁଡ଼ିକ ଦେବେ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pa/strings.xml b/packages/CompanionDeviceManager/res/values-pa/strings.xml
index fe13c00..ae0b59d 100644
--- a/packages/CompanionDeviceManager/res/values-pa/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pa/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ਆਗਿਆ ਨਾ ਦਿਓ"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ਰੱਦ ਕਰੋ"</string>
     <string name="consent_back" msgid="2560683030046918882">"ਪਿੱਛੇ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"ਸੂਚੀ ਨੂੰ ਹੇਠਾਂ ਵੱਲ ਸਕ੍ਰੋਲ ਕਰੋ"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ਹੇਠਾਂ ਤੀਰ"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ਦਾ ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ਨੂੰ ਸਮੇਟੋ"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ਕੀ &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਮੌਜੂਦ ਐਪਾਂ ਨੂੰ &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; \'ਤੇ ਮੌਜੂਦ ਐਪਾਂ ਵਾਂਗ ਇਜਾਜ਼ਤਾਂ ਦੇਣੀਆਂ ਹਨ?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pl/strings.xml b/packages/CompanionDeviceManager/res/values-pl/strings.xml
index 1599f3f..bce0a6e 100644
--- a/packages/CompanionDeviceManager/res/values-pl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pl/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nie zezwalaj"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Anuluj"</string>
     <string name="consent_back" msgid="2560683030046918882">"Wstecz"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Przewiń listę w dół"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Strzałka w dół"</string>
     <string name="permission_expand" msgid="893185038020887411">"Rozwiń sekcję <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Zwiń sekcję <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Czy aplikacjom na urządzeniu &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; przyznać te same uprawnienia co na urządzeniu &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
index 85c23ea7..35b653a 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rBR/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
     <string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Role para baixo na lista"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Seta para baixo"</string>
     <string name="permission_expand" msgid="893185038020887411">"Abrir <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Fechar <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dar aos apps no dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; as mesmas permissões do dispositivo &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
index bee8e91..ec9beeb 100644
--- a/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt-rPT/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
     <string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Deslocar para baixo na lista"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Seta para baixo"</string>
     <string name="permission_expand" msgid="893185038020887411">"Expandir <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Reduzir <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dar às apps no dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; as mesmas autorizações de &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-pt/strings.xml b/packages/CompanionDeviceManager/res/values-pt/strings.xml
index 85c23ea7..35b653a 100644
--- a/packages/CompanionDeviceManager/res/values-pt/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-pt/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Não permitir"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Cancelar"</string>
     <string name="consent_back" msgid="2560683030046918882">"Voltar"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Role para baixo na lista"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Seta para baixo"</string>
     <string name="permission_expand" msgid="893185038020887411">"Abrir <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Fechar <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Dar aos apps no dispositivo &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; as mesmas permissões do dispositivo &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ro/strings.xml b/packages/CompanionDeviceManager/res/values-ro/strings.xml
index 6820d5b..0fdeb29 100644
--- a/packages/CompanionDeviceManager/res/values-ro/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ro/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nu permite"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Anulează"</string>
     <string name="consent_back" msgid="2560683030046918882">"Înapoi"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Derulează în jos lista"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Săgeată în jos"</string>
     <string name="permission_expand" msgid="893185038020887411">"Extinde <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Restrânge <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Acorzi aplicațiilor de pe &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; aceleași permisiuni ca pe &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ru/strings.xml b/packages/CompanionDeviceManager/res/values-ru/strings.xml
index 3213a2f..872f45e 100644
--- a/packages/CompanionDeviceManager/res/values-ru/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ru/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Запретить"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Отмена"</string>
     <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Прокрутить список вниз"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Стрелка вниз"</string>
     <string name="permission_expand" msgid="893185038020887411">"Разворачивать список \"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\"."</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Сворачивать список \"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\"."</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Предоставить приложениям на устройстве &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; те же разрешения, что на устройстве &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-si/strings.xml b/packages/CompanionDeviceManager/res/values-si/strings.xml
index 7fd6611..ec362f2 100644
--- a/packages/CompanionDeviceManager/res/values-si/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-si/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ඉඩ නොදෙන්න"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"අවලංගු කරන්න"</string>
     <string name="consent_back" msgid="2560683030046918882">"ආපසු"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"ලැයිස්තුව පහළට අනුචලනය කරන්න"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"පහළට ඊතලය"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> විදහන්න"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> හකුළන්න"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; the හි යෙදුම්වලට &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; හි අවසරම දෙන්නද?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sk/strings.xml b/packages/CompanionDeviceManager/res/values-sk/strings.xml
index 5194f21..cbf5648 100644
--- a/packages/CompanionDeviceManager/res/values-sk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sk/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Nepovoliť"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Zrušiť"</string>
     <string name="consent_back" msgid="2560683030046918882">"Späť"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Posunúť zoznam nadol"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Šípka nadol"</string>
     <string name="permission_expand" msgid="893185038020887411">"Rozbaliť sekciu <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Zbaliť sekciu <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Chcete udeliť aplikáciám v zariadení &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; rovnaké povolenia ako v zariadení &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sl/strings.xml b/packages/CompanionDeviceManager/res/values-sl/strings.xml
index 2200220..20570c30 100644
--- a/packages/CompanionDeviceManager/res/values-sl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sl/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ne dovoli"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Prekliči"</string>
     <string name="consent_back" msgid="2560683030046918882">"Nazaj"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Pomikanje navzdol po seznamu"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Puščica navzdol"</string>
     <string name="permission_expand" msgid="893185038020887411">"Razširi dovoljenje »<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>«"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Strni dovoljenje »<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>«"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Ali želite aplikacijam v napravi &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; odobriti enaka dovoljenja kot v napravi &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sq/strings.xml b/packages/CompanionDeviceManager/res/values-sq/strings.xml
index f683dd9..32ede40 100644
--- a/packages/CompanionDeviceManager/res/values-sq/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sq/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Mos lejo"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Anulo"</string>
     <string name="consent_back" msgid="2560683030046918882">"Pas"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Lëviz poshtë në listë"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Shigjeta poshtë"</string>
     <string name="permission_expand" msgid="893185038020887411">"Zgjero: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Palos: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"T\'i jepen aplikacioneve në &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; të njëjtat leje si në &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sr/strings.xml b/packages/CompanionDeviceManager/res/values-sr/strings.xml
index d568009..ac84c34 100644
--- a/packages/CompanionDeviceManager/res/values-sr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sr/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Не дозволи"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Откажи"</string>
     <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Скролујте надоле на листи"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Стрелица надоле"</string>
     <string name="permission_expand" msgid="893185038020887411">"Прошири <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Скупи <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Апликцијама на уређају &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; дајете све дозволе као на уређају &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sv/strings.xml b/packages/CompanionDeviceManager/res/values-sv/strings.xml
index 5c6f5ba..c9364b8 100644
--- a/packages/CompanionDeviceManager/res/values-sv/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sv/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Tillåt inte"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Avbryt"</string>
     <string name="consent_back" msgid="2560683030046918882">"Tillbaka"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Scrolla nedåt i listan"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Nedåtpil"</string>
     <string name="permission_expand" msgid="893185038020887411">"Utöka <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Komprimera <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Vill du ge apparna på &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; samma behörigheter som de har på &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-sw/strings.xml b/packages/CompanionDeviceManager/res/values-sw/strings.xml
index 7a1cf98..2a9cbee 100644
--- a/packages/CompanionDeviceManager/res/values-sw/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-sw/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Usiruhusu"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Ghairi"</string>
     <string name="consent_back" msgid="2560683030046918882">"Nyuma"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Sogeza chini kwenye orodha"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Kishale kinachoelekeza chini"</string>
     <string name="permission_expand" msgid="893185038020887411">"Panua <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Kunja <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Ungependa kuzipa programu katika &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ruhusa ile ile kama kwenye &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ta/strings.xml b/packages/CompanionDeviceManager/res/values-ta/strings.xml
index 2313cc3..2503826 100644
--- a/packages/CompanionDeviceManager/res/values-ta/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ta/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"அனுமதிக்க வேண்டாம்"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ரத்துசெய்"</string>
     <string name="consent_back" msgid="2560683030046918882">"பின்செல்"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"பட்டியலில் கீழே நகர்த்து"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"கீழ்நோக்கிய அம்புக்குறி"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ஐ விரிவாக்கும்"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> ஐச் சுருக்கும்"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; சாதனத்தில் இருக்கும் அதே அனுமதிகளை &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; சாதனத்தில் உள்ள ஆப்ஸுக்கும் வழங்கவா?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-te/strings.xml b/packages/CompanionDeviceManager/res/values-te/strings.xml
index eed0eee..d82c57c 100644
--- a/packages/CompanionDeviceManager/res/values-te/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-te/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"అనుమతించవద్దు"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"రద్దు చేయండి"</string>
     <string name="consent_back" msgid="2560683030046918882">"వెనుకకు"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"లిస్ట్‌ను కిందకు స్క్రోల్ చేయి"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"కింది వైపు బాణం గుర్తు"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>‌ను విస్తరించండి"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>‌ను కుదించండి"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;లోని యాప్‌లకు &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;లో ఉన్న అనుమతులను ఇవ్వాలా?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-th/strings.xml b/packages/CompanionDeviceManager/res/values-th/strings.xml
index bf14f4c..26aa9dd 100644
--- a/packages/CompanionDeviceManager/res/values-th/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-th/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"ไม่อนุญาต"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"ยกเลิก"</string>
     <string name="consent_back" msgid="2560683030046918882">"กลับ"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"เลื่อนรายการลง"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"ลูกศรชี้ลง"</string>
     <string name="permission_expand" msgid="893185038020887411">"ขยาย <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"ยุบ <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"ให้แอปใน &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; มีสิทธิ์เหมือนกับใน &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; ไหม"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tl/strings.xml b/packages/CompanionDeviceManager/res/values-tl/strings.xml
index 90e5eb7..fbc12f2 100644
--- a/packages/CompanionDeviceManager/res/values-tl/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tl/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Huwag payagan"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Kanselahin"</string>
     <string name="consent_back" msgid="2560683030046918882">"Bumalik"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Mag-scroll pababa sa listahan"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Pababang arrow"</string>
     <string name="permission_expand" msgid="893185038020887411">"I-expand ang <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"I-collapse ang <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Bigyan ang mga app sa &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ng mga pahintulot na mayroon din sa &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-tr/strings.xml b/packages/CompanionDeviceManager/res/values-tr/strings.xml
index 56997d7..01fc767 100644
--- a/packages/CompanionDeviceManager/res/values-tr/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-tr/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"İzin verme"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"İptal"</string>
     <string name="consent_back" msgid="2560683030046918882">"Geri"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Listeyi aşağı kaydırın"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Aşağı ok"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> panelini genişlet"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> panelini daralt"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; cihazındaki uygulamalara, &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; cihazındakiyle aynı izinler verilsin mi?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uk/strings.xml b/packages/CompanionDeviceManager/res/values-uk/strings.xml
index 7d7b9de..73e5d58 100644
--- a/packages/CompanionDeviceManager/res/values-uk/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uk/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Не дозволяти"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Скасувати"</string>
     <string name="consent_back" msgid="2560683030046918882">"Назад"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Прокрутити список униз"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Стрілка вниз"</string>
     <string name="permission_expand" msgid="893185038020887411">"Розгорнути дозвіл \"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\""</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Згорнути дозвіл \"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>\""</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Надати додаткам на пристрої &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; такі самі дозволи, що й на пристрої &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-ur/strings.xml b/packages/CompanionDeviceManager/res/values-ur/strings.xml
index 690e439..895dfb0 100644
--- a/packages/CompanionDeviceManager/res/values-ur/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-ur/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"اجازت نہ دیں"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"منسوخ کریں"</string>
     <string name="consent_back" msgid="2560683030046918882">"پیچھے"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"فہرست نیچے سکرول کریں"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"نیچے کی طرف تیر کا نشان"</string>
     <string name="permission_expand" msgid="893185038020887411">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> کو پھیلائیں"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g> کو سکیڑیں"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"‏ایپس کو &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; پر وہی اجازتیں دیں جو &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; پر دی گئی ہیں؟"</string>
diff --git a/packages/CompanionDeviceManager/res/values-uz/strings.xml b/packages/CompanionDeviceManager/res/values-uz/strings.xml
index e1a024c..b4ac45c 100644
--- a/packages/CompanionDeviceManager/res/values-uz/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-uz/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ruxsat berilmasin"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Bekor qilish"</string>
     <string name="consent_back" msgid="2560683030046918882">"Orqaga"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Roʻyxatni pastga varaqlash"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Pastga strelka"</string>
     <string name="permission_expand" msgid="893185038020887411">"Yoyish: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Yopish: <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; ilovalariga &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; qurilmasidagi kabi bir xil ruxsatlar berilsinmi?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-vi/strings.xml b/packages/CompanionDeviceManager/res/values-vi/strings.xml
index 0293317..11cceaf 100644
--- a/packages/CompanionDeviceManager/res/values-vi/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-vi/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Không cho phép"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Huỷ"</string>
     <string name="consent_back" msgid="2560683030046918882">"Quay lại"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Di chuyển xuống danh sách"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Mũi tên xuống"</string>
     <string name="permission_expand" msgid="893185038020887411">"Mở rộng <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Thu gọn <xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Cấp cho các ứng dụng trên &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; các quyền giống như trên &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
index ed68dd3..7632af0 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rCN/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"不允许"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"取消"</string>
     <string name="consent_back" msgid="2560683030046918882">"返回"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"向下滚动列表"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"向下箭头"</string>
     <string name="permission_expand" msgid="893185038020887411">"展开<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"收起<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"要让&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt;上的应用享有在&lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;上的同等权限吗?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
index 17d3482f..9f988c3 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rHK/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"不允許"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"取消"</string>
     <string name="consent_back" msgid="2560683030046918882">"返回"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"向下捲動清單"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"向下箭咀"</string>
     <string name="permission_expand" msgid="893185038020887411">"展開<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"收合<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"&lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; 上的應用程式可獲在 &lt;strong&gt;<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt; 上的相同權限嗎?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
index 542a73fc..5bc7bfa 100644
--- a/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zh-rTW/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"不允許"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"取消"</string>
     <string name="consent_back" msgid="2560683030046918882">"返回"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"向下捲動清單"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"向下箭頭"</string>
     <string name="permission_expand" msgid="893185038020887411">"展開<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"收合<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"要讓「<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;的應用程式沿用在「<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>」&lt;strong&gt;&lt;/strong&gt;上的權限嗎?"</string>
diff --git a/packages/CompanionDeviceManager/res/values-zu/strings.xml b/packages/CompanionDeviceManager/res/values-zu/strings.xml
index b1c7a14..37034fa 100644
--- a/packages/CompanionDeviceManager/res/values-zu/strings.xml
+++ b/packages/CompanionDeviceManager/res/values-zu/strings.xml
@@ -51,10 +51,8 @@
     <string name="consent_no" msgid="2640796915611404382">"Ungavumeli"</string>
     <string name="consent_cancel" msgid="5655005528379285841">"Khansela"</string>
     <string name="consent_back" msgid="2560683030046918882">"Emuva"</string>
-    <!-- no translation found for downward_arrow_action (2327165938832076333) -->
-    <skip />
-    <!-- no translation found for downward_arrow (2292427714411156088) -->
-    <skip />
+    <string name="downward_arrow_action" msgid="2327165938832076333">"Skrola uye ezansi ohlwini"</string>
+    <string name="downward_arrow" msgid="2292427714411156088">"Umcibisholo obheke phansi"</string>
     <string name="permission_expand" msgid="893185038020887411">"Nweba i-<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_collapse" msgid="3320833884220844084">"Goqa i-<xliff:g id="PERMISSION_TYPE">%1$s</xliff:g>"</string>
     <string name="permission_sync_confirmation_title" msgid="4409622174437248702">"Nikeza ama-app &lt;strong&gt;<xliff:g id="COMPANION_DEVICE_NAME">%1$s</xliff:g>&lt;/strong&gt; izimvume ezifanayot &lt;strong&gt;njengaku-<xliff:g id="PRIMARY_DEVICE_NAME">%2$s</xliff:g>&lt;/strong&gt;?"</string>
diff --git a/packages/DynamicSystemInstallationService/res/values-mr/strings.xml b/packages/DynamicSystemInstallationService/res/values-mr/strings.xml
index 3b6741d..b18ce0e 100644
--- a/packages/DynamicSystemInstallationService/res/values-mr/strings.xml
+++ b/packages/DynamicSystemInstallationService/res/values-mr/strings.xml
@@ -1,17 +1,17 @@
 <?xml version="1.0" encoding="UTF-8"?>
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
-    <string name="keyguard_description" msgid="8582605799129954556">"कृपया तुमचा पासवर्ड एंटर करा आणि डायनॅमिक सिस्टम अपडेट वर जा"</string>
-    <string name="notification_install_completed" msgid="6252047868415172643">"डायनॅमिक सिस्टम तयार आहे. ती वापरणे सुरू करण्यासाठी, तुमचे डिव्हाइस रीस्टार्ट करा."</string>
+    <string name="keyguard_description" msgid="8582605799129954556">"कृपया तुमचा पासवर्ड एंटर करा आणि डायनॅमिक सिस्टीम अपडेट वर जा"</string>
+    <string name="notification_install_completed" msgid="6252047868415172643">"डायनॅमिक सिस्टीम तयार आहे. ती वापरणे सुरू करण्यासाठी, तुमचे डिव्हाइस रीस्टार्ट करा."</string>
     <string name="notification_install_inprogress" msgid="7383334330065065017">"इंस्टॉल प्रगतीपथावर आहे"</string>
     <string name="notification_install_failed" msgid="4066039210317521404">"इंस्टॉल करता आली नाही"</string>
     <string name="notification_image_validation_failed" msgid="2720357826403917016">"इमेज प्रमाणित करता आली नाही. इंस्टॉलेशन रद्द करा."</string>
-    <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"सध्या डायनॅमिक सिस्टम रन करत आहे. मूळ Android आवृत्ती वापरण्यासाठी रीस्टार्ट करा."</string>
+    <string name="notification_dynsystem_in_use" msgid="1053194595682188396">"सध्या डायनॅमिक सिस्टीम रन करत आहे. मूळ Android आवृत्ती वापरण्यासाठी रीस्टार्ट करा."</string>
     <string name="notification_action_cancel" msgid="5929299408545961077">"रद्द करा"</string>
     <string name="notification_action_discard" msgid="1817481003134947493">"काढून टाका"</string>
     <string name="notification_action_reboot_to_dynsystem" msgid="4015817159115912479">"रीस्टार्ट करा"</string>
     <string name="notification_action_reboot_to_origin" msgid="4013901243271889897">"रीस्टार्ट करा"</string>
-    <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"डायनॅमिक सिस्टम काढून टाकली"</string>
-    <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"डायनॅमिक सिस्टम रीस्टार्ट किंवा लोड करू शकत नाही"</string>
-    <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"डायनॅमिक सिस्टम बंद करता आली नाही"</string>
+    <string name="toast_dynsystem_discarded" msgid="1733249860276017050">"डायनॅमिक सिस्टीम काढून टाकली"</string>
+    <string name="toast_failed_to_reboot_to_dynsystem" msgid="6336737274625452067">"डायनॅमिक सिस्टीम रीस्टार्ट किंवा लोड करू शकत नाही"</string>
+    <string name="toast_failed_to_disable_dynsystem" msgid="3285742944977744413">"डायनॅमिक सिस्टीम बंद करता आली नाही"</string>
 </resources>
diff --git a/packages/EasterEgg/src/com/android/egg/landroid/UniverseProgressNotifier.kt b/packages/EasterEgg/src/com/android/egg/landroid/UniverseProgressNotifier.kt
index bb3a04d..705d9e1 100644
--- a/packages/EasterEgg/src/com/android/egg/landroid/UniverseProgressNotifier.kt
+++ b/packages/EasterEgg/src/com/android/egg/landroid/UniverseProgressNotifier.kt
@@ -127,7 +127,7 @@
                     val eta = if (speed > 0) "%1.0fs".format(distToTarget / speed) else "???"
                     builder.setContentTitle("headed to: ${target.name}")
                     builder.setContentText(
-                        "autopilot is ${autopilot.strategy.toLowerCase()}" +
+                        "autopilot is ${autopilot.strategy.lowercase()}" +
                             "\ndist: ${distToTarget}u // eta: $eta"
                     )
                     // fun fact: ProgressStyle was originally EnRouteStyle
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout-v36/settingslib_expressive_main_switch_layout.xml b/packages/SettingsLib/MainSwitchPreference/res/layout-v36/settingslib_expressive_main_switch_layout.xml
index 94c6924..7adbfbf 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout-v36/settingslib_expressive_main_switch_layout.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout-v36/settingslib_expressive_main_switch_layout.xml
@@ -19,14 +19,14 @@
     android:layout_height="wrap_content"
     android:layout_width="match_parent"
     android:paddingStart="?android:attr/listPreferredItemPaddingStart"
-    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd"
-    android:importantForAccessibility="no">
+    android:paddingEnd="?android:attr/listPreferredItemPaddingEnd">
 
     <com.android.settingslib.widget.MainSwitchBar
         android:id="@+id/settingslib_main_switch_bar"
         android:visibility="gone"
         android:layout_height="wrap_content"
-        android:layout_width="match_parent" />
+        android:layout_width="match_parent"
+        android:importantForAccessibility="no" />
 
 </FrameLayout>
 
diff --git a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_layout.xml b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_layout.xml
index bef6e35..c5dd24c 100644
--- a/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_layout.xml
+++ b/packages/SettingsLib/MainSwitchPreference/res/layout/settingslib_main_switch_layout.xml
@@ -17,14 +17,14 @@
 
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_height="wrap_content"
-    android:layout_width="match_parent"
-    android:importantForAccessibility="no">
+    android:layout_width="match_parent">
 
     <com.android.settingslib.widget.MainSwitchBar
         android:id="@+id/settingslib_main_switch_bar"
         android:visibility="gone"
         android:layout_height="wrap_content"
-        android:layout_width="match_parent" />
+        android:layout_width="match_parent"
+        android:importantForAccessibility="no" />
 
 </FrameLayout>
 
diff --git a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
index d883fb0..5170581 100644
--- a/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
+++ b/packages/SettingsLib/MainSwitchPreference/src/com/android/settingslib/widget/MainSwitchPreference.java
@@ -80,7 +80,14 @@
         mainSwitchBar.setIconSpaceReserved(isIconSpaceReserved());
         // To support onPreferenceChange callback, it needs to call callChangeListener() when
         // MainSwitchBar is clicked.
-        mainSwitchBar.setOnClickListener(view -> callChangeListener(isChecked()));
+        mainSwitchBar.setOnClickListener(view -> {
+            boolean isChecked = isChecked();
+            if (!callChangeListener(isChecked)) {
+                // Change checked state back if listener doesn't like it.
+                // Note that CompoundButton maintains internal state to avoid infinite recursion.
+                mainSwitchBar.setChecked(!isChecked);
+            }
+        });
 
         // Remove all listeners to 1. avoid triggering listener when update UI 2. prevent potential
         // listener leaking when the view holder is reused by RecyclerView
@@ -88,7 +95,11 @@
         mainSwitchBar.setChecked(isChecked());
         mainSwitchBar.addOnSwitchChangeListener(this);
 
-        mainSwitchBar.show();
+        if (isVisible()) {
+            mainSwitchBar.show();
+        } else {
+            mainSwitchBar.hide();
+        }
     }
 
     @Override
@@ -101,7 +112,10 @@
 
     /**
      * Adds a listener for switch changes
+     *
+     * @deprecated Use {@link #setOnPreferenceChangeListener(OnPreferenceChangeListener)}
      */
+    @Deprecated
     public void addOnSwitchChangeListener(OnCheckedChangeListener listener) {
         if (!mSwitchChangeListeners.contains(listener)) {
             mSwitchChangeListeners.add(listener);
@@ -110,7 +124,10 @@
 
     /**
      * Remove a listener for switch changes
+     *
+     * @deprecated Use {@link #setOnPreferenceChangeListener(OnPreferenceChangeListener)}
      */
+    @Deprecated
     public void removeOnSwitchChangeListener(OnCheckedChangeListener listener) {
         mSwitchChangeListeners.remove(listener);
     }
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/res/layout-v36/preference_selector_with_widget.xml b/packages/SettingsLib/SelectorWithWidgetPreference/res/layout-v36/settingslib_expressive_preference_selector_with_widget.xml
similarity index 100%
rename from packages/SettingsLib/SelectorWithWidgetPreference/res/layout-v36/preference_selector_with_widget.xml
rename to packages/SettingsLib/SelectorWithWidgetPreference/res/layout-v36/settingslib_expressive_preference_selector_with_widget.xml
diff --git a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
index cde8b33..465b6cc 100644
--- a/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
+++ b/packages/SettingsLib/SelectorWithWidgetPreference/src/com/android/settingslib/widget/SelectorWithWidgetPreference.java
@@ -238,7 +238,10 @@
         } else {
             setWidgetLayoutResource(R.layout.settingslib_preference_widget_radiobutton);
         }
-        setLayoutResource(R.layout.preference_selector_with_widget);
+        int resID = SettingsThemeHelper.isExpressiveTheme(context)
+                ? R.layout.settingslib_expressive_preference_selector_with_widget
+                : R.layout.preference_selector_with_widget;
+        setLayoutResource(resID);
         setIconSpaceReserved(false);
 
         final TypedArray a =
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background.xml
index 0446873..9aa0bc3 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background.xml
@@ -19,12 +19,16 @@
     android:color="?android:colorControlHighlight">
     <item
         android:start="?android:attr/listPreferredItemPaddingStart"
-        android:end="?android:attr/listPreferredItemPaddingEnd">
+        android:end="?android:attr/listPreferredItemPaddingEnd"
+        android:top="2dp"
+        android:bottom="16dp">
         <shape android:shape="rectangle">
             <solid
                 android:color="@color/settingslib_materialColorSurfaceBright" />
             <corners
                 android:radius="@dimen/settingslib_preference_corner_radius" />
+            <padding
+                android:bottom="16dp"/>
         </shape>
     </item>
-</ripple>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom.xml
index 25a936d..554cba5 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom.xml
@@ -19,7 +19,9 @@
     android:color="?android:colorControlHighlight">
     <item
         android:start="?android:attr/listPreferredItemPaddingStart"
-        android:end="?android:attr/listPreferredItemPaddingEnd">
+        android:end="?android:attr/listPreferredItemPaddingEnd"
+        android:top="2dp"
+        android:bottom="16dp">
         <shape android:shape="rectangle">
             <solid
                 android:color="@color/settingslib_materialColorSurfaceBright" />
@@ -28,6 +30,8 @@
                 android:bottomLeftRadius="@dimen/settingslib_preference_corner_radius"
                 android:topRightRadius="4dp"
                 android:bottomRightRadius="@dimen/settingslib_preference_corner_radius" />
+            <padding
+                android:bottom="16dp"/>
         </shape>
     </item>
-</ripple>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_highlighted.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_highlighted.xml
index db2800e..c0c0869 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_highlighted.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_highlighted.xml
@@ -19,7 +19,8 @@
     <item
         android:bottom="16dp"
         android:end="?android:attr/listPreferredItemPaddingEnd"
-        android:start="?android:attr/listPreferredItemPaddingStart">
+        android:start="?android:attr/listPreferredItemPaddingStart"
+        android:top="2dp">
         <shape
             android:shape="rectangle"
             android:tint="?android:attr/colorAccent">
@@ -28,7 +29,8 @@
                 android:bottomRightRadius="@dimen/settingslib_preference_corner_radius"
                 android:topLeftRadius="4dp"
                 android:topRightRadius="4dp" />
+            <padding android:bottom="16dp" />
             <solid android:color="#42000000" />
         </shape>
     </item>
-</ripple>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_selected.xml
index 98f95d92..543b237 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_selected.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_bottom_selected.xml
@@ -19,7 +19,9 @@
     android:color="?android:colorControlHighlight">
     <item
         android:start="?android:attr/listPreferredItemPaddingStart"
-        android:end="?android:attr/listPreferredItemPaddingEnd">
+        android:end="?android:attr/listPreferredItemPaddingEnd"
+        android:top="2dp"
+        android:bottom="16dp">
         <shape android:shape="rectangle">
             <solid
                 android:color="@color/settingslib_materialColorSurfaceContainer" />
@@ -28,6 +30,8 @@
                 android:bottomLeftRadius="@dimen/settingslib_preference_corner_radius"
                 android:topRightRadius="4dp"
                 android:bottomRightRadius="@dimen/settingslib_preference_corner_radius" />
+            <padding
+                android:bottom="16dp"/>
         </shape>
     </item>
-</ripple>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center.xml
index c4286fd..b89a0dd 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center.xml
@@ -19,7 +19,8 @@
     android:color="?android:colorControlHighlight">
     <item
         android:start="?android:attr/listPreferredItemPaddingStart"
-        android:end="?android:attr/listPreferredItemPaddingEnd">
+        android:end="?android:attr/listPreferredItemPaddingEnd"
+        android:top="2dp">
         <shape android:shape="rectangle">
             <solid
                 android:color="@color/settingslib_materialColorSurfaceBright" />
@@ -27,4 +28,4 @@
                 android:radius="4dp" />
         </shape>
     </item>
-</ripple>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_highlighted.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_highlighted.xml
index 194cdb0..8099d9b 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_highlighted.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_highlighted.xml
@@ -18,7 +18,8 @@
     android:color="?android:colorControlHighlight">
     <item
         android:end="?android:attr/listPreferredItemPaddingEnd"
-        android:start="?android:attr/listPreferredItemPaddingStart">
+        android:start="?android:attr/listPreferredItemPaddingStart"
+        android:top="2dp">
         <shape
             android:shape="rectangle"
             android:tint="?android:attr/colorAccent">
@@ -26,4 +27,4 @@
             <solid android:color="#42000000" />
         </shape>
     </item>
-</ripple>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_selected.xml
index 8bc2f2f..6d2cd1a 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_selected.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_center_selected.xml
@@ -19,7 +19,8 @@
     android:color="?android:colorControlHighlight">
     <item
         android:start="?android:attr/listPreferredItemPaddingStart"
-        android:end="?android:attr/listPreferredItemPaddingEnd">
+        android:end="?android:attr/listPreferredItemPaddingEnd"
+        android:top="2dp">
         <shape android:shape="rectangle">
             <solid
                 android:color="@color/settingslib_materialColorSurfaceContainer" />
@@ -27,4 +28,4 @@
                 android:radius="4dp" />
         </shape>
     </item>
-</ripple>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_highlighted.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_highlighted.xml
index 2341661..a119a4a 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_highlighted.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_highlighted.xml
@@ -19,12 +19,14 @@
     <item
         android:bottom="16dp"
         android:end="?android:attr/listPreferredItemPaddingEnd"
-        android:start="?android:attr/listPreferredItemPaddingStart">
+        android:start="?android:attr/listPreferredItemPaddingStart"
+        android:top="2dp">
         <shape
             android:shape="rectangle"
             android:tint="?android:attr/colorAccent">
             <corners android:radius="@dimen/settingslib_preference_corner_radius" />
+            <padding android:bottom="16dp" />
             <solid android:color="#42000000" />
         </shape>
     </item>
-</ripple>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_selected.xml
index 99704f2d..bcdbf1d 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_selected.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_selected.xml
@@ -19,12 +19,16 @@
     android:color="?android:colorControlHighlight">
     <item
         android:start="?android:attr/listPreferredItemPaddingStart"
-        android:end="?android:attr/listPreferredItemPaddingEnd">
+        android:end="?android:attr/listPreferredItemPaddingEnd"
+        android:top="2dp"
+        android:bottom="16dp">
         <shape android:shape="rectangle">
             <solid
                 android:color="@color/settingslib_materialColorSurfaceContainer" />
             <corners
                 android:radius="@dimen/settingslib_preference_corner_radius" />
+            <padding
+                android:bottom="16dp"/>
         </shape>
     </item>
-</ripple>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top.xml
index 3a59386..7955e44 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top.xml
@@ -19,7 +19,8 @@
     android:color="?android:colorControlHighlight">
     <item
         android:start="?android:attr/listPreferredItemPaddingStart"
-        android:end="?android:attr/listPreferredItemPaddingEnd">
+        android:end="?android:attr/listPreferredItemPaddingEnd"
+        android:top="2dp">
         <shape android:shape="rectangle">
             <solid
                 android:color="@color/settingslib_materialColorSurfaceBright" />
@@ -30,4 +31,4 @@
                 android:bottomRightRadius="4dp" />
         </shape>
     </item>
-</ripple>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_highlighted.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_highlighted.xml
index edace29..052eb01 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_highlighted.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_highlighted.xml
@@ -19,7 +19,8 @@
     <item
         android:color="?android:attr/colorAccent"
         android:end="?android:attr/listPreferredItemPaddingEnd"
-        android:start="?android:attr/listPreferredItemPaddingStart">
+        android:start="?android:attr/listPreferredItemPaddingStart"
+        android:top="2dp">
         <shape
             android:shape="rectangle"
             android:tint="?android:attr/colorAccent">
@@ -31,4 +32,4 @@
             <solid android:color="#42000000" />
         </shape>
     </item>
-</ripple>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_selected.xml b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_selected.xml
index b2d6d9d..d4b658c 100644
--- a/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_selected.xml
+++ b/packages/SettingsLib/SettingsTheme/res/drawable-v36/settingslib_round_background_top_selected.xml
@@ -19,7 +19,8 @@
     android:color="?android:colorControlHighlight">
     <item
         android:start="?android:attr/listPreferredItemPaddingStart"
-        android:end="?android:attr/listPreferredItemPaddingEnd">
+        android:end="?android:attr/listPreferredItemPaddingEnd"
+        android:top="2dp">
         <shape android:shape="rectangle">
             <solid
                 android:color="@color/settingslib_materialColorSurfaceContainer" />
@@ -30,4 +31,4 @@
                 android:bottomRightRadius="4dp" />
         </shape>
     </item>
-</ripple>
+</ripple>
\ No newline at end of file
diff --git a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt
index 22cd873..8d12f01 100644
--- a/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt
+++ b/packages/SettingsLib/SettingsTheme/src/com/android/settingslib/widget/SettingsBasePreferenceFragment.kt
@@ -16,7 +16,6 @@
 
 package com.android.settingslib.widget
 
-import android.graphics.Rect
 import android.os.Bundle
 import android.view.LayoutInflater;
 import android.view.View
@@ -25,7 +24,6 @@
 import androidx.preference.PreferenceFragmentCompat
 import androidx.preference.PreferenceScreen
 import androidx.recyclerview.widget.RecyclerView
-import com.android.settingslib.widget.theme.R
 
 /** Base class for Settings to use PreferenceFragmentCompat */
 abstract class SettingsBasePreferenceFragment : PreferenceFragmentCompat() {
@@ -45,7 +43,6 @@
         if (SettingsThemeHelper.isExpressiveTheme(requireContext())) {
             // Don't allow any divider in between the preferences in expressive design.
             setDivider(null)
-            this.listView.addItemDecoration(MarginItemDecoration())
         }
     }
 
@@ -54,18 +51,4 @@
             return SettingsPreferenceGroupAdapter(preferenceScreen)
         return super.onCreateAdapter(preferenceScreen)
     }
-
-    internal class MarginItemDecoration() : RecyclerView.ItemDecoration() {
-        override fun getItemOffsets(
-            outRect: Rect,
-            view: View,
-            parent: RecyclerView,
-            state: RecyclerView.State,
-        ) {
-            with(outRect) {
-                bottom =
-                    view.resources.getDimensionPixelSize(R.dimen.settingslib_expressive_radius_extrasmall1)
-            }
-        }
-  }
 }
diff --git a/packages/SettingsLib/SpaPrivileged/tests/Android.bp b/packages/SettingsLib/SpaPrivileged/tests/unit/Android.bp
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/Android.bp
rename to packages/SettingsLib/SpaPrivileged/tests/unit/Android.bp
diff --git a/packages/SettingsLib/SpaPrivileged/tests/AndroidManifest.xml b/packages/SettingsLib/SpaPrivileged/tests/unit/AndroidManifest.xml
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/AndroidManifest.xml
rename to packages/SettingsLib/SpaPrivileged/tests/unit/AndroidManifest.xml
diff --git a/packages/SettingsLib/SpaPrivileged/tests/res/values/strings.xml b/packages/SettingsLib/SpaPrivileged/tests/unit/res/values/strings.xml
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/res/values/strings.xml
rename to packages/SettingsLib/SpaPrivileged/tests/unit/res/values/strings.xml
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverAsUserFlowTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/common/BroadcastReceiverFlowTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatterTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatterTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatterTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/common/BytesFormatterTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/framework/compose/DisposableBroadcastReceiverAsUserTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppListRepositoryTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppListViewModelTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppOpsControllerTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionControllerTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionControllerTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionControllerTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppOpsPermissionControllerTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppOpsRepositoryTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppOpsRepositoryTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppOpsRepositoryTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppRepositoryTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepositoryTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepositoryTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepositoryTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/AppStorageRepositoryTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfosTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfosTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfosTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/ApplicationInfosTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagerExtTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/PackageManagerExtTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagerExtTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/PackageManagerExtTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagersTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/PackageManagersTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PackageManagersTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/PackageManagersTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlowTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlowTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/app/PermissionsChangedFlowTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedModeTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedModeTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedModeTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/model/enterprise/RestrictedModeTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalBooleanTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsGlobalChangeFlowTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBooleanTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBooleanTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBooleanTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureBooleanTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/settingsprovider/SettingsSecureStringTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppInfoTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListPageTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItemTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItemTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItemTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListSwitchItemTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTwoTargetSwitchItemTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListTwoTargetSwitchItemTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppListTwoTargetSwitchItemTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppListTwoTargetSwitchItemTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppOpPermissionAppListTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/AppStorageSizeTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppInfoPageTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListPageTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/app/TogglePermissionAppListTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/common/UserProfilePagerTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/common/UserProfilePagerTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/common/UserProfilePagerTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/common/UserProfilePagerTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedMainSwitchPreferenceTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedMainSwitchPreferenceTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedMainSwitchPreferenceTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedMainSwitchPreferenceTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedPreferenceTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedPreferenceTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedPreferenceTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedPreferenceTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedSwitchPreferenceTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedTwoTargetSwitchPreferenceTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedTwoTargetSwitchPreferenceTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/preference/RestrictedTwoTargetSwitchPreferenceTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/preference/RestrictedTwoTargetSwitchPreferenceTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/template/scaffold/RestrictedMenuItemTest.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/RestrictedTestUtils.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/RestrictedTestUtils.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/RestrictedTestUtils.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/RestrictedTestUtils.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestAppListModel.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/TestAppListModel.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestAppListModel.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/TestAppListModel.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListModel.kt
diff --git a/packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt b/packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt
similarity index 100%
rename from packages/SettingsLib/SpaPrivileged/tests/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt
rename to packages/SettingsLib/SpaPrivileged/tests/unit/src/com/android/settingslib/spaprivileged/tests/testutils/TestTogglePermissionAppListProvider.kt
diff --git a/packages/SettingsLib/aconfig/settingslib.aconfig b/packages/SettingsLib/aconfig/settingslib.aconfig
index a029f56..349d13a 100644
--- a/packages/SettingsLib/aconfig/settingslib.aconfig
+++ b/packages/SettingsLib/aconfig/settingslib.aconfig
@@ -37,13 +37,6 @@
 }
 
 flag {
-    name: "enable_hide_exclusively_managed_bluetooth_device"
-    namespace: "dck_framework"
-    description: "Hide exclusively managed Bluetooth devices in BT settings menu."
-    bug: "324475542"
-}
-
-flag {
     name: "enable_set_preferred_transport_for_le_audio_device"
     namespace: "bluetooth"
     description: "Enable setting preferred transport for Le Audio device"
@@ -249,3 +242,13 @@
         purpose: PURPOSE_BUGFIX
     }
 }
+
+flag {
+    name: "audio_stream_media_service_by_receive_state"
+    namespace: "cross_device_experiences"
+    description: "Start or update audio stream media service by receive state"
+    bug: "398700619"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/packages/SettingsLib/res/drawable/ic_news.xml b/packages/SettingsLib/res/drawable/ic_news.xml
new file mode 100644
index 0000000..90615ec
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_news.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="14.933333dp" android:viewportHeight="14" android:viewportWidth="15" android:width="16dp">
+    <path android:fillColor="#ffffff" android:pathData="M3,10.8H11V9.6H3V10.8ZM3,8.4H5.4V4.8H3V8.4ZM12.2,13.6H1.8C1.467,13.6 1.183,13.483 0.95,13.25C0.717,13.017 0.6,12.733 0.6,12.4V3.6C0.6,3.267 0.717,2.983 0.95,2.75C1.183,2.517 1.467,2.4 1.8,2.4H6.683C6.528,2.711 6.406,3.033 6.317,3.367C6.239,3.7 6.2,4.044 6.2,4.4C6.2,4.933 6.283,5.439 6.45,5.917C6.628,6.383 6.878,6.811 7.2,7.2H6.6V8.4H8.767C9.056,8.522 9.35,8.622 9.65,8.7C9.961,8.767 10.278,8.8 10.6,8.8C11.111,8.8 11.606,8.717 12.083,8.55C12.572,8.372 13.011,8.122 13.4,7.8V12.4C13.4,12.733 13.283,13.017 13.05,13.25C12.817,13.483 12.533,13.6 12.2,13.6ZM10.6,8C10.6,7 10.25,6.15 9.55,5.45C8.85,4.75 8,4.4 7,4.4C8,4.4 8.85,4.05 9.55,3.35C10.25,2.65 10.6,1.8 10.6,0.8C10.6,1.8 10.95,2.65 11.65,3.35C12.35,4.05 13.2,4.4 14.2,4.4C13.2,4.4 12.35,4.75 11.65,5.45C10.95,6.15 10.6,7 10.6,8Z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_promotions.xml b/packages/SettingsLib/res/drawable/ic_promotions.xml
new file mode 100644
index 0000000..a597ece
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_promotions.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="16dp" android:viewportHeight="15" android:viewportWidth="13" android:width="13.866667dp">
+    <path android:fillColor="#ffffff" android:pathData="M1.4,13.4C1.067,13.4 0.783,13.283 0.55,13.05C0.317,12.817 0.2,12.533 0.2,12.2V4.6C0.2,4.267 0.317,3.983 0.55,3.75C0.783,3.517 1.067,3.4 1.4,3.4H2.6V3.133C2.6,2.467 2.822,1.878 3.267,1.367C3.722,0.856 4.3,0.6 5,0.6C5.667,0.6 6.233,0.833 6.7,1.3C7.167,1.767 7.4,2.333 7.4,3V3.4H8.6C8.933,3.4 9.217,3.517 9.45,3.75C9.683,3.983 9.8,4.267 9.8,4.6V6.367C9.611,6.311 9.417,6.272 9.217,6.25C9.017,6.217 8.811,6.2 8.6,6.2C7.378,6.2 6.339,6.628 5.483,7.483C4.628,8.339 4.2,9.378 4.2,10.6C4.2,11.111 4.283,11.611 4.45,12.1C4.628,12.578 4.878,13.011 5.2,13.4H1.4ZM8.6,14.2C8.6,13.2 8.25,12.35 7.55,11.65C6.85,10.95 6,10.6 5,10.6C6,10.6 6.85,10.25 7.55,9.55C8.25,8.85 8.6,8 8.6,7C8.6,8 8.95,8.85 9.65,9.55C10.35,10.25 11.2,10.6 12.2,10.6C11.2,10.6 10.35,10.95 9.65,11.65C8.95,12.35 8.6,13.2 8.6,14.2ZM3.8,3.4H6.2V3C6.2,2.667 6.083,2.383 5.85,2.15C5.617,1.917 5.333,1.8 5,1.8C4.667,1.8 4.383,1.917 4.15,2.15C3.917,2.383 3.8,2.667 3.8,3V3.4ZM3.2,5.8C3.367,5.8 3.506,5.744 3.617,5.633C3.739,5.511 3.8,5.367 3.8,5.2V4.6H2.6V5.2C2.6,5.367 2.656,5.511 2.767,5.633C2.889,5.744 3.033,5.8 3.2,5.8ZM6.8,5.8C6.967,5.8 7.106,5.744 7.217,5.633C7.339,5.511 7.4,5.367 7.4,5.2V4.6H6.2V5.2C6.2,5.367 6.256,5.511 6.367,5.633C6.489,5.744 6.633,5.8 6.8,5.8Z"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_recs.xml b/packages/SettingsLib/res/drawable/ic_recs.xml
new file mode 100644
index 0000000..034ff9e
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_recs.xml
@@ -0,0 +1,25 @@
+<!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="14dp"
+    android:height="16dp"
+    android:viewportWidth="14"
+    android:viewportHeight="16">
+  <path
+      android:pathData="M6,15.2L3.6,12.8H1.6C1.278,12.8 0.994,12.683 0.75,12.45C0.517,12.206 0.4,11.922 0.4,11.6V2.8C0.4,2.478 0.517,2.2 0.75,1.967C0.994,1.722 1.278,1.6 1.6,1.6H6.2C5.878,1.989 5.628,2.428 5.45,2.917C5.283,3.394 5.2,3.889 5.2,4.4C5.2,5.622 5.628,6.661 6.483,7.517C7.339,8.372 8.378,8.8 9.6,8.8C9.956,8.8 10.3,8.761 10.633,8.683C10.967,8.594 11.289,8.472 11.6,8.317V11.6C11.6,11.922 11.483,12.206 11.25,12.45C11.017,12.683 10.733,12.8 10.4,12.8H8.4L6,15.2ZM9.6,8C9.6,7 9.25,6.15 8.55,5.45C7.85,4.75 7,4.4 6,4.4C7,4.4 7.85,4.05 8.55,3.35C9.25,2.65 9.6,1.8 9.6,0.8C9.6,1.8 9.95,2.65 10.65,3.35C11.35,4.05 12.2,4.4 13.2,4.4C12.2,4.4 11.35,4.75 10.65,5.45C9.95,6.15 9.6,7 9.6,8Z"
+      android:fillColor="#ffffff"/>
+</vector>
diff --git a/packages/SettingsLib/res/drawable/ic_social.xml b/packages/SettingsLib/res/drawable/ic_social.xml
new file mode 100644
index 0000000..0197431
--- /dev/null
+++ b/packages/SettingsLib/res/drawable/ic_social.xml
@@ -0,0 +1,19 @@
+<!--
+  ~ Copyright (C) 2025 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+
+<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="16dp" android:viewportHeight="15" android:viewportWidth="15" android:width="16dp">
+    <path android:fillColor="#ffffff" android:pathData="M0.6,14.4V12.733C0.6,12.411 0.678,12.117 0.833,11.85C0.989,11.583 1.211,11.378 1.5,11.233C2.056,10.956 2.628,10.75 3.217,10.617C3.817,10.472 4.428,10.4 5.05,10.4C5.661,10.4 6.256,10.472 6.833,10.617C7.422,10.75 7.989,10.956 8.533,11.233C8.811,11.378 9.028,11.583 9.183,11.85C9.339,12.117 9.417,12.411 9.417,12.733V14.4H0.6ZM10.6,14.4V12.617C10.6,12.183 10.494,11.778 10.283,11.4C10.072,11.022 9.772,10.733 9.383,10.533C9.772,10.6 10.144,10.7 10.5,10.833C10.856,10.956 11.206,11.106 11.55,11.283C11.828,11.439 12.072,11.628 12.283,11.85C12.494,12.061 12.6,12.317 12.6,12.617V14.4H10.6ZM5.2,9.6C4.589,9.6 4.067,9.389 3.633,8.967C3.211,8.533 3,8.011 3,7.4C3,6.789 3.211,6.272 3.633,5.85C4.067,5.417 4.589,5.2 5.2,5.2C5.811,5.2 6.328,5.417 6.75,5.85C7.183,6.272 7.4,6.789 7.4,7.4C7.4,8.011 7.183,8.533 6.75,8.967C6.328,9.389 5.811,9.6 5.2,9.6ZM10.6,7.4C10.6,8.011 10.383,8.533 9.95,8.967C9.528,9.389 9.011,9.6 8.4,9.6C8.311,9.6 8.217,9.594 8.117,9.583C8.017,9.572 7.922,9.55 7.833,9.517C8.089,9.206 8.278,8.872 8.4,8.517C8.533,8.161 8.6,7.789 8.6,7.4C8.6,7.011 8.533,6.639 8.4,6.283C8.278,5.928 8.089,5.594 7.833,5.283C7.922,5.25 8.017,5.228 8.117,5.217C8.217,5.206 8.311,5.2 8.4,5.2C9.011,5.2 9.528,5.417 9.95,5.85C10.383,6.272 10.6,6.789 10.6,7.4ZM11.4,6.4C11.4,5.622 11.128,4.961 10.583,4.417C10.039,3.872 9.378,3.6 8.6,3.6C9.378,3.6 10.039,3.328 10.583,2.783C11.128,2.239 11.4,1.578 11.4,0.8C11.4,1.578 11.672,2.239 12.217,2.783C12.761,3.328 13.422,3.6 14.2,3.6C13.422,3.6 12.761,3.872 12.217,4.417C11.672,4.961 11.4,5.622 11.4,6.4Z"/>
+</vector>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 2fc946b..07849e0 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -81,7 +81,7 @@
     <string name="speed_label_fast" msgid="2677719134596044051">"Élevée"</string>
     <string name="speed_label_very_fast" msgid="8215718029533182439">"Très rapide"</string>
     <string name="wifi_passpoint_expired" msgid="6540867261754427561">"Arrivé à expiration"</string>
-    <string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g>/<xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
+    <string name="preference_summary_default_combination" msgid="2644094566845577901">"<xliff:g id="STATE">%1$s</xliff:g> / <xliff:g id="DESCRIPTION">%2$s</xliff:g>"</string>
     <string name="bluetooth_disconnected" msgid="7739366554710388701">"Déconnecté"</string>
     <string name="bluetooth_disconnecting" msgid="7638892134401574338">"Déconnexion…"</string>
     <string name="bluetooth_connecting" msgid="5871702668260192755">"Connexion…"</string>
diff --git a/packages/SettingsLib/res/values-mr/strings.xml b/packages/SettingsLib/res/values-mr/strings.xml
index 826d601..8c77b08 100644
--- a/packages/SettingsLib/res/values-mr/strings.xml
+++ b/packages/SettingsLib/res/values-mr/strings.xml
@@ -561,7 +561,7 @@
     <string name="retail_demo_reset_next" msgid="3688129033843885362">"पुढील"</string>
     <string name="retail_demo_reset_title" msgid="1866911701095959800">"पासवर्ड आवश्यक"</string>
     <string name="active_input_method_subtypes" msgid="4232680535471633046">"सक्रिय इनपुट पद्धती"</string>
-    <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"सिस्टम भाषा वापरा"</string>
+    <string name="use_system_language_to_select_input_method_subtypes" msgid="4865195835541387040">"सिस्टीम भाषा वापरा"</string>
     <string name="failed_to_open_app_settings_toast" msgid="764897252657692092">"<xliff:g id="SPELL_APPLICATION_NAME">%1$s</xliff:g> साठी सेटिंग्ज उघडण्यात अयशस्वी"</string>
     <string name="ime_security_warning" msgid="6547562217880551450">"ही इनपुट पद्धत पासवर्ड आणि क्रेडिट कार्ड नंबर यासह, तुम्ही टाइप करता तो सर्व मजकूर संकलित करण्यात सक्षम होऊ शकते. ही <xliff:g id="IME_APPLICATION_NAME">%1$s</xliff:g> ॲपवरून येते. ही इनपुट पद्धत वापरायची?"</string>
     <string name="direct_boot_unaware_dialog_message" msgid="7845398276735021548">"टीप: रीबूट केल्यानंतर, तुम्ही तुमचा फोन अनलॉक करेपर्यंत हे अ‍ॅप सुरू होऊ शकत नाही"</string>
diff --git a/packages/SettingsLib/res/values-pt-rPT/strings.xml b/packages/SettingsLib/res/values-pt-rPT/strings.xml
index e4381d6..11f410f 100644
--- a/packages/SettingsLib/res/values-pt-rPT/strings.xml
+++ b/packages/SettingsLib/res/values-pt-rPT/strings.xml
@@ -530,7 +530,7 @@
     <string name="battery_info_status_charging_dock" msgid="8573274094093364791">"A carregar"</string>
     <string name="battery_info_status_discharging" msgid="6962689305413556485">"Não está a carregar"</string>
     <string name="battery_info_status_not_charging" msgid="1103084691314264664">"Ligado, mas não está a carregar"</string>
-    <string name="battery_info_status_full" msgid="1339002294876531312">"Carregada"</string>
+    <string name="battery_info_status_full" msgid="1339002294876531312">"Bateria carregada"</string>
     <string name="battery_info_status_full_charged" msgid="3536054261505567948">"Totalmente carregada"</string>
     <string name="battery_info_status_charging_on_hold" msgid="6364355145521694438">"Carregamento em espera"</string>
     <string name="battery_info_status_charging_v2" msgid="6118522107222245505">"Carregamento"</string>
diff --git a/packages/SettingsLib/res/values-vi/strings.xml b/packages/SettingsLib/res/values-vi/strings.xml
index 6095e8c..c2c035c 100644
--- a/packages/SettingsLib/res/values-vi/strings.xml
+++ b/packages/SettingsLib/res/values-vi/strings.xml
@@ -109,7 +109,7 @@
     <string name="bluetooth_saved_device" msgid="4895871321722311428">"Đã lưu"</string>
     <string name="bluetooth_hearing_aid_left_active" msgid="8330226430756799572">"Đang hoạt động (chỉ tai trái)"</string>
     <string name="bluetooth_hearing_aid_right_active" msgid="2244728507170385397">"Đang hoạt động (chỉ tai phải)"</string>
-    <string name="bluetooth_hearing_aid_left_and_right_active" msgid="4294571497939983181">"Đang hoạt động (cả tai phải và tai trái)"</string>
+    <string name="bluetooth_hearing_aid_left_and_right_active" msgid="4294571497939983181">"Đang hoạt động (trái và phải)"</string>
     <string name="bluetooth_hearing_device_ambient_error" msgid="6035857289108813878">"Không cập nhật được âm lượng xung quanh"</string>
     <string name="bluetooth_active_media_only_battery_level" msgid="7772517511061834073">"Đang hoạt động (chỉ phát nội dung đa phương tiện). Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE">%1$s</xliff:g> pin."</string>
     <string name="bluetooth_active_media_only_battery_level_untethered" msgid="7444753133664620926">"Đang hoạt động (chỉ phát nội dung đa phương tiện). Bên trái: Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_0">%1$s</xliff:g> pin. Bên phải: Còn <xliff:g id="BATTERY_LEVEL_AS_PERCENTAGE_1">%2$s</xliff:g> pin."</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BatteryLevelsInfo.kt b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BatteryLevelsInfo.kt
new file mode 100644
index 0000000..b52a901
--- /dev/null
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BatteryLevelsInfo.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.bluetooth
+
+/**
+ * BatteryLevelsInfo contains the battery levels of different components of a bluetooth device.
+ * The range of a valid battery level is [0-100], and -1 if the battery level is not applicable.
+ */
+data class BatteryLevelsInfo(
+    val leftBatteryLevel: Int,
+    val rightBatteryLevel: Int,
+    val caseBatteryLevel: Int,
+    val overallBatteryLevel: Int,
+)
\ No newline at end of file
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
index e78a692..ae9ad95 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/BluetoothUtils.java
@@ -51,6 +51,8 @@
 import com.google.common.collect.ImmutableSet;
 
 import java.io.IOException;
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
@@ -1268,4 +1270,15 @@
 
         return false;
     }
+
+    /** Gets key missing count of the device. This is a workaround before the API is rolled out. */
+    public static Integer getKeyMissingCount(BluetoothDevice device) {
+        try {
+            Method m = BluetoothDevice.class.getDeclaredMethod("getKeyMissingCount");
+            return (int) m.invoke(device);
+        } catch (NoSuchMethodException | InvocationTargetException | IllegalAccessException e) {
+            Log.w(TAG, "error happens when getKeyMissingCount.");
+            return null;
+        }
+    }
 }
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index bb96041..3646842 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -44,10 +44,12 @@
 import android.util.Log;
 import android.util.LruCache;
 import android.util.Pair;
+import android.view.InputDevice;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 import androidx.annotation.VisibleForTesting;
+import androidx.annotation.WorkerThread;
 
 import com.android.internal.util.ArrayUtils;
 import com.android.settingslib.R;
@@ -62,6 +64,7 @@
 
 import java.sql.Timestamp;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collection;
 import java.util.HashSet;
 import java.util.List;
@@ -150,6 +153,9 @@
     private boolean mIsHearingAidProfileConnectedFail = false;
     private boolean mIsLeAudioProfileConnectedFail = false;
     private boolean mUnpairing;
+    @Nullable
+    private final InputDevice mInputDevice;
+    private final boolean mIsDeviceStylus;
 
     // Group second device for Hearing Aid
     private CachedBluetoothDevice mSubDevice;
@@ -193,6 +199,8 @@
         mGroupId = BluetoothCsipSetCoordinator.GROUP_ID_INVALID;
         initDrawableCache();
         mUnpairing = false;
+        mInputDevice = BluetoothUtils.getInputDevice(mContext, getAddress());
+        mIsDeviceStylus = BluetoothUtils.isDeviceStylus(mInputDevice, this);
     }
 
     /** Clears any pending messages in the message queue. */
@@ -1622,6 +1630,86 @@
         }
     }
 
+    /**
+     * Returns the battery levels of all components of the bluetooth device. If no battery info is
+     * available then returns null.
+     */
+    @WorkerThread
+    @Nullable
+    public BatteryLevelsInfo getBatteryLevelsInfo() {
+        // Try getting the battery information from metadata.
+        BatteryLevelsInfo metadataSourceBattery = getBatteryFromMetadata();
+        if (metadataSourceBattery != null) {
+            return metadataSourceBattery;
+        }
+        // Get the battery information from Bluetooth service.
+        return getBatteryFromBluetoothService();
+    }
+
+    @Nullable
+    private BatteryLevelsInfo getBatteryFromMetadata() {
+        if (BluetoothUtils.getBooleanMetaData(mDevice,
+                BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)) {
+            // The device is untethered headset, containing both earbuds and case.
+            int leftBattery =
+                    BluetoothUtils.getIntMetaData(
+                            mDevice, BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY);
+            int rightBattery =
+                    BluetoothUtils.getIntMetaData(
+                            mDevice, BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY);
+            int caseBattery =
+                    BluetoothUtils.getIntMetaData(
+                            mDevice, BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY);
+
+            if (leftBattery <= BluetoothDevice.BATTERY_LEVEL_UNKNOWN
+                    && rightBattery <= BluetoothDevice.BATTERY_LEVEL_UNKNOWN
+                    && caseBattery <= BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+                Log.d(TAG, "No battery info from metadata is available for untethered device "
+                        + mDevice.getAnonymizedAddress());
+                return null;
+            } else {
+                int overallBattery =
+                        Arrays.stream(new int[]{leftBattery, rightBattery, caseBattery})
+                                .filter(battery -> battery > BluetoothDevice.BATTERY_LEVEL_UNKNOWN)
+                                .min()
+                                .orElse(BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
+                Log.d(TAG, "Acquired battery info from metadata for untethered device "
+                        + mDevice.getAnonymizedAddress()
+                        + " left earbud battery: " + leftBattery
+                        + " right earbud battery: " + rightBattery
+                        + " case battery: " + caseBattery
+                        + " overall battery: " + overallBattery);
+                return new BatteryLevelsInfo(
+                        leftBattery, rightBattery, caseBattery, overallBattery);
+            }
+        } else if (mInputDevice != null || mIsDeviceStylus) {
+            // The device is input device, using METADATA_MAIN_BATTERY field to get battery info.
+            int overallBattery = BluetoothUtils.getIntMetaData(
+                    mDevice, BluetoothDevice.METADATA_MAIN_BATTERY);
+            if (overallBattery <= BluetoothDevice.BATTERY_LEVEL_UNKNOWN) {
+                Log.d(TAG, "No battery info from metadata is available for input device "
+                        + mDevice.getAnonymizedAddress());
+                return null;
+            } else {
+                Log.d(TAG, "Acquired battery info from metadata for input device "
+                        + mDevice.getAnonymizedAddress()
+                        + " overall battery: " + overallBattery);
+                return new BatteryLevelsInfo(
+                        BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
+                        BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
+                        BluetoothDevice.BATTERY_LEVEL_UNKNOWN,
+                        overallBattery);
+            }
+        }
+        return null;
+    }
+
+    @Nullable
+    private BatteryLevelsInfo getBatteryFromBluetoothService() {
+        // TODO(b/397847825): Implement the logic to get battery from Bluetooth service.
+        return null;
+    }
+
     private CharSequence getTvBatterySummary(int mainBattery, int leftBattery, int rightBattery,
             int lowBatteryColorRes) {
         // Since there doesn't seem to be a way to use format strings to add the
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index f6e26a7..ed53d8d 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -40,12 +40,14 @@
 import android.bluetooth.BluetoothStatusCodes;
 import android.content.Context;
 import android.graphics.drawable.BitmapDrawable;
+import android.hardware.input.InputManager;
 import android.media.AudioManager;
 import android.platform.test.flag.junit.SetFlagsRule;
 import android.provider.Settings;
 import android.text.Spannable;
 import android.text.style.ForegroundColorSpan;
 import android.util.LruCache;
+import android.view.InputDevice;
 
 import com.android.settingslib.R;
 import com.android.settingslib.media.flags.Flags;
@@ -77,8 +79,10 @@
     private static final String DEVICE_ALIAS_NEW = "TestAliasNew";
     private static final String TWS_BATTERY_LEFT = "15";
     private static final String TWS_BATTERY_RIGHT = "25";
+    private static final String TWS_BATTERY_CASE = "10";
     private static final String TWS_LOW_BATTERY_THRESHOLD_LOW = "10";
     private static final String TWS_LOW_BATTERY_THRESHOLD_HIGH = "25";
+    private static final String MAIN_BATTERY = "80";
     private static final String TEMP_BOND_METADATA =
             "<TEMP_BOND_TYPE>le_audio_sharing</TEMP_BOND_TYPE>";
     private static final short RSSI_1 = 10;
@@ -87,6 +91,8 @@
     private static final boolean JUSTDISCOVERED_2 = false;
     private static final int LOW_BATTERY_COLOR = android.R.color.holo_red_dark;
     private static final int METADATA_FAST_PAIR_CUSTOMIZED_FIELDS = 25;
+    private static final int TEST_DEVICE_ID = 123;
+    private final InputDevice mInputDevice = mock(InputDevice.class);
     @Mock
     private LocalBluetoothProfileManager mProfileManager;
     @Mock
@@ -116,6 +122,8 @@
     private LocalBluetoothLeBroadcastAssistant mAssistant;
     @Mock
     private BluetoothLeBroadcastReceiveState mLeBroadcastReceiveState;
+    @Mock
+    private InputManager mInputManager;
     private CachedBluetoothDevice mCachedDevice;
     private CachedBluetoothDevice mSubCachedDevice;
     private AudioManager mAudioManager;
@@ -2175,6 +2183,74 @@
         assertThat(mCachedDevice.isHearingDevice()).isFalse();
     }
 
+    @Test
+    public void getBatteryLevelsInfo_untetheredHeadsetWithBattery_returnBatteryLevelsInfo() {
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
+                "true".getBytes());
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_LEFT_BATTERY)).thenReturn(
+                TWS_BATTERY_LEFT.getBytes());
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_RIGHT_BATTERY)).thenReturn(
+                TWS_BATTERY_RIGHT.getBytes());
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_UNTETHERED_CASE_BATTERY)).thenReturn(
+                TWS_BATTERY_CASE.getBytes());
+
+        BatteryLevelsInfo batteryLevelsInfo = mCachedDevice.getBatteryLevelsInfo();
+
+        assertThat(batteryLevelsInfo.getLeftBatteryLevel()).isEqualTo(
+                Integer.parseInt(TWS_BATTERY_LEFT));
+        assertThat(batteryLevelsInfo.getRightBatteryLevel()).isEqualTo(
+                Integer.parseInt(TWS_BATTERY_RIGHT));
+        assertThat(batteryLevelsInfo.getCaseBatteryLevel()).isEqualTo(
+                Integer.parseInt(TWS_BATTERY_CASE));
+        assertThat(batteryLevelsInfo.getOverallBatteryLevel()).isEqualTo(
+                Integer.parseInt(TWS_BATTERY_CASE));
+    }
+
+    @Test
+    public void getBatteryLevelsInfo_inputDeviceWithBattery_returnBatteryLevelsInfo() {
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
+                "false".getBytes());
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_MAIN_BATTERY)).thenReturn(
+                MAIN_BATTERY.getBytes());
+        when(mContext.getSystemService(InputManager.class)).thenReturn(mInputManager);
+        when(mInputManager.getInputDeviceIds()).thenReturn(new int[]{TEST_DEVICE_ID});
+        when(mInputManager.getInputDeviceBluetoothAddress(TEST_DEVICE_ID)).thenReturn(
+                DEVICE_ADDRESS);
+        when(mInputManager.getInputDevice(TEST_DEVICE_ID)).thenReturn(mInputDevice);
+
+        BatteryLevelsInfo batteryLevelsInfo = mCachedDevice.getBatteryLevelsInfo();
+
+        assertThat(batteryLevelsInfo.getLeftBatteryLevel()).isEqualTo(
+                BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
+        assertThat(batteryLevelsInfo.getRightBatteryLevel()).isEqualTo(
+                BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
+        assertThat(batteryLevelsInfo.getCaseBatteryLevel()).isEqualTo(
+                BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
+        assertThat(batteryLevelsInfo.getOverallBatteryLevel()).isEqualTo(
+                Integer.parseInt(MAIN_BATTERY));
+    }
+
+    @Test
+    public void getBatteryLevelsInfo_stylusDeviceWithBattery_returnBatteryLevelsInfo() {
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET)).thenReturn(
+                "false".getBytes());
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_DEVICE_TYPE)).thenReturn(
+                BluetoothDevice.DEVICE_TYPE_STYLUS.getBytes());
+        when(mDevice.getMetadata(BluetoothDevice.METADATA_MAIN_BATTERY)).thenReturn(
+                MAIN_BATTERY.getBytes());
+
+        BatteryLevelsInfo batteryLevelsInfo = mCachedDevice.getBatteryLevelsInfo();
+
+        assertThat(batteryLevelsInfo.getLeftBatteryLevel()).isEqualTo(
+                BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
+        assertThat(batteryLevelsInfo.getRightBatteryLevel()).isEqualTo(
+                BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
+        assertThat(batteryLevelsInfo.getCaseBatteryLevel()).isEqualTo(
+                BluetoothDevice.BATTERY_LEVEL_UNKNOWN);
+        assertThat(batteryLevelsInfo.getOverallBatteryLevel()).isEqualTo(
+                Integer.parseInt(MAIN_BATTERY));
+    }
+
     private void updateProfileStatus(LocalBluetoothProfile profile, int status) {
         doReturn(status).when(profile).getConnectionStatus(mDevice);
         mCachedDevice.onProfileStateChanged(profile, status);
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchPreferenceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchPreferenceTest.java
index a47b4d5..093833e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchPreferenceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/widget/MainSwitchPreferenceTest.java
@@ -18,13 +18,22 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
 import android.content.Context;
 import android.view.View;
 import android.widget.TextView;
 
+import androidx.preference.PreferenceDataStore;
 import androidx.preference.PreferenceViewHolder;
 import androidx.test.core.app.ApplicationProvider;
 
+import com.android.settingslib.preference.PreferenceScreenFactory;
 import com.android.settingslib.widget.mainswitch.R;
 
 import org.junit.Before;
@@ -67,4 +76,31 @@
         assertThat(mRootView.<MainSwitchBar>requireViewById(
                 R.id.settingslib_main_switch_bar).isChecked()).isTrue();
     }
+
+    @Test
+    public void setOnPreferenceChangeListener() {
+        // Attach preference to preference screen, otherwise `Preference.performClick` does not
+        // interact with underlying datastore
+        new PreferenceScreenFactory(mContext).getOrCreatePreferenceScreen().addPreference(
+                mPreference);
+
+        PreferenceDataStore preferenceDataStore = mock(PreferenceDataStore.class);
+        // always return the provided default value
+        when(preferenceDataStore.getBoolean(any(), anyBoolean())).thenAnswer(
+                invocation -> invocation.getArguments()[1]);
+        mPreference.setPreferenceDataStore(preferenceDataStore);
+
+        String key = "key";
+        mPreference.setKey(key);
+        mPreference.setOnPreferenceChangeListener((preference, newValue) -> false);
+        mPreference.onBindViewHolder(mHolder);
+
+        mPreference.performClick();
+        verify(preferenceDataStore, never()).putBoolean(any(), anyBoolean());
+
+        mPreference.setOnPreferenceChangeListener((preference, newValue) -> true);
+
+        mPreference.performClick();
+        verify(preferenceDataStore).putBoolean(any(), anyBoolean());
+    }
 }
diff --git a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
index 3c70fc1..c010529 100644
--- a/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
+++ b/packages/SettingsProvider/src/android/provider/settings/backup/SecureSettings.java
@@ -271,8 +271,6 @@
         Settings.Secure.DEFAULT_NOTE_TASK_PROFILE,
         Settings.Secure.CREDENTIAL_SERVICE,
         Settings.Secure.CREDENTIAL_SERVICE_PRIMARY,
-        Settings.Secure.EVEN_DIMMER_ACTIVATED,
-        Settings.Secure.EVEN_DIMMER_MIN_NITS,
         Settings.Secure.STYLUS_POINTER_ICON_ENABLED,
         Settings.Secure.CAMERA_EXTENSIONS_FALLBACK,
         Settings.Secure.VISUAL_QUERY_ACCESSIBILITY_DETECTION_ENABLED,
diff --git a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
index c09e45e..0ffdf53 100644
--- a/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
+++ b/packages/SettingsProvider/src/android/provider/settings/validators/SecureSettingsValidators.java
@@ -114,9 +114,6 @@
         VALIDATORS.put(Secure.FONT_WEIGHT_ADJUSTMENT, ANY_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.REDUCE_BRIGHT_COLORS_LEVEL, PERCENTAGE_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.REDUCE_BRIGHT_COLORS_PERSIST_ACROSS_REBOOTS, BOOLEAN_VALIDATOR);
-        VALIDATORS.put(Secure.EVEN_DIMMER_ACTIVATED, BOOLEAN_VALIDATOR);
-        VALIDATORS.put(Secure.EVEN_DIMMER_MIN_NITS,
-                new InclusiveFloatRangeValidator(0.0f, Float.MAX_VALUE));
         VALIDATORS.put(Secure.TTS_DEFAULT_RATE, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.TTS_DEFAULT_PITCH, NON_NEGATIVE_INTEGER_VALIDATOR);
         VALIDATORS.put(Secure.TTS_DEFAULT_SYNTH, PACKAGE_NAME_VALIDATOR);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
index de7c450..7c975b7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/DeviceConfigService.java
@@ -72,6 +72,7 @@
 public final class DeviceConfigService extends Binder {
     private static final List<String> sAconfigTextProtoFilesOnDevice = List.of(
             "/system/etc/aconfig_flags.pb",
+            "/system_ext/etc/aconfig_flags.pb",
             "/product/etc/aconfig_flags.pb",
             "/vendor/etc/aconfig_flags.pb");
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
index 167674a..e07832e 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProtoDumpUtil.java
@@ -2189,15 +2189,6 @@
                 Settings.Secure.ENHANCED_VOICE_PRIVACY_ENABLED,
                 SecureSettingsProto.ENHANCED_VOICE_PRIVACY_ENABLED);
 
-        final long evenDimmerToken = p.start(SecureSettingsProto.EVEN_DIMMER);
-        dumpSetting(s, p,
-                Settings.Secure.EVEN_DIMMER_ACTIVATED,
-                SecureSettingsProto.EvenDimmer.EVEN_DIMMER_ACTIVATED);
-        dumpSetting(s, p,
-                Settings.Secure.EVEN_DIMMER_MIN_NITS,
-                SecureSettingsProto.EvenDimmer.EVEN_DIMMER_MIN_NITS);
-        p.end(evenDimmerToken);
-
         dumpSetting(s, p,
                 Settings.Secure.EM_VALUE,
                 SecureSettingsProto.Accessibility.EM_VALUE);
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index bc281ee..4a225bd 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -396,6 +396,8 @@
 
     private volatile SystemConfigManager mSysConfigManager;
 
+    private PackageMonitor mPackageMonitor;
+
     @GuardedBy("mLock")
     private boolean mSyncConfigDisabledUntilReboot;
 
@@ -403,6 +405,7 @@
     @EnabledSince(targetSdkVersion=android.os.Build.VERSION_CODES.S)
     private static final long ENFORCE_READ_PERMISSION_FOR_MULTI_SIM_DATA_CALL = 172670679L;
 
+
     @Override
     public boolean onCreate() {
         Settings.setInSystemServer();
@@ -1036,7 +1039,7 @@
             }
         }, userFilter);
 
-        PackageMonitor monitor = new PackageMonitor() {
+        mPackageMonitor = new PackageMonitor() {
             @Override
             public void onPackageRemoved(String packageName, int uid) {
                 synchronized (mLock) {
@@ -1062,7 +1065,7 @@
         };
 
         // package changes
-        monitor.register(getContext(), BackgroundThread.getHandler().getLooper(),
+        mPackageMonitor.register(getContext(), BackgroundThread.getHandler().getLooper(),
                 UserHandle.ALL, true);
     }
 
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
index 99c4e21c..17c13b7 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsState.java
@@ -158,6 +158,7 @@
 
     private static final List<String> sAconfigTextProtoFilesOnDevice = List.of(
             "/system/etc/aconfig_flags.pb",
+            "/system_ext/etc/aconfig_flags.pb",
             "/product/etc/aconfig_flags.pb",
             "/vendor/etc/aconfig_flags.pb");
 
diff --git a/packages/Shell/res/values-et/strings.xml b/packages/Shell/res/values-et/strings.xml
index 48c7334..c18687f 100644
--- a/packages/Shell/res/values-et/strings.xml
+++ b/packages/Shell/res/values-et/strings.xml
@@ -21,7 +21,7 @@
     <string name="bugreport_in_progress_title" msgid="4311705936714972757">"Luuakse veaaruannet <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_finished_title" msgid="4429132808670114081">"Jäädvustati veaaruanne <xliff:g id="ID">#%d</xliff:g>"</string>
     <string name="bugreport_updating_title" msgid="4423539949559634214">"Üksikasjade lisamine veaaruandesse"</string>
-    <string name="bugreport_updating_wait" msgid="3322151947853929470">"Oodake …"</string>
+    <string name="bugreport_updating_wait" msgid="3322151947853929470">"Palun oodake…"</string>
     <string name="bugreport_finished_text" product="watch" msgid="1223616207145252689">"Veaaruanne kuvatakse telefonis peagi"</string>
     <string name="bugreport_finished_text" product="tv" msgid="5758325479058638893">"Veaaruande jagamiseks valige"</string>
     <string name="bugreport_finished_text" product="default" msgid="8353769438382138847">"Veaaruande jagamiseks puudutage"</string>
diff --git a/packages/SystemUI/Android.bp b/packages/SystemUI/Android.bp
index b53cb27..5b48566 100644
--- a/packages/SystemUI/Android.bp
+++ b/packages/SystemUI/Android.bp
@@ -727,6 +727,7 @@
         "TraceurCommon",
         "Traceur-res",
         "aconfig_settings_flags_lib",
+        "kairos",
     ],
 }
 
diff --git a/packages/SystemUI/BUILD_OWNERS b/packages/SystemUI/BUILD_OWNERS
new file mode 100644
index 0000000..4aadee1
--- /dev/null
+++ b/packages/SystemUI/BUILD_OWNERS
@@ -0,0 +1,22 @@
+# Build file owners for System UI. Owners should consider the following:
+#
+#  - Does the change negatively affect developer builds? Will it make
+#    the build slower?
+#
+#  - Does the change add unnecessary dependencies or compilation steps
+#    that will be difficult to refactor?
+#
+# For more information, see http://go/sysui-build-owners
+
+dsandler@android.com
+
+caitlinshk@google.com
+ccross@android.com
+cinek@google.com
+jernej@google.com
+mankoff@google.com
+nicomazz@google.com
+peskal@google.com
+pixel@google.com
+saff@google.com
+vadimt@google.com
diff --git a/packages/SystemUI/OWNERS b/packages/SystemUI/OWNERS
index f5c0233..ab3fa1b 100644
--- a/packages/SystemUI/OWNERS
+++ b/packages/SystemUI/OWNERS
@@ -125,3 +125,6 @@
 uwaisashraf@google.com
 vinayjoglekar@google.com
 willosborn@google.com
+
+per-file *.mk,{**/,}Android.bp = set noparent
+per-file *.mk,{**/,}Android.bp = file:BUILD_OWNERS
diff --git a/packages/SystemUI/aconfig/predictive_back.aconfig b/packages/SystemUI/aconfig/predictive_back.aconfig
index ee918c2..89a0d89 100644
--- a/packages/SystemUI/aconfig/predictive_back.aconfig
+++ b/packages/SystemUI/aconfig/predictive_back.aconfig
@@ -7,3 +7,10 @@
     description: "Enable Shade Animations"
     bug: "327732946"
 }
+
+flag {
+    name: "predictive_back_delay_transition"
+    namespace: "systemui"
+    description: "Slightly delays the back transition start"
+    bug: "301195601"
+}
diff --git a/packages/SystemUI/aconfig/systemui.aconfig b/packages/SystemUI/aconfig/systemui.aconfig
index 7e8d549..9db4346 100644
--- a/packages/SystemUI/aconfig/systemui.aconfig
+++ b/packages/SystemUI/aconfig/systemui.aconfig
@@ -1434,16 +1434,6 @@
 }
 
 flag {
-  name: "notification_media_manager_background_execution"
-  namespace: "systemui"
-  description: "Decide whether to execute binder calls in background thread"
-  bug: "336612071"
-  metadata {
-    purpose: PURPOSE_BUGFIX
-  }
-}
-
-flag {
   name: "dozeui_scheduling_alarms_background_execution"
   namespace: "systemui"
   description: "Decide whether to execute binder calls to schedule alarms in background thread"
@@ -2103,3 +2093,20 @@
         purpose: PURPOSE_BUGFIX
    }
 }
+
+flag {
+    name: "always_compose_qs_ui_fragment"
+    namespace: "systemui"
+    description: "Have QQS and QS scenes in the Compose fragment always composed, not just when it should be visible."
+    bug: "389985793"
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
+
+flag {
+    name: "move_transition_animation_layer"
+    namespace: "systemui"
+    description: "Enables moving the launching window on top of the origin window in the Animation library."
+    bug: "390422470"
+}
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
index f03bd3d..e43b8a0 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityTransitionAnimator.kt
@@ -62,6 +62,7 @@
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.policy.ScreenDecorationsUtils
 import com.android.systemui.Flags.activityTransitionUseLargestWindow
+import com.android.systemui.Flags.moveTransitionAnimationLayer
 import com.android.systemui.Flags.translucentOccludingActivityFix
 import com.android.systemui.animation.TransitionAnimator.Companion.assertLongLivedReturnAnimations
 import com.android.systemui.animation.TransitionAnimator.Companion.assertReturnAnimations
@@ -1514,6 +1515,20 @@
                             )
                         }
 
+                        if (moveTransitionAnimationLayer()) {
+                            // Ensure that the launching window is rendered above the view's window,
+                            // so it is not obstructed.
+                            // TODO(b/397180418): re-use the start transaction once the
+                            //  RemoteAnimation wrapper is cleaned up.
+                            SurfaceControl.Transaction().use {
+                                it.reparent(
+                                    window.leash,
+                                    controller.transitionContainer.viewRootImpl.surfaceControl,
+                                )
+                                it.apply()
+                            }
+                        }
+
                         if (startTransaction != null) {
                             // Calling applyStateToWindow() here avoids skipping a frame when taking
                             // over an animation.
@@ -1566,12 +1581,18 @@
                 } else {
                     null
                 }
+            val fadeWindowBackgroundLayer =
+                if (moveTransitionAnimationLayer()) {
+                    false
+                } else {
+                    !controller.isBelowAnimatingWindow
+                }
             animation =
                 transitionAnimator.startAnimation(
                     controller,
                     endState,
                     windowBackgroundColor,
-                    fadeWindowBackgroundLayer = !controller.isBelowAnimatingWindow,
+                    fadeWindowBackgroundLayer = fadeWindowBackgroundLayer,
                     drawHole = !controller.isBelowAnimatingWindow,
                     startVelocity = velocityPxPerS,
                     startFrameTime = windowState?.timestamp ?: -1,
@@ -1685,7 +1706,7 @@
             // fade in progressively. Otherwise, it should be fully opaque and will be progressively
             // revealed as the window background color layer above the window fades out.
             val alpha =
-                if (controller.isBelowAnimatingWindow) {
+                if (moveTransitionAnimationLayer() || controller.isBelowAnimatingWindow) {
                     if (controller.isLaunching) {
                         interpolators.contentAfterFadeInInterpolator.getInterpolation(
                             windowProgress
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/GSFAxes.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/GSFAxes.kt
index f4e0361..96feeed 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/GSFAxes.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/GSFAxes.kt
@@ -91,8 +91,8 @@
 
     private val AXIS_MAP =
         listOf(WEIGHT, WIDTH, SLANT, ROUND, GRADE, OPTICAL_SIZE, ITALIC)
-            .map { def -> def.tag.toLowerCase() to def }
+            .map { def -> def.tag.lowercase() to def }
             .toMap()
 
-    fun getAxis(axis: String): AxisDefinition? = AXIS_MAP[axis.toLowerCase()]
+    fun getAxis(axis: String): AxisDefinition? = AXIS_MAP[axis.lowercase()]
 }
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
index 4e889e9..5d9c441 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/TransitionAnimator.kt
@@ -39,6 +39,7 @@
 import com.android.internal.annotations.VisibleForTesting
 import com.android.internal.dynamicanimation.animation.SpringAnimation
 import com.android.internal.dynamicanimation.animation.SpringForce
+import com.android.systemui.Flags.moveTransitionAnimationLayer
 import com.android.systemui.shared.Flags.returnAnimationFrameworkLibrary
 import com.android.systemui.shared.Flags.returnAnimationFrameworkLongLived
 import java.util.concurrent.Executor
@@ -509,6 +510,8 @@
      * punching a hole in the [transition container][Controller.transitionContainer]) iff [drawHole]
      * is true.
      *
+     * TODO(b/397646693): remove drawHole altogether.
+     *
      * If [startVelocity] (expressed in pixels per second) is not null, a multi-spring animation
      * using it for the initial momentum will be used instead of the default interpolators. In this
      * case, [startFrameTime] (if non-negative) represents the frame time at which the springs
@@ -1183,6 +1186,10 @@
                 if (drawHole) {
                     drawable.setXfermode(SRC_MODE)
                 }
+            } else if (moveTransitionAnimationLayer() && fadeOutProgress >= 1 && drawHole) {
+                // If [drawHole] is true, draw it once the opening content is done fading in.
+                drawable.alpha = 0x00
+                drawable.setXfermode(SRC_MODE)
             } else {
                 drawable.alpha = 0xFF
             }
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DoNotDirectlyConstructKosmosDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DoNotDirectlyConstructKosmosDetector.kt
new file mode 100644
index 0000000..40fac0d
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/DoNotDirectlyConstructKosmosDetector.kt
@@ -0,0 +1,79 @@
+/*
+ * 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.internal.systemui.lint
+
+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 com.intellij.psi.PsiMethod
+import org.jetbrains.uast.UCallExpression
+import org.jetbrains.uast.getContainingUClass
+
+/**
+ * Detects direct construction of `Kosmos()` in subclasses of SysuiTestCase, which can and should
+ * use `testKosmos`. See go/thetiger
+ */
+class DoNotDirectlyConstructKosmosDetector : Detector(), SourceCodeScanner {
+    override fun getApplicableConstructorTypes() = listOf("com.android.systemui.kosmos.Kosmos")
+
+    override fun visitConstructor(
+        context: JavaContext,
+        node: UCallExpression,
+        constructor: PsiMethod,
+    ) {
+        val superClassNames =
+            node.getContainingUClass()?.superTypes.orEmpty().map { it.resolve()?.qualifiedName }
+        if (superClassNames.contains("com.android.systemui.SysuiTestCase")) {
+            context.report(
+                issue = ISSUE,
+                scope = node,
+                location = context.getLocation(node.methodIdentifier),
+                message = "Prefer testKosmos to direct Kosmos() in sysui tests.  go/testkosmos",
+            )
+        }
+        super.visitConstructor(context, node, constructor)
+    }
+
+    companion object {
+        @JvmStatic
+        val ISSUE =
+            Issue.create(
+                id = "DoNotDirectlyConstructKosmos",
+                briefDescription =
+                    "Prefer testKosmos to direct Kosmos() in sysui tests.  go/testkosmos",
+                explanation =
+                    """
+                    SysuiTestCase.testKosmos allows us to pre-populate a Kosmos instance with
+                    team-standard fixture values, and makes it easier to make centralized changes
+                    when necessary.  See go/testkosmos
+                """,
+                category = Category.TESTING,
+                priority = 8,
+                severity = Severity.WARNING,
+                implementation =
+                    Implementation(
+                        DoNotDirectlyConstructKosmosDetector::class.java,
+                        Scope.JAVA_FILE_SCOPE,
+                    ),
+            )
+    }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetector.kt
index 4927fb9..13ffa6c 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetector.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/RunTestShouldUseKosmosDetector.kt
@@ -29,16 +29,12 @@
 import org.jetbrains.uast.UCallExpression
 import org.jetbrains.uast.getContainingUFile
 
-/**
- * Detects test function naming violations regarding use of the backtick-wrapped space-allowed
- * feature of Kotlin functions.
- */
+/** Detects use of `TestScope.runTest` when we should use `Kosmos.runTest` by go/kosmos-runtest */
 class RunTestShouldUseKosmosDetector : Detector(), SourceCodeScanner {
     override fun getApplicableMethodNames() = listOf("runTest")
 
     override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
         if (method.getReceiver()?.qualifiedName == "kotlinx.coroutines.test.TestScope") {
-
             val imports =
                 node.getContainingUFile()?.imports.orEmpty().mapNotNull {
                     it.importReference?.asSourceString()
diff --git a/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DoNotDirectlyConstructKosmosTest.kt b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DoNotDirectlyConstructKosmosTest.kt
new file mode 100644
index 0000000..20f6bcb
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/internal/systemui/lint/DoNotDirectlyConstructKosmosTest.kt
@@ -0,0 +1,104 @@
+/*
+ * 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.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.checks.infrastructure.TestLintResult
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+class DoNotDirectlyConstructKosmosTest : SystemUILintDetectorTest() {
+    override fun getDetector(): Detector = DoNotDirectlyConstructKosmosDetector()
+
+    override fun getIssues(): List<Issue> = listOf(DoNotDirectlyConstructKosmosDetector.ISSUE)
+
+    @Test
+    fun wronglyTriesToDirectlyConstructKosmos() {
+        val runOnSource =
+            runOnSource(
+                """
+                      package test.pkg.name
+
+                      import com.android.systemui.kosmos.Kosmos
+                      import com.android.systemui.SysuiTestCase
+
+                      class MyTest: SysuiTestCase {
+                          val kosmos = Kosmos()
+                      }
+                """
+            )
+
+        runOnSource
+            .expectWarningCount(1)
+            .expect(
+                """
+                src/test/pkg/name/MyTest.kt:7: Warning: Prefer testKosmos to direct Kosmos() in sysui tests.  go/testkosmos [DoNotDirectlyConstructKosmos]
+                    val kosmos = Kosmos()
+                                 ~~~~~~
+                0 errors, 1 warnings
+                """
+            )
+    }
+
+    @Test
+    fun okToConstructKosmosIfNotInSysuiTestCase() {
+        val runOnSource =
+            runOnSource(
+                """
+                      package test.pkg.name
+
+                      import com.android.systemui.kosmos.Kosmos
+
+                      class MyTest {
+                          val kosmos = Kosmos()
+                      }
+                """
+            )
+
+        runOnSource.expectWarningCount(0)
+    }
+
+    private fun runOnSource(source: String): TestLintResult {
+        return lint()
+            .files(TestFiles.kotlin(source).indented(), kosmosStub, sysuiTestCaseStub)
+            .issues(DoNotDirectlyConstructKosmosDetector.ISSUE)
+            .run()
+    }
+
+    companion object {
+        private val kosmosStub: TestFile =
+            kotlin(
+                """
+                package com.android.systemui.kosmos
+
+                class Kosmos
+            """
+            )
+
+        private val sysuiTestCaseStub: TestFile =
+            kotlin(
+                """
+                package com.android.systemui
+
+                class SysuiTestCase
+                """
+            )
+    }
+}
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt b/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
index 20efea5..df50eb8 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/PlatformButtons.kt
@@ -31,6 +31,7 @@
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.graphics.Shape
 import androidx.compose.ui.res.painterResource
 import androidx.compose.ui.unit.dp
 
@@ -40,12 +41,15 @@
     modifier: Modifier = Modifier,
     enabled: Boolean = true,
     colors: ButtonColors = filledButtonColors(),
+    contentPadding: PaddingValues = ButtonPaddings,
+    shape: Shape = ButtonDefaults.shape,
     content: @Composable RowScope.() -> Unit,
 ) {
     androidx.compose.material3.Button(
         modifier = modifier.heightIn(min = 36.dp),
         colors = colors,
-        contentPadding = ButtonPaddings,
+        contentPadding = contentPadding,
+        shape = shape,
         onClick = onClick,
         enabled = enabled,
     ) {
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/Bounceable.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/Bounceable.kt
index 3f2f84b..8270969 100644
--- a/packages/SystemUI/compose/core/src/com/android/compose/animation/Bounceable.kt
+++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/Bounceable.kt
@@ -17,13 +17,20 @@
 package com.android.compose.animation
 
 import androidx.compose.foundation.gestures.Orientation
+import androidx.compose.runtime.Stable
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.Measurable
+import androidx.compose.ui.layout.MeasureResult
+import androidx.compose.ui.layout.MeasureScope
 import androidx.compose.ui.layout.layout
+import androidx.compose.ui.node.LayoutModifierNode
+import androidx.compose.ui.node.ModifierNodeElement
 import androidx.compose.ui.unit.Constraints
 import androidx.compose.ui.unit.Dp
 import kotlin.math.roundToInt
 
 /** A component that can bounce in one dimension, for instance when it is tapped. */
+@Stable
 interface Bounceable {
     val bounce: Dp
 }
@@ -46,6 +53,7 @@
  *   RTL layouts) side. This can be used for grids for which the last item does not align perfectly
  *   with the end of the grid.
  */
+@Stable
 fun Modifier.bounceable(
     bounceable: Bounceable,
     previousBounceable: Bounceable?,
@@ -53,7 +61,47 @@
     orientation: Orientation,
     bounceEnd: Boolean = nextBounceable != null,
 ): Modifier {
-    return layout { measurable, constraints ->
+    return this then
+        BounceableElement(bounceable, previousBounceable, nextBounceable, orientation, bounceEnd)
+}
+
+private data class BounceableElement(
+    private val bounceable: Bounceable,
+    private val previousBounceable: Bounceable?,
+    private val nextBounceable: Bounceable?,
+    private val orientation: Orientation,
+    private val bounceEnd: Boolean,
+) : ModifierNodeElement<BounceableNode>() {
+    override fun create(): BounceableNode {
+        return BounceableNode(
+            bounceable,
+            previousBounceable,
+            nextBounceable,
+            orientation,
+            bounceEnd,
+        )
+    }
+
+    override fun update(node: BounceableNode) {
+        node.bounceable = bounceable
+        node.previousBounceable = previousBounceable
+        node.nextBounceable = nextBounceable
+        node.orientation = orientation
+        node.bounceEnd = bounceEnd
+    }
+}
+
+private class BounceableNode(
+    var bounceable: Bounceable,
+    var previousBounceable: Bounceable?,
+    var nextBounceable: Bounceable?,
+    var orientation: Orientation,
+    var bounceEnd: Boolean = nextBounceable != null,
+) : Modifier.Node(), LayoutModifierNode {
+    override fun MeasureScope.measure(
+        measurable: Measurable,
+        constraints: Constraints,
+    ): MeasureResult {
         // The constraints in the orientation should be fixed, otherwise there is no way to know
         // what the size of our child node will be without this animation code.
         checkFixedSize(constraints, orientation)
@@ -61,10 +109,12 @@
         var sizePrevious = 0f
         var sizeNext = 0f
 
+        val previousBounceable = previousBounceable
         if (previousBounceable != null) {
             sizePrevious += bounceable.bounce.toPx() - previousBounceable.bounce.toPx()
         }
 
+        val nextBounceable = nextBounceable
         if (nextBounceable != null) {
             sizeNext += bounceable.bounce.toPx() - nextBounceable.bounce.toPx()
         } else if (bounceEnd) {
@@ -84,7 +134,7 @@
                 // constraints, otherwise the parent will automatically center this node given the
                 // size that it expects us to be. This allows us to then place the element where we
                 // want it to be.
-                layout(idleWidth, placeable.height) {
+                return layout(idleWidth, placeable.height) {
                     placeable.placeRelative(-sizePrevious.roundToInt(), 0)
                 }
             }
@@ -95,7 +145,7 @@
                     constraints.copy(minHeight = animatedHeight, maxHeight = animatedHeight)
 
                 val placeable = measurable.measure(animatedConstraints)
-                layout(placeable.width, idleHeight) {
+                return layout(placeable.width, idleHeight) {
                     placeable.placeRelative(0, -sizePrevious.roundToInt())
                 }
             }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/PagerDots.kt
similarity index 98%
rename from packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt
rename to packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/PagerDots.kt
index 91f1477..172d88a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PagerDots.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/common/ui/compose/PagerDots.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.qs.panels.ui.compose
+package com.android.systemui.common.ui.compose
 
 import androidx.compose.animation.core.animateDpAsState
 import androidx.compose.foundation.Canvas
@@ -43,9 +43,9 @@
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.LayoutDirection
 import androidx.compose.ui.unit.dp
+import com.android.app.tracing.coroutines.launchTraced as launch
 import kotlin.math.absoluteValue
 import kotlinx.coroutines.CoroutineScope
-import com.android.app.tracing.coroutines.launchTraced as launch
 import platform.test.motion.compose.values.MotionTestValueKey
 import platform.test.motion.compose.values.motionTestValues
 
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 4e1aab5..3150e94 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
@@ -182,7 +182,7 @@
         viewModel.communalBackground.collectAsStateWithLifecycle(
             initialValue = CommunalBackgroundType.ANIMATED
         )
-    val swipeToHubEnabled by viewModel.swipeToHubEnabled.collectAsStateWithLifecycle()
+    val swipeToHubEnabled by viewModel.swipeToHubEnabled.collectAsStateWithLifecycle(false)
     val state: MutableSceneTransitionLayoutState =
         rememberMutableSceneTransitionLayoutState(
             initialScene = currentSceneKey,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/compose/modifiers/SysuiTestTag.kt b/packages/SystemUI/compose/features/src/com/android/systemui/compose/modifiers/SysuiTestTag.kt
index 9eb78e1..b1afb161 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/compose/modifiers/SysuiTestTag.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/compose/modifiers/SysuiTestTag.kt
@@ -16,7 +16,7 @@
 
 package com.android.systemui.compose.modifiers
 
-import androidx.compose.ui.ExperimentalComposeUiApi
+import androidx.compose.runtime.Stable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.semantics.semantics
@@ -26,7 +26,11 @@
  * Set a test tag on this node so that it is associated with [resId]. This node will then be
  * accessible by integration tests using `sysuiResSelector(resId)`.
  */
-@OptIn(ExperimentalComposeUiApi::class)
+@Stable
 fun Modifier.sysuiResTag(resId: String): Modifier {
-    return this.semantics { testTagsAsResourceId = true }.testTag("com.android.systemui:id/$resId")
+    // TODO(b/372412931): Only compose the semantics modifier once, at the root of the SystemUI
+    // window.
+    return this.then(TestTagAsResourceIdModifier).testTag("com.android.systemui:id/$resId")
 }
+
+private val TestTagAsResourceIdModifier = Modifier.semantics { testTagsAsResourceId = true }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/row/BundleHeader.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/row/BundleHeader.kt
new file mode 100644
index 0000000..d7740a4
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/row/BundleHeader.kt
@@ -0,0 +1,193 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.notifications.ui.composable.row
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.platform.ComposeView
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.constrainHeight
+import androidx.compose.ui.unit.constrainWidth
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastForEach
+import androidx.compose.ui.util.fastMap
+import androidx.compose.ui.util.fastMaxOfOrDefault
+import androidx.compose.ui.util.fastSumBy
+import com.android.compose.animation.scene.ContentScope
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.theme.PlatformTheme
+import com.android.compose.ui.graphics.painter.rememberDrawablePainter
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.BundleHeaderViewModel
+
+object BundleHeader {
+    object Scenes {
+        val Collapsed = SceneKey("Collapsed")
+        val Expanded = SceneKey("Expanded")
+    }
+
+    object Elements {
+        val PreviewIcon1 = ElementKey("PreviewIcon1")
+        val PreviewIcon2 = ElementKey("PreviewIcon2")
+        val PreviewIcon3 = ElementKey("PreviewIcon3")
+        val TitleText = ElementKey("TitleText")
+    }
+}
+
+fun createComposeView(viewModel: BundleHeaderViewModel, context: Context): ComposeView {
+    // TODO(b/399588047): Check if we can init PlatformTheme once instead of once per ComposeView
+    return ComposeView(context).apply { setContent { PlatformTheme { BundleHeader(viewModel) } } }
+}
+
+@Composable
+fun BundleHeader(viewModel: BundleHeaderViewModel, modifier: Modifier = Modifier) {
+    Box(modifier) {
+        Background(background = viewModel.backgroundDrawable, modifier = Modifier.matchParentSize())
+        val scope = rememberCoroutineScope()
+        SceneTransitionLayout(
+            state = viewModel.state,
+            modifier =
+                Modifier.clickable(
+                    onClick = { viewModel.onHeaderClicked(scope) },
+                    interactionSource = null,
+                    indication = null,
+                ),
+        ) {
+            scene(BundleHeader.Scenes.Collapsed) {
+                BundleHeaderContent(viewModel, collapsed = true)
+            }
+            scene(BundleHeader.Scenes.Expanded) {
+                BundleHeaderContent(viewModel, collapsed = false)
+            }
+        }
+    }
+}
+
+@Composable
+private fun Background(background: Drawable?, modifier: Modifier = Modifier) {
+    if (background != null) {
+        val painter = rememberDrawablePainter(drawable = background)
+        Image(
+            painter = painter,
+            contentDescription = null,
+            contentScale = ContentScale.Crop,
+            modifier = modifier,
+        )
+    }
+}
+
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
+@Composable
+private fun ContentScope.BundleHeaderContent(
+    viewModel: BundleHeaderViewModel,
+    collapsed: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    Row(
+        verticalAlignment = Alignment.CenterVertically,
+        modifier = modifier.padding(vertical = 16.dp),
+    ) {
+        BundleIcon(viewModel.bundleIcon, modifier = Modifier.padding(horizontal = 16.dp))
+        Text(
+            text = viewModel.titleText,
+            style = MaterialTheme.typography.titleMediumEmphasized,
+            color = MaterialTheme.colorScheme.primary,
+            overflow = TextOverflow.Ellipsis,
+            maxLines = 1,
+            modifier = Modifier.element(BundleHeader.Elements.TitleText).weight(1f),
+        )
+
+        if (collapsed && viewModel.previewIcons.isNotEmpty()) {
+            BundlePreviewIcons(
+                previewDrawables = viewModel.previewIcons,
+                modifier = Modifier.padding(start = 8.dp),
+            )
+        }
+
+        ExpansionControl(
+            collapsed = collapsed,
+            hasUnread = viewModel.hasUnreadMessages,
+            numberToShow = viewModel.numberOfChildren,
+            modifier = Modifier.padding(start = 8.dp, end = 16.dp),
+        )
+    }
+}
+
+@Composable
+private fun ContentScope.BundlePreviewIcons(
+    previewDrawables: List<Drawable>,
+    modifier: Modifier = Modifier,
+) {
+    check(previewDrawables.isNotEmpty())
+    val iconSize = 32.dp
+    HalfOverlappingReversedRow(modifier = modifier) {
+        PreviewIcon(
+            drawable = previewDrawables[0],
+            modifier = Modifier.element(BundleHeader.Elements.PreviewIcon1).size(iconSize),
+        )
+        if (previewDrawables.size < 2) return@HalfOverlappingReversedRow
+        PreviewIcon(
+            drawable = previewDrawables[1],
+            modifier = Modifier.element(BundleHeader.Elements.PreviewIcon2).size(iconSize),
+        )
+        if (previewDrawables.size < 3) return@HalfOverlappingReversedRow
+        PreviewIcon(
+            drawable = previewDrawables[2],
+            modifier = Modifier.element(BundleHeader.Elements.PreviewIcon3).size(iconSize),
+        )
+    }
+}
+
+@Composable
+private fun HalfOverlappingReversedRow(
+    modifier: Modifier = Modifier,
+    content: @Composable () -> Unit,
+) {
+    Layout(modifier = modifier, content = content) { measurables, constraints ->
+        val placeables = measurables.fastMap { measurable -> measurable.measure(constraints) }
+
+        if (placeables.isEmpty())
+            return@Layout layout(constraints.minWidth, constraints.minHeight) {}
+        val width = placeables.fastSumBy { it.width / 2 } + placeables.first().width / 2
+        val childHeight = placeables.fastMaxOfOrDefault(0) { it.height }
+
+        layout(constraints.constrainWidth(width), constraints.constrainHeight(childHeight)) {
+            // Start in the middle of the right-most placeable
+            var currentXPosition = placeables.fastSumBy { it.width / 2 }
+            placeables.fastForEach { placeable ->
+                currentXPosition -= placeable.width / 2
+                placeable.placeRelative(x = currentXPosition, y = 0)
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/row/NotificationRowPrimitives.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/row/NotificationRowPrimitives.kt
new file mode 100644
index 0000000..c9ffa40
--- /dev/null
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/row/NotificationRowPrimitives.kt
@@ -0,0 +1,201 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.notifications.ui.composable.row
+
+import android.graphics.drawable.Drawable
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.border
+import androidx.compose.foundation.isSystemInDarkTheme
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.material.icons.Icons
+import androidx.compose.material.icons.filled.ExpandMore
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
+import androidx.compose.material3.Icon
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.ReadOnlyComposable
+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.draw.drawBehind
+import androidx.compose.ui.geometry.CornerRadius
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.platform.LocalDensity
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.unit.sp
+import com.android.compose.animation.scene.ContentScope
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.LowestZIndexContentPicker
+import com.android.compose.animation.scene.ValueKey
+import com.android.compose.animation.scene.animateElementColorAsState
+import com.android.compose.animation.scene.animateElementFloatAsState
+import com.android.compose.ui.graphics.painter.rememberDrawablePainter
+
+object NotificationRowPrimitives {
+    object Elements {
+        val PillBackground = ElementKey("PillBackground", contentPicker = LowestZIndexContentPicker)
+        val NotificationIconBackground = ElementKey("NotificationIconBackground")
+        val Chevron = ElementKey("Chevron")
+    }
+
+    object Values {
+        val ChevronRotation = ValueKey("NotificationChevronRotation")
+        val PillBackgroundColor = ValueKey("PillBackgroundColor")
+    }
+}
+
+/** The Icon displayed at the start of any notification row. */
+@Composable
+fun ContentScope.BundleIcon(drawable: Drawable?, modifier: Modifier = Modifier) {
+    val surfaceColor = notificationElementSurfaceColor()
+    Box(
+        modifier =
+            modifier
+                // Has to be a shared element because we may have semi-transparent background color
+                .element(NotificationRowPrimitives.Elements.NotificationIconBackground)
+                .size(40.dp)
+                .background(color = surfaceColor, shape = CircleShape)
+    ) {
+        if (drawable == null) return@Box
+        val painter = rememberDrawablePainter(drawable)
+        Image(
+            painter = painter,
+            contentDescription = null,
+            modifier = Modifier.padding(10.dp).fillMaxSize(),
+            contentScale = ContentScale.Fit,
+            colorFilter = ColorFilter.tint(MaterialTheme.colorScheme.primary),
+        )
+    }
+}
+
+/** The Icon used to display a preview of contained child notifications in a Bundle. */
+@Composable
+fun PreviewIcon(drawable: Drawable, modifier: Modifier = Modifier) {
+    val surfaceColor = notificationElementSurfaceColor()
+    Box(
+        modifier =
+            modifier
+                .background(color = surfaceColor, shape = CircleShape)
+                .border(0.5.dp, surfaceColor, CircleShape)
+    ) {
+        val painter = rememberDrawablePainter(drawable)
+        Image(
+            painter = painter,
+            contentDescription = null,
+            modifier = Modifier.fillMaxSize().clip(CircleShape),
+            contentScale = ContentScale.Fit,
+        )
+    }
+}
+
+/** The ExpansionControl of any expandable notification row, containing a Chevron. */
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
+@Composable
+fun ContentScope.ExpansionControl(
+    collapsed: Boolean,
+    hasUnread: Boolean,
+    numberToShow: Int?,
+    modifier: Modifier = Modifier,
+) {
+    val textColor =
+        if (hasUnread) MaterialTheme.colorScheme.onTertiary else MaterialTheme.colorScheme.onSurface
+    Box(modifier = modifier) {
+        // The background is a shared Element and therefore can't be the parent of a different
+        // shared Element (the chevron), otherwise the child can't be animated.
+        PillBackground(hasUnread, modifier = Modifier.matchParentSize())
+        Row(
+            verticalAlignment = Alignment.CenterVertically,
+            modifier = Modifier.padding(vertical = 2.dp, horizontal = 6.dp),
+        ) {
+            val iconSizeDp = with(LocalDensity.current) { 16.sp.toDp() }
+
+            if (numberToShow != null) {
+                Text(
+                    text = numberToShow.toString(),
+                    style = MaterialTheme.typography.labelSmallEmphasized,
+                    color = textColor,
+                    modifier = Modifier.padding(end = 2.dp),
+                )
+            }
+            Chevron(collapsed = collapsed, modifier = Modifier.size(iconSizeDp), color = textColor)
+        }
+    }
+}
+
+@Composable
+private fun ContentScope.PillBackground(hasUnread: Boolean, modifier: Modifier = Modifier) {
+    ElementWithValues(NotificationRowPrimitives.Elements.PillBackground, modifier) {
+        val bgColorNoUnread = notificationElementSurfaceColor()
+        val surfaceColor by
+            animateElementColorAsState(
+                if (hasUnread) MaterialTheme.colorScheme.tertiary else bgColorNoUnread,
+                NotificationRowPrimitives.Values.PillBackgroundColor,
+            )
+        content {
+            Box(
+                modifier =
+                    Modifier.drawBehind {
+                        drawRoundRect(
+                            color = surfaceColor,
+                            cornerRadius = CornerRadius(100.dp.toPx(), 100.dp.toPx()),
+                        )
+                    }
+            )
+        }
+    }
+}
+
+@Composable
+@ReadOnlyComposable
+private fun notificationElementSurfaceColor(): Color {
+    return if (isSystemInDarkTheme()) {
+        Color.White.copy(alpha = 0.15f)
+    } else {
+        MaterialTheme.colorScheme.surfaceContainerHighest
+    }
+}
+
+@Composable
+private fun ContentScope.Chevron(collapsed: Boolean, color: Color, modifier: Modifier = Modifier) {
+    val key = NotificationRowPrimitives.Elements.Chevron
+    ElementWithValues(key, modifier) {
+        val rotation by
+            animateElementFloatAsState(
+                if (collapsed) 0f else 180f,
+                NotificationRowPrimitives.Values.ChevronRotation,
+            )
+        content {
+            Icon(
+                imageVector = Icons.Default.ExpandMore,
+                contentDescription = null,
+                modifier = Modifier.graphicsLayer { rotationZ = rotation },
+                tint = color,
+            )
+        }
+    }
+}
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 60c01722..216f0a7 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
@@ -141,7 +141,7 @@
         mutableStateOf<FooterActionsForegroundServicesButtonViewModel?>(null)
     }
     var userSwitcher by remember { mutableStateOf<FooterActionsButtonViewModel?>(null) }
-    var power by remember { mutableStateOf<FooterActionsButtonViewModel?>(null) }
+    var power by remember { mutableStateOf(viewModel.initialPower()) }
 
     LaunchedEffect(
         context,
@@ -218,23 +218,19 @@
             }
 
             val useModifierBasedExpandable = remember { QSComposeFragment.isEnabled }
-            security?.let { SecurityButton(it, useModifierBasedExpandable, Modifier.weight(1f)) }
-            foregroundServices?.let { ForegroundServicesButton(it, useModifierBasedExpandable) }
-            userSwitcher?.let {
-                IconButton(
-                    it,
-                    useModifierBasedExpandable,
-                    Modifier.sysuiResTag("multi_user_switch"),
-                )
-            }
+            SecurityButton({ security }, useModifierBasedExpandable, Modifier.weight(1f))
+            ForegroundServicesButton({ foregroundServices }, useModifierBasedExpandable)
             IconButton(
-                viewModel.settings,
+                { userSwitcher },
+                useModifierBasedExpandable,
+                Modifier.sysuiResTag("multi_user_switch"),
+            )
+            IconButton(
+                { viewModel.settings },
                 useModifierBasedExpandable,
                 Modifier.sysuiResTag("settings_button_container"),
             )
-            power?.let {
-                IconButton(it, useModifierBasedExpandable, Modifier.sysuiResTag("pm_lite"))
-            }
+            IconButton({ power }, useModifierBasedExpandable, Modifier.sysuiResTag("pm_lite"))
         }
     }
 }
@@ -242,10 +238,11 @@
 /** The security button. */
 @Composable
 private fun SecurityButton(
-    model: FooterActionsSecurityButtonViewModel,
+    model: () -> FooterActionsSecurityButtonViewModel?,
     useModifierBasedExpandable: Boolean,
     modifier: Modifier = Modifier,
 ) {
+    val model = model() ?: return
     val onClick: ((Expandable) -> Unit)? =
         model.onClick?.let { onClick ->
             val context = LocalContext.current
@@ -265,9 +262,10 @@
 /** The foreground services button. */
 @Composable
 private fun RowScope.ForegroundServicesButton(
-    model: FooterActionsForegroundServicesButtonViewModel,
+    model: () -> FooterActionsForegroundServicesButtonViewModel?,
     useModifierBasedExpandable: Boolean,
 ) {
+    val model = model() ?: return
     if (model.displayText) {
         TextButton(
             Icon.Resource(R.drawable.ic_info_outline, contentDescription = null),
@@ -291,6 +289,17 @@
 /** A button with an icon. */
 @Composable
 fun IconButton(
+    model: () -> FooterActionsButtonViewModel?,
+    useModifierBasedExpandable: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    val model = model() ?: return
+    IconButton(model, useModifierBasedExpandable, modifier)
+}
+
+/** A button with an icon. */
+@Composable
+fun IconButton(
     model: FooterActionsButtonViewModel,
     useModifierBasedExpandable: Boolean,
     modifier: Modifier = Modifier,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
index 0f1cb40..a021626 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt
@@ -26,16 +26,19 @@
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.requiredHeight
 import androidx.compose.foundation.rememberScrollState
+import androidx.compose.foundation.systemGestureExclusion
 import androidx.compose.foundation.verticalScroll
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Rect
+import androidx.compose.ui.geometry.Size
 import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.layout.boundsInWindow
 import androidx.compose.ui.layout.onPlaced
@@ -46,6 +49,8 @@
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.UserAction
 import com.android.compose.animation.scene.UserActionResult
+import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.modifiers.thenIf
 import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.dagger.SysUISingleton
@@ -59,6 +64,7 @@
 import com.android.systemui.qs.panels.ui.compose.TileDetails
 import com.android.systemui.qs.panels.ui.compose.TileGrid
 import com.android.systemui.qs.panels.ui.compose.toolbar.Toolbar
+import com.android.systemui.qs.ui.composable.QuickSettingsShade.systemGestureExclusionInShade
 import com.android.systemui.qs.ui.viewmodel.QuickSettingsContainerViewModel
 import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayActionsViewModel
 import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayContentViewModel
@@ -255,8 +261,10 @@
                 viewModel = viewModel.brightnessSliderViewModel,
                 containerColor = OverlayShade.Colors.PanelBackground,
                 modifier =
-                    Modifier.fillMaxWidth()
-                        .height(QuickSettingsShade.Dimensions.BrightnessSliderHeight),
+                    Modifier.systemGestureExclusionInShade(
+                            enabled = { layoutState.transitionState is TransitionState.Idle }
+                        )
+                        .fillMaxWidth(),
             )
 
             Box {
@@ -280,6 +288,27 @@
     object Dimensions {
         val Padding = 16.dp
         val ToolbarHeight = 48.dp
-        val BrightnessSliderHeight = 64.dp
+    }
+
+    /**
+     * Applies system gesture exclusion to a component adding [Dimensions.Padding] to left and
+     * right.
+     */
+    @Composable
+    fun Modifier.systemGestureExclusionInShade(enabled: () -> Boolean): Modifier {
+        val density = LocalDensity.current
+        return thenIf(enabled()) {
+            Modifier.systemGestureExclusion { layoutCoordinates ->
+                val sidePadding = with(density) { Dimensions.Padding.toPx() }
+                Rect(
+                    offset = Offset(x = -sidePadding, y = 0f),
+                    size =
+                        Size(
+                            width = layoutCoordinates.size.width.toFloat() + 2 * sidePadding,
+                            height = layoutCoordinates.size.height.toFloat(),
+                        ),
+                )
+            }
+        }
     }
 }
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 0c502e6..7015f79 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
@@ -56,6 +56,7 @@
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.ui.view.SceneJankMonitor
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import com.android.systemui.shade.ui.composable.OverlayShade
 import com.android.systemui.shade.ui.composable.isFullWidthShade
 import javax.inject.Provider
 
@@ -100,9 +101,13 @@
         rememberActivated(traceName = "sceneJankMonitor") { sceneJankMonitorFactory.create() }
 
     val hapticFeedback = LocalHapticFeedback.current
+    val shadeExpansionMotion = OverlayShade.rememberShadeExpansionMotion()
     val sceneTransitions =
-        remember(hapticFeedback) {
-            transitionsBuilder.build(viewModel.hapticsViewModel.getRevealHaptics(hapticFeedback))
+        remember(hapticFeedback, shadeExpansionMotion) {
+            transitionsBuilder.build(
+                shadeExpansionMotion,
+                viewModel.hapticsViewModel.getRevealHaptics(hapticFeedback),
+            )
         }
 
     val state =
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
index 7fe19fe..9b45ef6 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt
@@ -6,6 +6,7 @@
 import com.android.compose.animation.scene.reveal.ContainerRevealHaptics
 import com.android.compose.animation.scene.transitions
 import com.android.internal.jank.Cuj
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
 import com.android.systemui.notifications.ui.composable.Notifications
 import com.android.systemui.scene.shared.model.Overlays
 import com.android.systemui.scene.shared.model.Scenes
@@ -48,7 +49,10 @@
  * Please keep the list sorted alphabetically.
  */
 class SceneContainerTransitions : SceneContainerTransitionsBuilder {
-    override fun build(revealHaptics: ContainerRevealHaptics): SceneTransitions {
+    override fun build(
+        shadeExpansionMotion: EdgeContainerExpansionSpec,
+        revealHaptics: ContainerRevealHaptics,
+    ): SceneTransitions {
         return transitions {
             interruptionHandler = DefaultInterruptionHandler
 
@@ -201,13 +205,19 @@
                 Overlays.NotificationsShade,
                 cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
             ) {
-                toNotificationsShadeTransition(revealHaptics = revealHaptics)
+                toNotificationsShadeTransition(
+                    shadeExpansionMotion = shadeExpansionMotion,
+                    revealHaptics = revealHaptics,
+                )
             }
             to(
                 Overlays.QuickSettingsShade,
                 cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
             ) {
-                toQuickSettingsShadeTransition(revealHaptics = revealHaptics)
+                toQuickSettingsShadeTransition(
+                    shadeExpansionMotion = shadeExpansionMotion,
+                    revealHaptics = revealHaptics,
+                )
             }
             from(
                 Scenes.Gone,
@@ -215,7 +225,11 @@
                 key = SlightlyFasterShadeCollapse,
                 cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
             ) {
-                toNotificationsShadeTransition(durationScale = 0.9, revealHaptics = revealHaptics)
+                toNotificationsShadeTransition(
+                    durationScale = 0.9,
+                    shadeExpansionMotion = shadeExpansionMotion,
+                    revealHaptics = revealHaptics,
+                )
             }
             from(
                 Scenes.Gone,
@@ -223,7 +237,11 @@
                 key = SlightlyFasterShadeCollapse,
                 cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
             ) {
-                toQuickSettingsShadeTransition(durationScale = 0.9, revealHaptics = revealHaptics)
+                toQuickSettingsShadeTransition(
+                    durationScale = 0.9,
+                    shadeExpansionMotion = shadeExpansionMotion,
+                    revealHaptics = revealHaptics,
+                )
             }
             from(
                 Scenes.Lockscreen,
@@ -231,7 +249,11 @@
                 key = SlightlyFasterShadeCollapse,
                 cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
             ) {
-                toNotificationsShadeTransition(durationScale = 0.9, revealHaptics = revealHaptics)
+                toNotificationsShadeTransition(
+                    durationScale = 0.9,
+                    shadeExpansionMotion = shadeExpansionMotion,
+                    revealHaptics = revealHaptics,
+                )
             }
             from(
                 Scenes.Lockscreen,
@@ -239,7 +261,11 @@
                 key = SlightlyFasterShadeCollapse,
                 cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
             ) {
-                toQuickSettingsShadeTransition(durationScale = 0.9, revealHaptics = revealHaptics)
+                toQuickSettingsShadeTransition(
+                    durationScale = 0.9,
+                    shadeExpansionMotion = shadeExpansionMotion,
+                    revealHaptics = revealHaptics,
+                )
             }
         }
     }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitionsBuilder.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitionsBuilder.kt
index 13d3456..eb5548d 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitionsBuilder.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitionsBuilder.kt
@@ -19,6 +19,7 @@
 import com.android.compose.animation.scene.SceneTransitions
 import com.android.compose.animation.scene.reveal.ContainerRevealHaptics
 import com.android.compose.animation.scene.transitions
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
 
 /**
  * Builder of the comprehensive definition of all transitions between scenes and overlays in the
@@ -27,7 +28,10 @@
 interface SceneContainerTransitionsBuilder {
 
     /** Build the [SceneContainer] transitions spec. */
-    fun build(revealHaptics: ContainerRevealHaptics): SceneTransitions
+    fun build(
+        shadeExpansionMotion: EdgeContainerExpansionSpec,
+        revealHaptics: ContainerRevealHaptics,
+    ): SceneTransitions
 }
 
 /**
@@ -37,5 +41,8 @@
 class ConstantSceneContainerTransitionsBuilder(
     private val transitions: SceneTransitions = transitions { /* No transitions */ }
 ) : SceneContainerTransitionsBuilder {
-    override fun build(revealHaptics: ContainerRevealHaptics): SceneTransitions = transitions
+    override fun build(
+        shadeExpansionMotion: EdgeContainerExpansionSpec,
+        revealHaptics: ContainerRevealHaptics,
+    ): SceneTransitions = transitions
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt
index 722af6a..9b4b91e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt
@@ -20,6 +20,7 @@
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.compose.animation.scene.reveal.ContainerRevealHaptics
 import com.android.compose.animation.scene.reveal.verticalContainerReveal
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
 import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys
 import com.android.systemui.notifications.ui.composable.NotificationsShade
 import com.android.systemui.scene.shared.model.Overlays
@@ -28,6 +29,7 @@
 
 fun TransitionBuilder.toNotificationsShadeTransition(
     durationScale: Double = 1.0,
+    shadeExpansionMotion: EdgeContainerExpansionSpec,
     revealHaptics: ContainerRevealHaptics,
 ) {
     spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
@@ -38,7 +40,7 @@
         elevateInContent = Overlays.NotificationsShade,
     )
 
-    verticalContainerReveal(NotificationsShade.Elements.Panel, revealHaptics)
+    verticalContainerReveal(NotificationsShade.Elements.Panel, shadeExpansionMotion, revealHaptics)
 
     fractionRange(end = .5f) { fade(OverlayShade.Elements.Scrim) }
     fractionRange(start = .5f) { fade(NotificationsShade.Elements.StatusBar) }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
index 3cce997..47dd85f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt
@@ -20,17 +20,19 @@
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.compose.animation.scene.reveal.ContainerRevealHaptics
 import com.android.compose.animation.scene.reveal.verticalContainerReveal
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
 import com.android.systemui.qs.ui.composable.QuickSettingsShade
 import com.android.systemui.shade.ui.composable.OverlayShade
 import kotlin.time.Duration.Companion.milliseconds
 
 fun TransitionBuilder.toQuickSettingsShadeTransition(
     durationScale: Double = 1.0,
+    shadeExpansionMotion: EdgeContainerExpansionSpec,
     revealHaptics: ContainerRevealHaptics,
 ) {
     spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
 
-    verticalContainerReveal(QuickSettingsShade.Elements.Panel, revealHaptics)
+    verticalContainerReveal(QuickSettingsShade.Elements.Panel, shadeExpansionMotion, revealHaptics)
 
     fractionRange(end = .5f) { fade(OverlayShade.Elements.Scrim) }
     fractionRange(start = .5f) { fade(QuickSettingsShade.Elements.StatusBar) }
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 7e7b629..3446081 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
@@ -37,24 +37,26 @@
 import androidx.compose.foundation.layout.waterfall
 import androidx.compose.foundation.layout.width
 import androidx.compose.foundation.overscroll
-import androidx.compose.foundation.shape.RoundedCornerShape
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.material3.windowsizeclass.WindowWidthSizeClass
 import androidx.compose.runtime.Composable
 import androidx.compose.runtime.ReadOnlyComposable
+import androidx.compose.runtime.remember
 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.platform.LocalLayoutDirection
 import androidx.compose.ui.res.dimensionResource
+import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.ContentScope
 import com.android.compose.animation.scene.ElementKey
 import com.android.compose.animation.scene.LowestZIndexContentPicker
 import com.android.compose.windowsizeclass.LocalWindowSizeClass
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
+import com.android.mechanics.behavior.edgeContainerExpansionBackground
 import com.android.systemui.res.R
-import androidx.compose.ui.unit.Dp
+import com.android.systemui.shade.ui.composable.OverlayShade.rememberShadeExpansionMotion
 
 /** Renders a lightweight shade UI container, as an overlay. */
 @Composable
@@ -110,23 +112,15 @@
 ) {
     Box(
         modifier =
-            modifier.clip(OverlayShade.Shapes.RoundedCornerPanel).disableSwipesWhenScrolling()
+            modifier
+                .disableSwipesWhenScrolling()
+                .edgeContainerExpansionBackground(
+                    OverlayShade.Colors.PanelBackground,
+                    rememberShadeExpansionMotion(),
+                )
     ) {
-        Spacer(
-            modifier =
-                Modifier.element(OverlayShade.Elements.PanelBackground)
-                    .matchParentSize()
-                    .background(
-                        color = OverlayShade.Colors.PanelBackground,
-                        shape = OverlayShade.Shapes.RoundedCornerPanel,
-                    )
-        )
-
         Column {
             header?.invoke()
-
-            // This content is intentionally rendered as a separate element from the background in
-            // order to allow for more flexibility when defining transitions.
             content()
         }
     }
@@ -192,8 +186,6 @@
                 contentPicker = LowestZIndexContentPicker,
                 placeAllCopies = true,
             )
-        val PanelBackground =
-            ElementKey("OverlayShadePanelBackground", contentPicker = LowestZIndexContentPicker)
     }
 
     object Colors {
@@ -205,13 +197,13 @@
     object Dimensions {
         val PanelCornerRadius: Dp
             @Composable
-            @ReadOnlyComposable get() =
-                dimensionResource(R.dimen.overlay_shade_panel_shape_radius)
+            @ReadOnlyComposable
+            get() = dimensionResource(R.dimen.overlay_shade_panel_shape_radius)
     }
 
-    object Shapes {
-        val RoundedCornerPanel: RoundedCornerShape
-            @Composable
-            @ReadOnlyComposable get() = RoundedCornerShape(Dimensions.PanelCornerRadius)
+    @Composable
+    fun rememberShadeExpansionMotion(): EdgeContainerExpansionSpec {
+        val radius = Dimensions.PanelCornerRadius
+        return remember(radius) { EdgeContainerExpansionSpec(radius = radius) }
     }
 }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
index 404f1b2..22688d3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayout.kt
@@ -102,6 +102,7 @@
         key: SceneKey,
         userActions: Map<UserAction, UserActionResult> = emptyMap(),
         effectFactory: OverscrollFactory? = null,
+        alwaysCompose: Boolean = false,
         content: @Composable CS.() -> Unit,
     )
 
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
index e3c4eb0..4da83c3 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/SceneTransitionLayoutImpl.kt
@@ -207,6 +207,9 @@
     private val nestedScrollDispatcher = NestedScrollDispatcher()
     private val nestedScrollConnection = object : NestedScrollConnection {}
 
+    // TODO(b/399825091): Remove this.
+    private var scenesToAlwaysCompose: MutableList<Scene>? = null
+
     init {
         updateContents(builder, layoutDirection, defaultEffectFactory)
 
@@ -312,6 +315,7 @@
                     key: SceneKey,
                     userActions: Map<UserAction, UserActionResult>,
                     effectFactory: OverscrollFactory?,
+                    alwaysCompose: Boolean,
                     content: @Composable InternalContentScope.() -> Unit,
                 ) {
                     require(!overlaysDefined) { "all scenes must be defined before overlays" }
@@ -324,6 +328,10 @@
                         Content.calculateGlobalZIndex(parentZIndex, ++zIndex, ancestors.size)
                     val factory = effectFactory ?: defaultEffectFactory
                     if (scene != null) {
+                        check(alwaysCompose == scene.alwaysCompose) {
+                            "scene.alwaysCompose can not change"
+                        }
+
                         // Update an existing scene.
                         scene.content = content
                         scene.userActions = resolvedUserActions
@@ -332,7 +340,7 @@
                         scene.maybeUpdateEffects(factory)
                     } else {
                         // New scene.
-                        scenes[key] =
+                        val scene =
                             Scene(
                                 key,
                                 this@SceneTransitionLayoutImpl,
@@ -341,7 +349,16 @@
                                 zIndex.toFloat(),
                                 globalZIndex,
                                 factory,
+                                alwaysCompose,
                             )
+
+                        scenes[key] = scene
+
+                        if (alwaysCompose) {
+                            (scenesToAlwaysCompose
+                                    ?: mutableListOf<Scene>().also { scenesToAlwaysCompose = it })
+                                .add(scene)
+                        }
                     }
                 }
 
@@ -470,22 +487,24 @@
 
     @Composable
     private fun Scenes() {
-        scenesToCompose().fastForEach { scene -> key(scene.key) { scene.Content() } }
+        scenesToCompose().fastForEach { (scene, isInvisible) ->
+            key(scene.key) { scene.Content(isInvisible = isInvisible) }
+        }
     }
 
-    private fun scenesToCompose(): List<Scene> {
+    private fun scenesToCompose(): List<SceneToCompose> {
         val transitions = state.currentTransitions
-        return if (transitions.isEmpty()) {
-            listOf(scene(state.transitionState.currentScene))
-        } else {
-            buildList {
-                val visited = mutableSetOf<SceneKey>()
-                fun maybeAdd(sceneKey: SceneKey) {
-                    if (visited.add(sceneKey)) {
-                        add(scene(sceneKey))
-                    }
+        return buildList {
+            val visited = mutableSetOf<SceneKey>()
+            fun maybeAdd(sceneKey: SceneKey, isInvisible: Boolean = false) {
+                if (visited.add(sceneKey)) {
+                    add(SceneToCompose(scene(sceneKey), isInvisible))
                 }
+            }
 
+            if (transitions.isEmpty()) {
+                maybeAdd(state.transitionState.currentScene)
+            } else {
                 // Compose the new scene we are going to first.
                 transitions.fastForEachReversed { transition ->
                     when (transition) {
@@ -504,9 +523,13 @@
                 // Make sure that the current scene is always composed.
                 maybeAdd(transitions.last().currentScene)
             }
+
+            scenesToAlwaysCompose?.fastForEach { maybeAdd(it.key, isInvisible = true) }
         }
     }
 
+    private data class SceneToCompose(val scene: Scene, val isInvisible: Boolean)
+
     @Composable
     private fun BoxScope.Overlays() {
         val overlaysOrderedByZIndex = overlaysToComposeOrderedByZIndex()
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
index 149a9e7..72ee75a 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Content.kt
@@ -34,6 +34,7 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.layout.LookaheadScope
 import androidx.compose.ui.layout.approachLayout
+import androidx.compose.ui.layout.layout
 import androidx.compose.ui.platform.testTag
 import androidx.compose.ui.unit.IntSize
 import androidx.compose.ui.zIndex
@@ -154,11 +155,12 @@
 
     @SuppressLint("NotConstructor")
     @Composable
-    fun Content(modifier: Modifier = Modifier) {
+    fun Content(modifier: Modifier = Modifier, isInvisible: Boolean = false) {
         // If this content has a custom factory, provide it to the content so that the factory is
         // automatically used when calling rememberOverscrollEffect().
         Box(
             modifier
+                .thenIf(isInvisible) { InvisibleModifier }
                 .zIndex(zIndex)
                 .approachLayout(
                     isMeasurementApproachInProgress = { layoutImpl.state.isTransitioning() }
@@ -305,3 +307,8 @@
         )
     }
 }
+
+private val InvisibleModifier =
+    Modifier.layout { measurable, constraints ->
+        measurable.measure(constraints).run { layout(width, height) {} }
+    }
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Scene.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Scene.kt
index 7f57798..38acd4b 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Scene.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/Scene.kt
@@ -35,6 +35,7 @@
     zIndex: Float,
     globalZIndex: Long,
     effectFactory: OverscrollFactory,
+    val alwaysCompose: Boolean,
 ) : Content(key, layoutImpl, content, actions, zIndex, globalZIndex, effectFactory) {
     override fun toString(): String {
         return "Scene(key=$key)"
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
index e23e234..312dd77 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/content/state/TransitionState.kt
@@ -22,6 +22,8 @@
 import androidx.compose.runtime.Stable
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
 import com.android.compose.animation.scene.OverlayKey
@@ -241,6 +243,15 @@
         /** Additional gesture context whenever the transition is driven by a user gesture. */
         abstract val gestureContext: GestureContext?
 
+        /**
+         * True when the transition reached the end and the progress won't be updated anymore.
+         *
+         * [isProgressStable] will be `true` before this [Transition] is completed while there are
+         * still custom transition animations settling.
+         */
+        var isProgressStable: Boolean by mutableStateOf(false)
+            private set
+
         /** The CUJ covered by this transition. */
         @CujType
         val cuj: Int?
@@ -372,7 +383,11 @@
             check(_coroutineScope == null) { "A Transition can be started only once." }
             coroutineScope {
                 _coroutineScope = this
-                run()
+                try {
+                    run()
+                } finally {
+                    isProgressStable = true
+                }
             }
         }
 
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/mechanics/TransitionScopedMechanicsAdapter.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/mechanics/TransitionScopedMechanicsAdapter.kt
new file mode 100644
index 0000000..ac8a8c0
--- /dev/null
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/mechanics/TransitionScopedMechanicsAdapter.kt
@@ -0,0 +1,135 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.mechanics
+
+import androidx.annotation.VisibleForTesting
+import androidx.compose.runtime.mutableFloatStateOf
+import com.android.compose.animation.scene.ContentKey
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.ElementStateScope
+import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
+import com.android.compose.animation.scene.transformation.PropertyTransformationScope
+import com.android.mechanics.MotionValue
+import com.android.mechanics.ProvidedGestureContext
+import com.android.mechanics.spec.InputDirection
+import com.android.mechanics.spec.MotionSpec
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Callback to create a [MotionSpec] on the first call to [CustomPropertyTransformation.transform]
+ */
+typealias SpecFactory =
+    PropertyTransformationScope.(content: ContentKey, element: ElementKey) -> MotionSpec
+
+/** Callback to compute the [MotionValue] per frame */
+typealias MotionValueInput =
+    PropertyTransformationScope.(progress: Float, content: ContentKey, element: ElementKey) -> Float
+
+/**
+ * Adapter to create a [MotionValue] and `keepRunning()` it temporarily while a
+ * [CustomPropertyTransformation] is in progress and until the animation settles.
+ *
+ * The [MotionValue]'s input is by default the transition progress.
+ */
+internal class TransitionScopedMechanicsAdapter(
+    private val computeInput: MotionValueInput = { progress, _, _ -> progress },
+    private val stableThreshold: Float = MotionValue.StableThresholdEffect,
+    private val label: String? = null,
+    private val createSpec: SpecFactory,
+) {
+
+    private val input = mutableFloatStateOf(0f)
+    private var motionValue: MotionValue? = null
+
+    fun PropertyTransformationScope.update(
+        content: ContentKey,
+        element: ElementKey,
+        transition: TransitionState.Transition,
+        transitionScope: CoroutineScope,
+    ): Float {
+        val progress = transition.progressTo(content)
+        input.floatValue = computeInput(progress, content, element)
+        var motionValue = motionValue
+
+        if (motionValue == null) {
+            motionValue =
+                MotionValue(
+                    input::floatValue,
+                    transition.gestureContext
+                        ?: ProvidedGestureContext(
+                            0f,
+                            appearDirection(content, element, transition),
+                        ),
+                    createSpec(content, element),
+                    stableThreshold = stableThreshold,
+                    label = label,
+                )
+            this@TransitionScopedMechanicsAdapter.motionValue = motionValue
+
+            transitionScope.launch {
+                motionValue.keepRunningWhile { !transition.isProgressStable || !isStable }
+            }
+        }
+
+        return motionValue.output
+    }
+
+    companion object {
+        /**
+         * Computes the InputDirection for a triggered transition of an element appearing /
+         * disappearing.
+         *
+         * Since [CustomPropertyTransformation] are only supported for non-shared elements, the
+         * [TransitionScopedMechanicsAdapter] is only used in the context of an element appearing /
+         * disappearing. This helper computes the direction to result in [InputDirection.Max] for an
+         * appear transition, and [InputDirection.Min] for a disappear transition.
+         */
+        @VisibleForTesting
+        internal fun ElementStateScope.appearDirection(
+            content: ContentKey,
+            element: ElementKey,
+            transition: TransitionState.Transition,
+        ): InputDirection {
+            check(!transition.isInitiatedByUserInput)
+
+            val inMaxDirection =
+                when (transition) {
+                    is TransitionState.Transition.ChangeScene -> {
+                        val transitionTowardsContent = content == transition.toContent
+                        val elementInContent = element.targetSize(content) != null
+                        val isReversed = transition.currentScene != transition.toScene
+                        (transitionTowardsContent xor elementInContent) xor !isReversed
+                    }
+
+                    is TransitionState.Transition.ShowOrHideOverlay -> {
+                        val transitioningTowardsOverlay = transition.overlay == transition.toContent
+                        val isReversed =
+                            transitioningTowardsOverlay xor transition.isEffectivelyShown
+                        transitioningTowardsOverlay xor isReversed
+                    }
+
+                    is TransitionState.Transition.ReplaceOverlay -> {
+                        transition.effectivelyShownOverlay == content
+                    }
+                }
+
+            return if (inMaxDirection) InputDirection.Max else InputDirection.Min
+        }
+    }
+}
diff --git a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt
index 2134510..72f9bd5 100644
--- a/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt
+++ b/packages/SystemUI/compose/scene/src/com/android/compose/animation/scene/reveal/ContainerReveal.kt
@@ -16,28 +16,20 @@
 
 package com.android.compose.animation.scene.reveal
 
-import androidx.compose.animation.core.AnimationVector1D
-import androidx.compose.animation.core.DeferredTargetAnimation
-import androidx.compose.animation.core.ExperimentalAnimatableApi
-import androidx.compose.animation.core.FiniteAnimationSpec
-import androidx.compose.animation.core.VectorConverter
-import androidx.compose.animation.core.spring
-import androidx.compose.ui.unit.Dp
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
 import androidx.compose.ui.unit.IntSize
-import androidx.compose.ui.unit.dp
-import androidx.compose.ui.util.fastCoerceAtLeast
-import androidx.compose.ui.util.fastCoerceAtMost
 import com.android.compose.animation.scene.ContentKey
 import com.android.compose.animation.scene.ElementKey
-import com.android.compose.animation.scene.OverlayKey
-import com.android.compose.animation.scene.SceneKey
 import com.android.compose.animation.scene.TransitionBuilder
 import com.android.compose.animation.scene.UserActionDistance
 import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.mechanics.MotionValueInput
+import com.android.compose.animation.scene.mechanics.TransitionScopedMechanicsAdapter
 import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
 import com.android.compose.animation.scene.transformation.PropertyTransformation
 import com.android.compose.animation.scene.transformation.PropertyTransformationScope
-import kotlin.math.roundToInt
+import com.android.mechanics.MotionValue
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
 import kotlinx.coroutines.CoroutineScope
 
 interface ContainerRevealHaptics {
@@ -53,9 +45,15 @@
     fun onRevealThresholdCrossed(revealed: Boolean)
 }
 
-/** Animate the reveal of [container] by animating its size. */
+/**
+ * Animate the reveal of [container] by animating its size.
+ *
+ * This implicitly sets the [distance] of the transition to the target size of [container]
+ */
+@OptIn(ExperimentalMaterial3ExpressiveApi::class)
 fun TransitionBuilder.verticalContainerReveal(
     container: ElementKey,
+    motionSpec: EdgeContainerExpansionSpec,
     haptics: ContainerRevealHaptics,
 ) {
     // Make the swipe distance be exactly the target height of the container.
@@ -76,188 +74,73 @@
         (targetSizeInToContent?.height ?: targetSizeInFromContent?.height)?.toFloat() ?: 0f
     }
 
-    // TODO(b/376438969): Improve the motion of this gesture using Motion Mechanics.
-
-    // The min distance to swipe before triggering the reveal spring.
-    val distanceThreshold = 80.dp
-
-    // The minimum height of the container.
-    val minHeight = 10.dp
-
-    // The amount removed from the container width at 0% progress.
-    val widthDelta = 140.dp
-
-    // The ratio at which the distance is tracked before reaching the threshold, e.g. if the user
-    // drags 60dp then the height will be 60dp * 0.25f = 15dp.
-    val trackingRatio = 0.25f
-
-    // The max progress starting from which the container should always be visible, even if we are
-    // animating the container out. This is used so that we don't immediately fade out the container
-    // when triggering a one-off animation that hides it.
-    val alphaProgressThreshold = 0.05f
-
-    // The spring animating the size of the container.
-    val sizeSpec = spring<Float>(stiffness = 380f, dampingRatio = 0.9f)
-
-    // The spring animating the alpha of the container.
-    val alphaSpec = spring<Float>(stiffness = 1200f, dampingRatio = 0.99f)
-
-    // Size transformation.
-    transformation(container) {
-        VerticalContainerRevealSizeTransformation(
-            haptics,
-            distanceThreshold,
-            trackingRatio,
-            minHeight,
-            widthDelta,
-            sizeSpec,
-        )
-    }
-
-    // Alpha transformation.
-    transformation(container) {
-        ContainerRevealAlphaTransformation(alphaSpec, alphaProgressThreshold)
-    }
-}
-
-@OptIn(ExperimentalAnimatableApi::class)
-private class VerticalContainerRevealSizeTransformation(
-    private val haptics: ContainerRevealHaptics,
-    private val distanceThreshold: Dp,
-    private val trackingRatio: Float,
-    private val minHeight: Dp,
-    private val widthDelta: Dp,
-    private val spec: FiniteAnimationSpec<Float>,
-) : CustomPropertyTransformation<IntSize> {
-    override val property = PropertyTransformation.Property.Size
-
-    private val widthAnimation = DeferredTargetAnimation(Float.VectorConverter)
-    private val heightAnimation = DeferredTargetAnimation(Float.VectorConverter)
-
-    private var previousHasReachedThreshold: Boolean? = null
-
-    override fun PropertyTransformationScope.transform(
-        content: ContentKey,
-        element: ElementKey,
-        transition: TransitionState.Transition,
-        transitionScope: CoroutineScope,
-    ): IntSize {
-        // The distance to go to 100%. Note that we don't use
-        // TransitionState.HasOverscrollProperties.absoluteDistance because the transition will not
-        // implement HasOverscrollProperties if the transition is triggered and not gesture based.
+    // TODO(b/392534646) Add haptics back
+    val heightInput: MotionValueInput = { progress, content, element ->
         val idleSize = checkNotNull(element.targetSize(content))
-        val userActionDistance = idleSize.height
-        val progress = transition.progressTo(content)
-        val distance = (progress * userActionDistance).fastCoerceAtLeast(0f)
-        val threshold = distanceThreshold.toPx()
-
-        // Width.
-        val widthDelta = widthDelta.toPx()
-        val width =
-            (idleSize.width - widthDelta +
-                    animateSize(
-                        size = widthDelta,
-                        distance = distance,
-                        threshold = threshold,
-                        transitionScope = transitionScope,
-                        animation = widthAnimation,
-                    ))
-                .roundToInt()
-
-        // Height.
-        val minHeight = minHeight.toPx()
-        val height =
-            (
-                // 1) The minimum size of the container.
-                minHeight +
-
-                    // 2) The animated size between the minimum size and the threshold.
-                    animateSize(
-                        size = threshold - minHeight,
-                        distance = distance,
-                        threshold = threshold,
-                        transitionScope = transitionScope,
-                        animation = heightAnimation,
-                    ) +
-
-                    // 3) The remaining height after the threshold, tracking the finger.
-                    (distance - threshold).fastCoerceAtLeast(0f))
-                .roundToInt()
-                .fastCoerceAtMost(idleSize.height)
-
-        // Haptics.
-        val hasReachedThreshold = distance >= threshold
-        if (
-            previousHasReachedThreshold != null &&
-                hasReachedThreshold != previousHasReachedThreshold &&
-                transition.isUserInputOngoing
-        ) {
-            haptics.onRevealThresholdCrossed(revealed = hasReachedThreshold)
-        }
-        previousHasReachedThreshold = hasReachedThreshold
-
-        return IntSize(width = width, height = height)
+        val targetHeight = idleSize.height.toFloat()
+        targetHeight * progress
     }
 
-    /**
-     * Animate a size up to [size], so that it is equal to 0f when distance is 0f and equal to
-     * [size] when `distance >= threshold`, taking the [trackingRatio] into account.
-     */
-    @OptIn(ExperimentalAnimatableApi::class)
-    private fun animateSize(
-        size: Float,
-        distance: Float,
-        threshold: Float,
-        transitionScope: CoroutineScope,
-        animation: DeferredTargetAnimation<Float, AnimationVector1D>,
-    ): Float {
-        val trackingSize = distance.fastCoerceAtMost(threshold) / threshold * size * trackingRatio
-        val springTarget =
-            if (distance >= threshold) {
-                size * (1f - trackingRatio)
-            } else {
-                0f
+    transformation(container) {
+        object : CustomPropertyTransformation<IntSize> {
+            override val property = PropertyTransformation.Property.Size
+
+            val heightValue =
+                TransitionScopedMechanicsAdapter(
+                    computeInput = heightInput,
+                    stableThreshold = MotionValue.StableThresholdSpatial,
+                    label = "verticalContainerReveal::height",
+                ) { _, _ ->
+                    motionSpec.createHeightSpec(motionScheme, density = this)
+                }
+            val widthValue =
+                TransitionScopedMechanicsAdapter(
+                    computeInput = heightInput,
+                    stableThreshold = MotionValue.StableThresholdSpatial,
+                    label = "verticalContainerReveal::width",
+                ) { content, element ->
+                    val idleSize = checkNotNull(element.targetSize(content))
+                    val intrinsicWidth = idleSize.width.toFloat()
+                    motionSpec.createWidthSpec(intrinsicWidth, motionScheme, density = this)
+                }
+
+            override fun PropertyTransformationScope.transform(
+                content: ContentKey,
+                element: ElementKey,
+                transition: TransitionState.Transition,
+                transitionScope: CoroutineScope,
+            ): IntSize {
+
+                val height =
+                    with(heightValue) { update(content, element, transition, transitionScope) }
+                val width =
+                    with(widthValue) { update(content, element, transition, transitionScope) }
+
+                return IntSize(width.toInt(), height.toInt())
             }
-        val springSize = animation.updateTarget(springTarget, transitionScope, spec)
-        return trackingSize + springSize
-    }
-}
-
-@OptIn(ExperimentalAnimatableApi::class)
-private class ContainerRevealAlphaTransformation(
-    private val spec: FiniteAnimationSpec<Float>,
-    private val progressThreshold: Float,
-) : CustomPropertyTransformation<Float> {
-    override val property = PropertyTransformation.Property.Alpha
-    private val alphaAnimation = DeferredTargetAnimation(Float.VectorConverter)
-
-    override fun PropertyTransformationScope.transform(
-        content: ContentKey,
-        element: ElementKey,
-        transition: TransitionState.Transition,
-        transitionScope: CoroutineScope,
-    ): Float {
-        return alphaAnimation.updateTarget(targetAlpha(transition, content), transitionScope, spec)
-    }
-
-    private fun targetAlpha(transition: TransitionState.Transition, content: ContentKey): Float {
-        if (transition.isUserInputOngoing) {
-            return if (transition.progressTo(content) > 0f) 1f else 0f
         }
+    }
 
-        // The transition was committed (the user released their finger), so the alpha depends on
-        // whether we are animating towards the content (showing the container) or away from it
-        // (hiding the container).
-        val isShowingContainer =
-            when (content) {
-                is SceneKey -> transition.currentScene == content
-                is OverlayKey -> transition.currentOverlays.contains(content)
+    transformation(container) {
+        object : CustomPropertyTransformation<Float> {
+
+            override val property = PropertyTransformation.Property.Alpha
+            val alphaValue =
+                TransitionScopedMechanicsAdapter(
+                    computeInput = heightInput,
+                    label = "verticalContainerReveal::alpha",
+                ) { _, _ ->
+                    motionSpec.createAlphaSpec(motionScheme, density = this)
+                }
+
+            override fun PropertyTransformationScope.transform(
+                content: ContentKey,
+                element: ElementKey,
+                transition: TransitionState.Transition,
+                transitionScope: CoroutineScope,
+            ): Float {
+                return with(alphaValue) { update(content, element, transition, transitionScope) }
             }
-
-        return if (isShowingContainer || transition.progressTo(content) >= progressThreshold) {
-            1f
-        } else {
-            0f
         }
     }
 }
diff --git a/packages/SystemUI/compose/scene/tests/goldens/motionValue_interruptedAnimation_completes.json b/packages/SystemUI/compose/scene/tests/goldens/motionValue_interruptedAnimation_completes.json
new file mode 100644
index 0000000..a2f8863
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/motionValue_interruptedAnimation_completes.json
@@ -0,0 +1,68 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    "after"
+  ],
+  "features": [
+    {
+      "name": "Foo_yOffset",
+      "type": "float",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        125,
+        125,
+        124.28647,
+        107.02858,
+        81.95502,
+        0,
+        0,
+        0,
+        0,
+        7.2947845,
+        30.375374,
+        55.12497,
+        75.944496,
+        91.69751,
+        102.92622,
+        110.62873,
+        115.772865,
+        119.141266,
+        121.313736,
+        122.69816,
+        123.57184,
+        124.11877,
+        {
+          "type": "not_found"
+        }
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/motionValue_withAnimation_prolongsTransition.json b/packages/SystemUI/compose/scene/tests/goldens/motionValue_withAnimation_prolongsTransition.json
new file mode 100644
index 0000000..bda53bbf
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/motionValue_withAnimation_prolongsTransition.json
@@ -0,0 +1,48 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    "after"
+  ],
+  "features": [
+    {
+      "name": "Foo_yOffset",
+      "type": "float",
+      "data_points": [
+        125,
+        125,
+        125,
+        125,
+        111.61491,
+        86.9892,
+        63.112034,
+        43.8049,
+        29.501678,
+        19.439606,
+        12.599068,
+        8.06028,
+        5.102936,
+        3.2029724,
+        1.9959946,
+        1.2362518,
+        0.761673,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/motionValue_withoutAnimation_terminatesImmediately.json b/packages/SystemUI/compose/scene/tests/goldens/motionValue_withoutAnimation_terminatesImmediately.json
new file mode 100644
index 0000000..7def82f
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/motionValue_withoutAnimation_terminatesImmediately.json
@@ -0,0 +1,26 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    "after"
+  ],
+  "features": [
+    {
+      "name": "Foo_yOffset",
+      "type": "float",
+      "data_points": [
+        125,
+        104.166664,
+        83.33333,
+        62.5,
+        41.666664,
+        20.833336,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeEnter.json b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeEnter.json
index 2df44091..054b4a1 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeEnter.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeEnter.json
@@ -20,7 +20,7 @@
           "height": 100
         },
         {
-          "width": 125.14286,
+          "width": 125.2,
           "height": 90
         },
         {
@@ -28,7 +28,7 @@
           "height": 80
         },
         {
-          "width": 175.14285,
+          "width": 175.2,
           "height": 70
         },
         {
diff --git a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeExit.json b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeExit.json
index 2b0a954..ad46a8d 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeExit.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredSizeExit.json
@@ -21,7 +21,7 @@
           "height": 100
         },
         {
-          "width": 125.14286,
+          "width": 125.2,
           "height": 90
         },
         {
@@ -29,7 +29,7 @@
           "height": 80
         },
         {
-          "width": 175.14285,
+          "width": 175.2,
           "height": 70
         },
         {
diff --git a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredWidthOnly.json b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredWidthOnly.json
index 027df29..9a97053 100644
--- a/packages/SystemUI/compose/scene/tests/goldens/testAnchoredWidthOnly.json
+++ b/packages/SystemUI/compose/scene/tests/goldens/testAnchoredWidthOnly.json
@@ -20,7 +20,7 @@
           "height": 60
         },
         {
-          "width": 125.14286,
+          "width": 125.2,
           "height": 60
         },
         {
@@ -28,7 +28,7 @@
           "height": 60
         },
         {
-          "width": 175.14285,
+          "width": 175.2,
           "height": 60
         },
         {
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragFullyClose.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragFullyClose.json
new file mode 100644
index 0000000..0fcdfa3
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragFullyClose.json
@@ -0,0 +1,634 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432,
+    448,
+    464,
+    480,
+    496,
+    512,
+    528,
+    544,
+    560,
+    576,
+    592,
+    608,
+    624,
+    640,
+    656,
+    672,
+    688,
+    704,
+    720,
+    736,
+    752,
+    768,
+    784,
+    800,
+    816,
+    832,
+    848,
+    864,
+    880,
+    896,
+    912,
+    928,
+    944,
+    960
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50.4
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 52.4,
+          "y": 50
+        },
+        {
+          "x": 56,
+          "y": 50
+        },
+        {
+          "x": 58.8,
+          "y": 50
+        },
+        {
+          "x": 60.8,
+          "y": 50
+        },
+        {
+          "x": 62,
+          "y": 50
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 63.6,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 393.2
+        },
+        {
+          "width": 188,
+          "height": 393.2
+        },
+        {
+          "width": 188,
+          "height": 386
+        },
+        {
+          "width": 188,
+          "height": 379.6
+        },
+        {
+          "width": 188,
+          "height": 372.8
+        },
+        {
+          "width": 188,
+          "height": 366.8
+        },
+        {
+          "width": 188,
+          "height": 360.4
+        },
+        {
+          "width": 188,
+          "height": 354
+        },
+        {
+          "width": 188,
+          "height": 347.6
+        },
+        {
+          "width": 188,
+          "height": 341.2
+        },
+        {
+          "width": 188,
+          "height": 341.2
+        },
+        {
+          "width": 188,
+          "height": 334
+        },
+        {
+          "width": 188,
+          "height": 328
+        },
+        {
+          "width": 188,
+          "height": 321.6
+        },
+        {
+          "width": 188,
+          "height": 315.2
+        },
+        {
+          "width": 188,
+          "height": 308.8
+        },
+        {
+          "width": 188,
+          "height": 302.4
+        },
+        {
+          "width": 188,
+          "height": 296
+        },
+        {
+          "width": 188,
+          "height": 289.6
+        },
+        {
+          "width": 188,
+          "height": 289.6
+        },
+        {
+          "width": 188,
+          "height": 282.8
+        },
+        {
+          "width": 188,
+          "height": 276.4
+        },
+        {
+          "width": 188,
+          "height": 270
+        },
+        {
+          "width": 188,
+          "height": 263.6
+        },
+        {
+          "width": 188,
+          "height": 257.2
+        },
+        {
+          "width": 188,
+          "height": 250.8
+        },
+        {
+          "width": 188,
+          "height": 244.4
+        },
+        {
+          "width": 188,
+          "height": 238
+        },
+        {
+          "width": 188,
+          "height": 238
+        },
+        {
+          "width": 188,
+          "height": 231.2
+        },
+        {
+          "width": 188,
+          "height": 224.8
+        },
+        {
+          "width": 188,
+          "height": 218.4
+        },
+        {
+          "width": 188,
+          "height": 212
+        },
+        {
+          "width": 188,
+          "height": 212
+        },
+        {
+          "width": 188,
+          "height": 192.4
+        },
+        {
+          "width": 188,
+          "height": 159.6
+        },
+        {
+          "width": 188,
+          "height": 124.4
+        },
+        {
+          "width": 188,
+          "height": 92.8
+        },
+        {
+          "width": 183.2,
+          "height": 66.4
+        },
+        {
+          "width": 176,
+          "height": 46
+        },
+        {
+          "width": 170.4,
+          "height": 39.2
+        },
+        {
+          "width": 166.8,
+          "height": 36
+        },
+        {
+          "width": 164,
+          "height": 31.6
+        },
+        {
+          "width": 162.4,
+          "height": 26.8
+        },
+        {
+          "width": 161.2,
+          "height": 22
+        },
+        {
+          "width": 160.4,
+          "height": 17.6
+        },
+        {
+          "width": 160,
+          "height": 14
+        },
+        {
+          "width": 160,
+          "height": 10.8
+        },
+        {
+          "width": 160,
+          "height": 8
+        },
+        {
+          "width": 160,
+          "height": 6
+        },
+        {
+          "width": 160,
+          "height": 4.4
+        },
+        {
+          "width": 160,
+          "height": 2.8
+        },
+        {
+          "width": 160,
+          "height": 2
+        },
+        {
+          "width": 160,
+          "height": 1.2
+        },
+        {
+          "width": 160,
+          "height": 0.8
+        },
+        {
+          "width": 160,
+          "height": 0.4
+        },
+        {
+          "width": 160,
+          "height": 0
+        },
+        {
+          "width": 160,
+          "height": 0
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        0.9808927,
+        0.8211168,
+        0.61845565,
+        0.43834114,
+        0.29850912,
+        0.19755232,
+        0.12793064,
+        0.08142871,
+        0.051099956,
+        0.031684637,
+        0.019442618,
+        0.011821032,
+        0,
+        0,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragHalfClose.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragHalfClose.json
new file mode 100644
index 0000000..3196334
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragHalfClose.json
@@ -0,0 +1,624 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432,
+    448,
+    464,
+    480,
+    496,
+    512,
+    528,
+    544,
+    560,
+    576,
+    592,
+    608,
+    624,
+    640,
+    656,
+    672,
+    688,
+    704,
+    720,
+    736,
+    752,
+    768,
+    784,
+    800,
+    816,
+    832,
+    848,
+    864,
+    880,
+    896,
+    912,
+    928,
+    944
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50.8,
+          "y": 52
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 52.4,
+          "y": 50
+        },
+        {
+          "x": 55.6,
+          "y": 50
+        },
+        {
+          "x": 58.4,
+          "y": 50
+        },
+        {
+          "x": 60.4,
+          "y": 50
+        },
+        {
+          "x": 61.6,
+          "y": 50
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 63.2,
+          "y": 50
+        },
+        {
+          "x": 63.6,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 390
+        },
+        {
+          "width": 188,
+          "height": 390
+        },
+        {
+          "width": 188,
+          "height": 379.2
+        },
+        {
+          "width": 188,
+          "height": 371.2
+        },
+        {
+          "width": 188,
+          "height": 363.2
+        },
+        {
+          "width": 188,
+          "height": 355.2
+        },
+        {
+          "width": 188,
+          "height": 347.2
+        },
+        {
+          "width": 188,
+          "height": 339.2
+        },
+        {
+          "width": 188,
+          "height": 331.2
+        },
+        {
+          "width": 188,
+          "height": 323.2
+        },
+        {
+          "width": 188,
+          "height": 323.2
+        },
+        {
+          "width": 188,
+          "height": 314.8
+        },
+        {
+          "width": 188,
+          "height": 306.8
+        },
+        {
+          "width": 188,
+          "height": 298.8
+        },
+        {
+          "width": 188,
+          "height": 290.8
+        },
+        {
+          "width": 188,
+          "height": 282.8
+        },
+        {
+          "width": 188,
+          "height": 274.8
+        },
+        {
+          "width": 188,
+          "height": 266.8
+        },
+        {
+          "width": 188,
+          "height": 258.8
+        },
+        {
+          "width": 188,
+          "height": 258.8
+        },
+        {
+          "width": 188,
+          "height": 250.4
+        },
+        {
+          "width": 188,
+          "height": 242.4
+        },
+        {
+          "width": 188,
+          "height": 234.4
+        },
+        {
+          "width": 188,
+          "height": 226.4
+        },
+        {
+          "width": 188,
+          "height": 218.4
+        },
+        {
+          "width": 188,
+          "height": 210.4
+        },
+        {
+          "width": 188,
+          "height": 202.4
+        },
+        {
+          "width": 188,
+          "height": 194.4
+        },
+        {
+          "width": 188,
+          "height": 194.4
+        },
+        {
+          "width": 188,
+          "height": 185.6
+        },
+        {
+          "width": 188,
+          "height": 178
+        },
+        {
+          "width": 188,
+          "height": 170
+        },
+        {
+          "width": 188,
+          "height": 161.6
+        },
+        {
+          "width": 188,
+          "height": 161.6
+        },
+        {
+          "width": 188,
+          "height": 144.8
+        },
+        {
+          "width": 188,
+          "height": 118.8
+        },
+        {
+          "width": 188,
+          "height": 92
+        },
+        {
+          "width": 183.6,
+          "height": 68
+        },
+        {
+          "width": 176.8,
+          "height": 48.4
+        },
+        {
+          "width": 171.6,
+          "height": 39.6
+        },
+        {
+          "width": 167.6,
+          "height": 36.8
+        },
+        {
+          "width": 164.8,
+          "height": 32.4
+        },
+        {
+          "width": 162.8,
+          "height": 27.6
+        },
+        {
+          "width": 161.6,
+          "height": 22.8
+        },
+        {
+          "width": 160.8,
+          "height": 18.4
+        },
+        {
+          "width": 160.4,
+          "height": 14.4
+        },
+        {
+          "width": 160,
+          "height": 11.2
+        },
+        {
+          "width": 160,
+          "height": 8.4
+        },
+        {
+          "width": 160,
+          "height": 6.4
+        },
+        {
+          "width": 160,
+          "height": 4.4
+        },
+        {
+          "width": 160,
+          "height": 3.2
+        },
+        {
+          "width": 160,
+          "height": 2
+        },
+        {
+          "width": 160,
+          "height": 1.6
+        },
+        {
+          "width": 160,
+          "height": 0.8
+        },
+        {
+          "width": 160,
+          "height": 0.4
+        },
+        {
+          "width": 160,
+          "height": 0.4
+        },
+        {
+          "width": 160,
+          "height": 0
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        0.9967737,
+        0.86538374,
+        0.66414475,
+        0.47619528,
+        0.32686388,
+        0.21757984,
+        0.14153665,
+        0.09041709,
+        0.05691254,
+        0.035380244,
+        0.02175957,
+        0.01325649,
+        0.008007765,
+        0,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragOpen.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragOpen.json
new file mode 100644
index 0000000..4b03068
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_dragOpen.json
@@ -0,0 +1,544 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432,
+    448,
+    464,
+    480,
+    496,
+    512,
+    528,
+    544,
+    560,
+    576,
+    592,
+    608,
+    624,
+    640,
+    656,
+    672,
+    688,
+    704,
+    720,
+    736,
+    752,
+    768,
+    784,
+    800,
+    816
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 61.6,
+          "y": 50
+        },
+        {
+          "x": 60.8,
+          "y": 50
+        },
+        {
+          "x": 59.6,
+          "y": 50
+        },
+        {
+          "x": 58.4,
+          "y": 50
+        },
+        {
+          "x": 57.2,
+          "y": 50
+        },
+        {
+          "x": 56,
+          "y": 50
+        },
+        {
+          "x": 55.2,
+          "y": 50
+        },
+        {
+          "x": 54,
+          "y": 50
+        },
+        {
+          "x": 54,
+          "y": 50
+        },
+        {
+          "x": 52.8,
+          "y": 50
+        },
+        {
+          "x": 51.6,
+          "y": 50
+        },
+        {
+          "x": 50.4,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "width": 162.4,
+          "height": 1.6
+        },
+        {
+          "width": 162.4,
+          "height": 1.6
+        },
+        {
+          "width": 164.8,
+          "height": 3.2
+        },
+        {
+          "width": 166.8,
+          "height": 4.8
+        },
+        {
+          "width": 169.2,
+          "height": 6.4
+        },
+        {
+          "width": 171.6,
+          "height": 8
+        },
+        {
+          "width": 173.6,
+          "height": 9.6
+        },
+        {
+          "width": 176,
+          "height": 11.2
+        },
+        {
+          "width": 178,
+          "height": 12.8
+        },
+        {
+          "width": 180.4,
+          "height": 14.4
+        },
+        {
+          "width": 180.4,
+          "height": 14.4
+        },
+        {
+          "width": 182.8,
+          "height": 16.4
+        },
+        {
+          "width": 185.2,
+          "height": 18
+        },
+        {
+          "width": 187.2,
+          "height": 19.6
+        },
+        {
+          "width": 188,
+          "height": 24.8
+        },
+        {
+          "width": 188,
+          "height": 32.8
+        },
+        {
+          "width": 188,
+          "height": 44
+        },
+        {
+          "width": 188,
+          "height": 57.2
+        },
+        {
+          "width": 188,
+          "height": 70.8
+        },
+        {
+          "width": 188,
+          "height": 78
+        },
+        {
+          "width": 188,
+          "height": 91.2
+        },
+        {
+          "width": 188,
+          "height": 103.2
+        },
+        {
+          "width": 188,
+          "height": 114.4
+        },
+        {
+          "width": 188,
+          "height": 124.4
+        },
+        {
+          "width": 188,
+          "height": 134
+        },
+        {
+          "width": 188,
+          "height": 142.8
+        },
+        {
+          "width": 188,
+          "height": 150.8
+        },
+        {
+          "width": 188,
+          "height": 158.8
+        },
+        {
+          "width": 188,
+          "height": 159.6
+        },
+        {
+          "width": 188,
+          "height": 167.2
+        },
+        {
+          "width": 188,
+          "height": 174
+        },
+        {
+          "width": 188,
+          "height": 180.8
+        },
+        {
+          "width": 188,
+          "height": 187.6
+        },
+        {
+          "width": 188,
+          "height": 187.6
+        },
+        {
+          "width": 188,
+          "height": 207.2
+        },
+        {
+          "width": 188,
+          "height": 240
+        },
+        {
+          "width": 188,
+          "height": 275.2
+        },
+        {
+          "width": 188,
+          "height": 306.8
+        },
+        {
+          "width": 188,
+          "height": 333.2
+        },
+        {
+          "width": 188,
+          "height": 353.6
+        },
+        {
+          "width": 188,
+          "height": 368.8
+        },
+        {
+          "width": 188,
+          "height": 380
+        },
+        {
+          "width": 188,
+          "height": 387.6
+        },
+        {
+          "width": 188,
+          "height": 392.4
+        },
+        {
+          "width": 188,
+          "height": 395.6
+        },
+        {
+          "width": 188,
+          "height": 398
+        },
+        {
+          "width": 188,
+          "height": 398.8
+        },
+        {
+          "width": 188,
+          "height": 399.6
+        },
+        {
+          "width": 188,
+          "height": 400
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        0,
+        0,
+        0,
+        0,
+        0.0067873597,
+        0.0612576,
+        0.19080025,
+        0.39327443,
+        0.5711931,
+        0.70855826,
+        0.8074064,
+        0.8754226,
+        0.9207788,
+        0.95032376,
+        0.9692185,
+        0.98112255,
+        0.9885286,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_flingClose.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_flingClose.json
new file mode 100644
index 0000000..10a9ba7
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_flingClose.json
@@ -0,0 +1,424 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432,
+    448,
+    464,
+    480,
+    496,
+    512,
+    528,
+    544,
+    560,
+    576,
+    592,
+    608,
+    624
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50.4,
+          "y": 50.8
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 51.2,
+          "y": 50
+        },
+        {
+          "x": 55.6,
+          "y": 50
+        },
+        {
+          "x": 58.8,
+          "y": 50
+        },
+        {
+          "x": 60.8,
+          "y": 50
+        },
+        {
+          "x": 62,
+          "y": 50
+        },
+        {
+          "x": 63.2,
+          "y": 50
+        },
+        {
+          "x": 63.6,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 389.6
+        },
+        {
+          "width": 188,
+          "height": 378.8
+        },
+        {
+          "width": 188,
+          "height": 366
+        },
+        {
+          "width": 188,
+          "height": 352
+        },
+        {
+          "width": 188,
+          "height": 352
+        },
+        {
+          "width": 188,
+          "height": 316.8
+        },
+        {
+          "width": 188,
+          "height": 261.2
+        },
+        {
+          "width": 188,
+          "height": 202.8
+        },
+        {
+          "width": 188,
+          "height": 150.8
+        },
+        {
+          "width": 188,
+          "height": 107.6
+        },
+        {
+          "width": 186,
+          "height": 74.4
+        },
+        {
+          "width": 177.2,
+          "height": 49.6
+        },
+        {
+          "width": 170.8,
+          "height": 39.6
+        },
+        {
+          "width": 166.8,
+          "height": 36.8
+        },
+        {
+          "width": 164,
+          "height": 32.4
+        },
+        {
+          "width": 162,
+          "height": 27.6
+        },
+        {
+          "width": 160.8,
+          "height": 22.8
+        },
+        {
+          "width": 160.4,
+          "height": 18.4
+        },
+        {
+          "width": 160,
+          "height": 14.4
+        },
+        {
+          "width": 160,
+          "height": 11.2
+        },
+        {
+          "width": 160,
+          "height": 8.4
+        },
+        {
+          "width": 160,
+          "height": 6
+        },
+        {
+          "width": 160,
+          "height": 4.4
+        },
+        {
+          "width": 160,
+          "height": 3.2
+        },
+        {
+          "width": 160,
+          "height": 2
+        },
+        {
+          "width": 160,
+          "height": 1.2
+        },
+        {
+          "width": 160,
+          "height": 0.8
+        },
+        {
+          "width": 160,
+          "height": 0.4
+        },
+        {
+          "width": 160,
+          "height": 0
+        },
+        {
+          "width": 160,
+          "height": 0
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        0.9833227,
+        0.8263634,
+        0.623688,
+        0.44261706,
+        0.3016883,
+        0.1997872,
+        0.12944388,
+        0.08242595,
+        0.051743627,
+        0.032093227,
+        0.019698441,
+        0.0119793415,
+        0,
+        0,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_flingOpen.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_flingOpen.json
new file mode 100644
index 0000000..d8bf48d
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_flingOpen.json
@@ -0,0 +1,364 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432,
+    448,
+    464,
+    480,
+    496,
+    512,
+    528
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "x": 62.4,
+          "y": 50
+        },
+        {
+          "x": 61.2,
+          "y": 50
+        },
+        {
+          "x": 59.2,
+          "y": 50
+        },
+        {
+          "x": 57.2,
+          "y": 50
+        },
+        {
+          "x": 54.8,
+          "y": 50
+        },
+        {
+          "x": 52.4,
+          "y": 50
+        },
+        {
+          "x": 52.4,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "width": 163.2,
+          "height": 2
+        },
+        {
+          "width": 166,
+          "height": 4.4
+        },
+        {
+          "width": 170,
+          "height": 6.8
+        },
+        {
+          "width": 174,
+          "height": 10
+        },
+        {
+          "width": 178.4,
+          "height": 13.2
+        },
+        {
+          "width": 183.6,
+          "height": 16.8
+        },
+        {
+          "width": 183.6,
+          "height": 16.8
+        },
+        {
+          "width": 188,
+          "height": 42.4
+        },
+        {
+          "width": 188,
+          "height": 100
+        },
+        {
+          "width": 188,
+          "height": 161.6
+        },
+        {
+          "width": 188,
+          "height": 218
+        },
+        {
+          "width": 188,
+          "height": 265.6
+        },
+        {
+          "width": 188,
+          "height": 303.6
+        },
+        {
+          "width": 188,
+          "height": 332.4
+        },
+        {
+          "width": 188,
+          "height": 354
+        },
+        {
+          "width": 188,
+          "height": 369.2
+        },
+        {
+          "width": 188,
+          "height": 380
+        },
+        {
+          "width": 188,
+          "height": 387.2
+        },
+        {
+          "width": 188,
+          "height": 392
+        },
+        {
+          "width": 188,
+          "height": 395.2
+        },
+        {
+          "width": 188,
+          "height": 397.6
+        },
+        {
+          "width": 188,
+          "height": 398.4
+        },
+        {
+          "width": 188,
+          "height": 398.8
+        },
+        {
+          "width": 188,
+          "height": 399.2
+        },
+        {
+          "width": 188,
+          "height": 399.6
+        },
+        {
+          "width": 188,
+          "height": 399.6
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        0,
+        0,
+        0.008216977,
+        0.06259775,
+        0.19032806,
+        0.39281356,
+        0.57081985,
+        0.7082821,
+        0.80721295,
+        0.8752918,
+        0.9206928,
+        0.95026827,
+        0.9691833,
+        0.98110056,
+        0.988515,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_magneticDetachAndReattach.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_magneticDetachAndReattach.json
new file mode 100644
index 0000000..57bdf3e
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_gesture_magneticDetachAndReattach.json
@@ -0,0 +1,744 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432,
+    448,
+    464,
+    480,
+    496,
+    512,
+    528,
+    544,
+    560,
+    576,
+    592,
+    608,
+    624,
+    640,
+    656,
+    672,
+    688,
+    704,
+    720,
+    736,
+    752,
+    768,
+    784,
+    800,
+    816,
+    832,
+    848,
+    864,
+    880,
+    896,
+    912,
+    928,
+    944,
+    960,
+    976,
+    992,
+    1008,
+    1024,
+    1040,
+    1056,
+    1072,
+    1088,
+    1104,
+    1120,
+    1136
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 62,
+          "y": 50
+        },
+        {
+          "x": 61.2,
+          "y": 50
+        },
+        {
+          "x": 60.4,
+          "y": 50
+        },
+        {
+          "x": 59.6,
+          "y": 50
+        },
+        {
+          "x": 58.8,
+          "y": 50
+        },
+        {
+          "x": 58,
+          "y": 50
+        },
+        {
+          "x": 57.2,
+          "y": 50
+        },
+        {
+          "x": 56.4,
+          "y": 50
+        },
+        {
+          "x": 55.6,
+          "y": 50
+        },
+        {
+          "x": 55.2,
+          "y": 50
+        },
+        {
+          "x": 54.4,
+          "y": 50
+        },
+        {
+          "x": 53.6,
+          "y": 50
+        },
+        {
+          "x": 53.2,
+          "y": 50
+        },
+        {
+          "x": 52.8,
+          "y": 50
+        },
+        {
+          "x": 52,
+          "y": 50
+        },
+        {
+          "x": 51.6,
+          "y": 50
+        },
+        {
+          "x": 51.2,
+          "y": 50
+        },
+        {
+          "x": 50.8,
+          "y": 50
+        },
+        {
+          "x": 50.4,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50.4,
+          "y": 50
+        },
+        {
+          "x": 50.8,
+          "y": 50
+        },
+        {
+          "x": 51.2,
+          "y": 50
+        },
+        {
+          "x": 51.6,
+          "y": 50
+        },
+        {
+          "x": 52,
+          "y": 50
+        },
+        {
+          "x": 52.8,
+          "y": 50
+        },
+        {
+          "x": 53.2,
+          "y": 50
+        },
+        {
+          "x": 53.6,
+          "y": 50
+        },
+        {
+          "x": 54.4,
+          "y": 50
+        },
+        {
+          "x": 55.2,
+          "y": 50
+        },
+        {
+          "x": 55.6,
+          "y": 50
+        },
+        {
+          "x": 56.4,
+          "y": 50
+        },
+        {
+          "x": 57.2,
+          "y": 50
+        },
+        {
+          "x": 58,
+          "y": 50
+        },
+        {
+          "x": 58.8,
+          "y": 50
+        },
+        {
+          "x": 59.6,
+          "y": 50
+        },
+        {
+          "x": 60.4,
+          "y": 50
+        },
+        {
+          "x": 61.2,
+          "y": 50
+        },
+        {
+          "x": 62,
+          "y": 50
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 63.6,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "width": 162.4,
+          "height": 1.6
+        },
+        {
+          "width": 164,
+          "height": 2.8
+        },
+        {
+          "width": 166,
+          "height": 4
+        },
+        {
+          "width": 167.6,
+          "height": 5.2
+        },
+        {
+          "width": 169.2,
+          "height": 6.4
+        },
+        {
+          "width": 170.8,
+          "height": 7.6
+        },
+        {
+          "width": 172.4,
+          "height": 8.8
+        },
+        {
+          "width": 174,
+          "height": 10
+        },
+        {
+          "width": 175.2,
+          "height": 10.8
+        },
+        {
+          "width": 176.8,
+          "height": 12
+        },
+        {
+          "width": 178,
+          "height": 12.8
+        },
+        {
+          "width": 179.2,
+          "height": 13.6
+        },
+        {
+          "width": 180.8,
+          "height": 14.8
+        },
+        {
+          "width": 182,
+          "height": 15.6
+        },
+        {
+          "width": 182.8,
+          "height": 16.4
+        },
+        {
+          "width": 184,
+          "height": 17.2
+        },
+        {
+          "width": 184.8,
+          "height": 17.6
+        },
+        {
+          "width": 186,
+          "height": 18.4
+        },
+        {
+          "width": 186.8,
+          "height": 19.2
+        },
+        {
+          "width": 187.6,
+          "height": 19.6
+        },
+        {
+          "width": 188,
+          "height": 21.2
+        },
+        {
+          "width": 188,
+          "height": 24
+        },
+        {
+          "width": 188,
+          "height": 29.6
+        },
+        {
+          "width": 188,
+          "height": 37.2
+        },
+        {
+          "width": 188,
+          "height": 45.6
+        },
+        {
+          "width": 188,
+          "height": 53.6
+        },
+        {
+          "width": 188,
+          "height": 60.4
+        },
+        {
+          "width": 188,
+          "height": 66.4
+        },
+        {
+          "width": 188,
+          "height": 71.2
+        },
+        {
+          "width": 188,
+          "height": 75.2
+        },
+        {
+          "width": 188,
+          "height": 77.6
+        },
+        {
+          "width": 188,
+          "height": 79.6
+        },
+        {
+          "width": 188,
+          "height": 80.4
+        },
+        {
+          "width": 188,
+          "height": 80.8
+        },
+        {
+          "width": 188,
+          "height": 80.4
+        },
+        {
+          "width": 188,
+          "height": 79.2
+        },
+        {
+          "width": 187.6,
+          "height": 78
+        },
+        {
+          "width": 186.8,
+          "height": 76
+        },
+        {
+          "width": 186,
+          "height": 74
+        },
+        {
+          "width": 184.8,
+          "height": 71.6
+        },
+        {
+          "width": 184,
+          "height": 69.2
+        },
+        {
+          "width": 182.8,
+          "height": 66
+        },
+        {
+          "width": 182,
+          "height": 62.8
+        },
+        {
+          "width": 180.8,
+          "height": 59.2
+        },
+        {
+          "width": 179.2,
+          "height": 55.6
+        },
+        {
+          "width": 178,
+          "height": 52
+        },
+        {
+          "width": 176.8,
+          "height": 48
+        },
+        {
+          "width": 175.2,
+          "height": 44
+        },
+        {
+          "width": 174,
+          "height": 40
+        },
+        {
+          "width": 172.4,
+          "height": 39.2
+        },
+        {
+          "width": 170.8,
+          "height": 38.4
+        },
+        {
+          "width": 169.2,
+          "height": 34.8
+        },
+        {
+          "width": 167.6,
+          "height": 30
+        },
+        {
+          "width": 166,
+          "height": 25.2
+        },
+        {
+          "width": 164,
+          "height": 20.4
+        },
+        {
+          "width": 162.4,
+          "height": 16.4
+        },
+        {
+          "width": 160.8,
+          "height": 12.8
+        },
+        {
+          "width": 160,
+          "height": 9.6
+        },
+        {
+          "width": 160,
+          "height": 7.2
+        },
+        {
+          "width": 160,
+          "height": 5.2
+        },
+        {
+          "width": 160,
+          "height": 3.6
+        },
+        {
+          "width": 160,
+          "height": 2.8
+        },
+        {
+          "width": 160,
+          "height": 1.6
+        },
+        {
+          "width": 160,
+          "height": 1.2
+        },
+        {
+          "width": 160,
+          "height": 0.8
+        },
+        {
+          "width": 160,
+          "height": 0.4
+        },
+        {
+          "width": 160,
+          "height": 0
+        },
+        {
+          "width": 160,
+          "height": 0
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        {
+          "type": "not_found"
+        },
+        0,
+        0,
+        0,
+        0,
+        0.012518823,
+        0.0741024,
+        0.2254293,
+        0.42628878,
+        0.5976641,
+        0.7280312,
+        0.82100236,
+        0.8845844,
+        0.9267946,
+        0.95419544,
+        0.9716705,
+        0.98265487,
+        0.98947525,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        0.9944124,
+        0.9417388,
+        0.8184184,
+        0.6157812,
+        0.4361611,
+        0.2968906,
+        0.19641554,
+        0.12716137,
+        0.080921985,
+        0.050773025,
+        0.03147719,
+        0.019312752,
+        0.011740655,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_triggeredRevealCloseTransition.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_triggeredRevealCloseTransition.json
new file mode 100644
index 0000000..9aa91c2
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_triggeredRevealCloseTransition.json
@@ -0,0 +1,304 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336,
+    352,
+    368,
+    384,
+    400,
+    416,
+    432
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 53.2,
+          "y": 50
+        },
+        {
+          "x": 57.2,
+          "y": 50
+        },
+        {
+          "x": 59.6,
+          "y": 50
+        },
+        {
+          "x": 61.6,
+          "y": 50
+        },
+        {
+          "x": 62.8,
+          "y": 50
+        },
+        {
+          "x": 63.6,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 64,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 400
+        },
+        {
+          "width": 188,
+          "height": 372
+        },
+        {
+          "width": 188,
+          "height": 312.8
+        },
+        {
+          "width": 188,
+          "height": 246.8
+        },
+        {
+          "width": 188,
+          "height": 185.2
+        },
+        {
+          "width": 188,
+          "height": 133.6
+        },
+        {
+          "width": 188,
+          "height": 93.2
+        },
+        {
+          "width": 181.6,
+          "height": 62.8
+        },
+        {
+          "width": 174,
+          "height": 40.8
+        },
+        {
+          "width": 168.8,
+          "height": 38.4
+        },
+        {
+          "width": 165.2,
+          "height": 34.8
+        },
+        {
+          "width": 162.8,
+          "height": 30
+        },
+        {
+          "width": 161.2,
+          "height": 25.2
+        },
+        {
+          "width": 160.4,
+          "height": 20.4
+        },
+        {
+          "width": 160,
+          "height": 16.4
+        },
+        {
+          "width": 160,
+          "height": 12.8
+        },
+        {
+          "width": 160,
+          "height": 9.6
+        },
+        {
+          "width": 160,
+          "height": 7.2
+        },
+        {
+          "width": 160,
+          "height": 5.2
+        },
+        {
+          "width": 160,
+          "height": 3.6
+        },
+        {
+          "width": 160,
+          "height": 2.8
+        },
+        {
+          "width": 160,
+          "height": 1.6
+        },
+        {
+          "width": 160,
+          "height": 1.2
+        },
+        {
+          "width": 160,
+          "height": 0.8
+        },
+        {
+          "width": 160,
+          "height": 0.4
+        },
+        {
+          "width": 160,
+          "height": 0
+        },
+        {
+          "width": 160,
+          "height": 0
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        0.91758585,
+        0.72435355,
+        0.52812576,
+        0.3665868,
+        0.24600428,
+        0.16102076,
+        0.103373945,
+        0.06533456,
+        0.04075712,
+        0.025142312,
+        0.015358448,
+        0.0092999935,
+        0,
+        0,
+        0,
+        0,
+        0
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_triggeredRevealOpenTransition.json b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_triggeredRevealOpenTransition.json
new file mode 100644
index 0000000..622c29e
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/goldens/verticalReveal_triggeredRevealOpenTransition.json
@@ -0,0 +1,244 @@
+{
+  "frame_ids": [
+    0,
+    16,
+    32,
+    48,
+    64,
+    80,
+    96,
+    112,
+    128,
+    144,
+    160,
+    176,
+    192,
+    208,
+    224,
+    240,
+    256,
+    272,
+    288,
+    304,
+    320,
+    336
+  ],
+  "features": [
+    {
+      "name": "RevealElement_position",
+      "type": "dpOffset",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "x": 64,
+          "y": 50
+        },
+        {
+          "x": 59.2,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        },
+        {
+          "x": 50,
+          "y": 50
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_size",
+      "type": "dpSize",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        {
+          "width": 160,
+          "height": 0
+        },
+        {
+          "width": 169.6,
+          "height": 6.8
+        },
+        {
+          "width": 188,
+          "height": 26.8
+        },
+        {
+          "width": 188,
+          "height": 95.6
+        },
+        {
+          "width": 188,
+          "height": 163.2
+        },
+        {
+          "width": 188,
+          "height": 222
+        },
+        {
+          "width": 188,
+          "height": 269.6
+        },
+        {
+          "width": 188,
+          "height": 307.2
+        },
+        {
+          "width": 188,
+          "height": 335.2
+        },
+        {
+          "width": 188,
+          "height": 356
+        },
+        {
+          "width": 188,
+          "height": 370.4
+        },
+        {
+          "width": 188,
+          "height": 380.8
+        },
+        {
+          "width": 188,
+          "height": 387.6
+        },
+        {
+          "width": 188,
+          "height": 392.4
+        },
+        {
+          "width": 188,
+          "height": 395.2
+        },
+        {
+          "width": 188,
+          "height": 397.2
+        },
+        {
+          "width": 188,
+          "height": 398
+        },
+        {
+          "width": 188,
+          "height": 398.8
+        },
+        {
+          "width": 188,
+          "height": 399.2
+        },
+        {
+          "width": 188,
+          "height": 399.2
+        },
+        {
+          "width": 188,
+          "height": 399.6
+        }
+      ]
+    },
+    {
+      "name": "RevealElement_alpha",
+      "type": "float",
+      "data_points": [
+        {
+          "type": "not_found"
+        },
+        0,
+        0.05698657,
+        0.24197984,
+        0.44158113,
+        0.6097554,
+        0.73685503,
+        0.8271309,
+        0.8886989,
+        0.9294886,
+        0.9559254,
+        0.97276413,
+        0.98333716,
+        0.98989624,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1,
+        1
+      ]
+    }
+  ]
+}
\ No newline at end of file
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
index fa7661b6..6538d43 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/SceneTransitionLayoutTest.kt
@@ -45,6 +45,7 @@
 import androidx.compose.ui.test.SemanticsNodeInteraction
 import androidx.compose.ui.test.assertHeightIsEqualTo
 import androidx.compose.ui.test.assertIsDisplayed
+import androidx.compose.ui.test.assertIsNotDisplayed
 import androidx.compose.ui.test.assertPositionInRootIsEqualTo
 import androidx.compose.ui.test.assertWidthIsEqualTo
 import androidx.compose.ui.test.junit4.createComposeRule
@@ -64,10 +65,13 @@
 import com.android.compose.animation.scene.TestScenes.SceneC
 import com.android.compose.animation.scene.subjects.assertThat
 import com.android.compose.test.assertSizeIsEqualTo
+import com.android.compose.test.setContentAndCreateMainScope
 import com.android.compose.test.subjects.DpOffsetSubject
 import com.android.compose.test.subjects.assertThat
+import com.android.compose.test.transition
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 import org.junit.Assert.assertThrows
 import org.junit.Rule
 import org.junit.Test
@@ -582,4 +586,34 @@
         assertThat((state2 as MutableSceneTransitionLayoutStateImpl).motionScheme)
             .isEqualTo(motionScheme2)
     }
+
+    @Test
+    fun alwaysCompose() {
+        val state = rule.runOnUiThread { MutableSceneTransitionLayoutStateForTests(SceneA) }
+        val scope =
+            rule.setContentAndCreateMainScope {
+                SceneTransitionLayoutForTesting(state) {
+                    scene(SceneA) { Box(Modifier.element(TestElements.Foo).size(20.dp)) }
+                    scene(SceneB, alwaysCompose = true) {
+                        Box(Modifier.element(TestElements.Bar).size(40.dp))
+                    }
+                }
+            }
+
+        // Idle(A): Foo is displayed and Bar exists given that SceneB is always composed but it is
+        // not displayed.
+        rule.onNode(isElement(TestElements.Foo)).assertIsDisplayed().assertSizeIsEqualTo(20.dp)
+        rule.onNode(isElement(TestElements.Bar)).assertExists().assertIsNotDisplayed()
+
+        // Transition(A => B): Foo and Bar are both displayed
+        val aToB = transition(SceneA, SceneB)
+        scope.launch { state.startTransition(aToB) }
+        rule.onNode(isElement(TestElements.Foo)).assertIsDisplayed().assertSizeIsEqualTo(20.dp)
+        rule.onNode(isElement(TestElements.Bar)).assertIsDisplayed().assertSizeIsEqualTo(40.dp)
+
+        // Idle(B): Foo does not exist and Bar is displayed.
+        aToB.finish()
+        rule.onNode(isElement(TestElements.Foo)).assertDoesNotExist()
+        rule.onNode(isElement(TestElements.Bar)).assertIsDisplayed().assertSizeIsEqualTo(40.dp)
+    }
 }
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/mechanics/TransitionScopedMechanicsAdapterTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/mechanics/TransitionScopedMechanicsAdapterTest.kt
new file mode 100644
index 0000000..9d40350
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/mechanics/TransitionScopedMechanicsAdapterTest.kt
@@ -0,0 +1,519 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.mechanics
+
+import android.platform.test.annotations.MotionTest
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.tween
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.semantics.SemanticsNode
+import androidx.compose.ui.test.junit4.ComposeContentTestRule
+import androidx.compose.ui.unit.IntSize
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.ContentKey
+import com.android.compose.animation.scene.ContentScope
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.MutableSceneTransitionLayoutStateForTests
+import com.android.compose.animation.scene.MutableSceneTransitionLayoutStateImpl
+import com.android.compose.animation.scene.OverlayKey
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.SceneTransitionLayoutForTesting
+import com.android.compose.animation.scene.SceneTransitionsBuilder
+import com.android.compose.animation.scene.TestElements
+import com.android.compose.animation.scene.TestOverlays
+import com.android.compose.animation.scene.TestScenes
+import com.android.compose.animation.scene.TransitionBuilder
+import com.android.compose.animation.scene.TransitionRecordingSpec
+import com.android.compose.animation.scene.content.state.TransitionState
+import com.android.compose.animation.scene.featureOfElement
+import com.android.compose.animation.scene.mechanics.TransitionScopedMechanicsAdapter.Companion.appearDirection
+import com.android.compose.animation.scene.recordTransition
+import com.android.compose.animation.scene.testing.lastOffsetForTesting
+import com.android.compose.animation.scene.transformation.CustomPropertyTransformation
+import com.android.compose.animation.scene.transformation.PropertyTransformation
+import com.android.compose.animation.scene.transformation.PropertyTransformationScope
+import com.android.compose.animation.scene.transitions
+import com.android.mechanics.spec.InputDirection
+import com.android.mechanics.spec.Mapping
+import com.android.mechanics.spec.MotionSpec
+import com.android.mechanics.spec.buildDirectionalMotionSpec
+import com.android.mechanics.spring.SpringParameters
+import com.google.common.truth.Truth
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.test.TestScope
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.motion.compose.ComposeRecordingSpec
+import platform.test.motion.compose.MotionControl
+import platform.test.motion.compose.createFixedConfigurationComposeMotionTestRule
+import platform.test.motion.compose.recordMotion
+import platform.test.motion.compose.runTest
+import platform.test.motion.golden.DataPoint
+import platform.test.motion.golden.DataPointTypes
+import platform.test.motion.golden.FeatureCapture
+import platform.test.motion.testing.createGoldenPathManager
+
+@RunWith(AndroidJUnit4::class)
+@MotionTest
+class TransitionScopedMechanicsAdapterTest {
+
+    private val goldenPaths =
+        createGoldenPathManager("frameworks/base/packages/SystemUI/compose/scene/tests/goldens")
+
+    private val testScope = TestScope()
+    @get:Rule val motionRule = createFixedConfigurationComposeMotionTestRule(goldenPaths, testScope)
+    private val composeRule = motionRule.toolkit.composeContentTestRule
+
+    @Test
+    fun motionValue_withoutAnimation_terminatesImmediately() =
+        motionRule.runTest {
+            val specFactory: SpecFactory = { _, _ ->
+                MotionSpec(
+                    // Linearly animate from 10 down to 0
+                    buildDirectionalMotionSpec(TestSpring, Mapping.Fixed(50.dp.toPx())) {
+                        targetFromCurrent(breakpoint = 0f, to = 0f)
+                        constantValueFromCurrent(breakpoint = 1f)
+                    }
+                )
+            }
+
+            assertOffsetMatchesGolden(
+                transition = {
+                    spec = tween(16 * 6, easing = LinearEasing)
+                    transformation(TestElements.Foo) { TestTransformation(specFactory) }
+                }
+            )
+        }
+
+    @Test
+    fun motionValue_withAnimation_prolongsTransition() =
+        motionRule.runTest {
+            val specFactory: SpecFactory = { _, _ ->
+                MotionSpec(
+                    // Use a spring to toggle 10f -> 0f at a progress of 0.5
+                    buildDirectionalMotionSpec(TestSpring, Mapping.Fixed(50.dp.toPx())) {
+                        constantValue(breakpoint = 0.5f, value = 0f)
+                    }
+                )
+            }
+
+            assertOffsetMatchesGolden(
+                transition = {
+                    spec = tween(16 * 6, easing = LinearEasing)
+                    transformation(TestElements.Foo) { TestTransformation(specFactory) }
+                }
+            )
+        }
+
+    @Test
+    fun motionValue_interruptedAnimation_completes() =
+        motionRule.runTest {
+            val transitions = transitions {
+                from(TestScenes.SceneA, to = TestScenes.SceneB) {
+                    spec = tween(16 * 6, easing = LinearEasing)
+
+                    transformation(TestElements.Foo) {
+                        TestTransformation { _, _ ->
+                            MotionSpec(
+                                buildDirectionalMotionSpec(
+                                    TestSpring,
+                                    Mapping.Fixed(50.dp.toPx()),
+                                ) {
+                                    constantValue(breakpoint = 0.3f, value = 0f)
+                                }
+                            )
+                        }
+                    }
+                }
+            }
+
+            val state =
+                composeRule.runOnUiThread {
+                    MutableSceneTransitionLayoutStateForTests(TestScenes.SceneA, transitions)
+                }
+            lateinit var coroutineScope: CoroutineScope
+
+            val motionControl =
+                MotionControl(delayRecording = { awaitFrames(4) }) {
+                    awaitFrames(1)
+                    val (transitionToB, firstTransitionJob) =
+                        toolkit.composeContentTestRule.runOnUiThread {
+                            checkNotNull(
+                                state.setTargetScene(
+                                    TestScenes.SceneB,
+                                    animationScope = coroutineScope,
+                                )
+                            )
+                        }
+
+                    awaitCondition { transitionToB.progress > 0.5f }
+                    val (transitionBackToA, secondTransitionJob) =
+                        toolkit.composeContentTestRule.runOnUiThread {
+                            checkNotNull(
+                                state.setTargetScene(
+                                    TestScenes.SceneA,
+                                    animationScope = coroutineScope,
+                                )
+                            )
+                        }
+
+                    Truth.assertThat(transitionBackToA.replacedTransition)
+                        .isSameInstanceAs(transitionToB)
+
+                    awaitCondition { !state.isTransitioning() }
+
+                    Truth.assertThat(firstTransitionJob.isCompleted).isTrue()
+                    Truth.assertThat(secondTransitionJob.isCompleted).isTrue()
+                }
+
+            val motion =
+                recordMotion(
+                    content = {
+                        coroutineScope = rememberCoroutineScope()
+                        SceneTransitionLayoutForTesting(state, modifier = Modifier.size(50.dp)) {
+                            scene(TestScenes.SceneA) { SceneAContent() }
+                            scene(TestScenes.SceneB) { SceneBContent() }
+                        }
+                    },
+                    ComposeRecordingSpec(motionControl, recordBefore = false) {
+                        featureOfElement(TestElements.Foo, yOffsetFeature)
+                    },
+                )
+
+            assertThat(motion).timeSeriesMatchesGolden()
+        }
+
+    @Test
+    fun animationDirection_sceneTransition_forward() {
+        val transitionDirection =
+            composeRule.getAppearDirectionOnTransition(
+                initialScene = TestScenes.SceneA,
+                transitionBuilder = {
+                    from(TestScenes.SceneA, to = TestScenes.SceneB) { it(TestElements.Foo) }
+                },
+            ) { state, animationScope, _ ->
+                state.setTargetScene(TestScenes.SceneB, animationScope)
+                false
+            }
+
+        Truth.assertThat(transitionDirection).isEqualTo(InputDirection.Max)
+    }
+
+    @Test
+    fun animationDirection_sceneTransition_backwards() {
+        val transitionDirection =
+            composeRule.getAppearDirectionOnTransition(
+                initialScene = TestScenes.SceneB,
+                transitionBuilder = {
+                    from(TestScenes.SceneA, to = TestScenes.SceneB) { it(TestElements.Foo) }
+                },
+            ) { state, animationScope, _ ->
+                state.setTargetScene(TestScenes.SceneA, animationScope)
+                false
+            }
+
+        Truth.assertThat(transitionDirection).isEqualTo(InputDirection.Min)
+    }
+
+    @Test
+    fun animationDirection_interruptedTransition_flipsDirection() {
+        val transitionDirection =
+            composeRule.getAppearDirectionOnTransition(
+                initialScene = TestScenes.SceneA,
+                transitionBuilder = {
+                    from(TestScenes.SceneA, to = TestScenes.SceneB) { it(TestElements.Foo) }
+                },
+            ) { state, animationScope, iteration ->
+                when (iteration) {
+                    0 -> {
+                        state.setTargetScene(TestScenes.SceneB, animationScope)
+                        true
+                    }
+                    1 -> {
+                        state.setTargetScene(TestScenes.SceneA, animationScope)
+                        false
+                    }
+                    else -> throw AssertionError()
+                }
+            }
+
+        Truth.assertThat(transitionDirection).isEqualTo(InputDirection.Min)
+    }
+
+    @Test
+    fun animationDirection_showOverlay_animatesInMaxDirection() {
+        val transitionDirection =
+            composeRule.getAppearDirectionOnTransition(
+                initialScene = TestScenes.SceneA,
+                transitionBuilder = { this.to(TestOverlays.OverlayA) { it(TestElements.Bar) } },
+            ) { state, animationScope, _ ->
+                state.showOverlay(TestOverlays.OverlayA, animationScope)
+                false
+            }
+
+        Truth.assertThat(transitionDirection).isEqualTo(InputDirection.Max)
+    }
+
+    @Test
+    fun animationDirection_hideOverlay_animatesInMinDirection() {
+        val transitionDirection =
+            composeRule.getAppearDirectionOnTransition(
+                initialScene = TestScenes.SceneA,
+                initialOverlays = setOf(TestOverlays.OverlayA),
+                transitionBuilder = { this.to(TestOverlays.OverlayA) { it(TestElements.Bar) } },
+            ) { state, animationScope, _ ->
+                state.hideOverlay(TestOverlays.OverlayA, animationScope)
+                false
+            }
+
+        Truth.assertThat(transitionDirection).isEqualTo(InputDirection.Min)
+    }
+
+    @Test
+    fun animationDirection_hideOverlayMidTransition_animatesInMinDirection() {
+        val transitionDirection =
+            composeRule.getAppearDirectionOnTransition(
+                initialScene = TestScenes.SceneA,
+                transitionBuilder = { this.to(TestOverlays.OverlayA) { it(TestElements.Bar) } },
+            ) { state, animationScope, iteration ->
+                when (iteration) {
+                    0 -> {
+                        state.showOverlay(TestOverlays.OverlayA, animationScope)
+                        true
+                    }
+                    1 -> {
+                        state.hideOverlay(TestOverlays.OverlayA, animationScope)
+                        false
+                    }
+                    else -> throw AssertionError()
+                }
+            }
+
+        Truth.assertThat(transitionDirection).isEqualTo(InputDirection.Min)
+    }
+
+    @Test
+    fun animationDirection_replaceOverlay_showingContent_animatesInMaxDirection() {
+        val transitionDirection =
+            composeRule.getAppearDirectionOnTransition(
+                initialScene = TestScenes.SceneA,
+                initialOverlays = setOf(TestOverlays.OverlayB),
+                transitionBuilder = { this.to(TestOverlays.OverlayA) { it(TestElements.Bar) } },
+            ) { state, animationScope, _ ->
+                state.replaceOverlay(TestOverlays.OverlayB, TestOverlays.OverlayA, animationScope)
+                false
+            }
+
+        Truth.assertThat(transitionDirection).isEqualTo(InputDirection.Max)
+    }
+
+    @Test
+    fun animationDirection_replaceOverlay_hidingContent_animatesInMinDirection() {
+        val transitionDirection =
+            composeRule.getAppearDirectionOnTransition(
+                initialScene = TestScenes.SceneA,
+                initialOverlays = setOf(TestOverlays.OverlayA),
+                transitionBuilder = { this.to(TestOverlays.OverlayA) { it(TestElements.Bar) } },
+            ) { state, animationScope, _ ->
+                state.replaceOverlay(TestOverlays.OverlayA, TestOverlays.OverlayB, animationScope)
+                false
+            }
+
+        Truth.assertThat(transitionDirection).isEqualTo(InputDirection.Min)
+    }
+
+    @Test
+    fun animationDirection_replaceOverlay_revertMidTransition_animatesInMinDirection() {
+        val transitionDirection =
+            composeRule.getAppearDirectionOnTransition(
+                initialScene = TestScenes.SceneA,
+                initialOverlays = setOf(TestOverlays.OverlayB),
+                transitionBuilder = { this.to(TestOverlays.OverlayA) { it(TestElements.Bar) } },
+            ) { state, animationScope, iteration ->
+                when (iteration) {
+                    0 -> {
+                        state.replaceOverlay(
+                            TestOverlays.OverlayB,
+                            TestOverlays.OverlayA,
+                            animationScope,
+                        )
+                        true
+                    }
+                    1 -> {
+                        state.replaceOverlay(
+                            TestOverlays.OverlayA,
+                            TestOverlays.OverlayB,
+                            animationScope,
+                        )
+                        false
+                    }
+                    else -> throw AssertionError()
+                }
+            }
+
+        Truth.assertThat(transitionDirection).isEqualTo(InputDirection.Min)
+    }
+
+    private fun ComposeContentTestRule.getAppearDirectionOnTransition(
+        initialScene: SceneKey,
+        transitionBuilder: SceneTransitionsBuilder.(foo: DirectionAssertionTransition) -> Unit,
+        initialOverlays: Set<OverlayKey> = emptySet(),
+        runTransition:
+            (
+                state: MutableSceneTransitionLayoutStateImpl,
+                animationScope: CoroutineScope,
+                iteration: Int,
+            ) -> Boolean,
+    ): InputDirection {
+
+        lateinit var result: InputDirection
+
+        val x: DirectionAssertionTransition = {
+            transformation(it) {
+                object : CustomPropertyTransformation<IntSize> {
+                    override val property = PropertyTransformation.Property.Size
+
+                    override fun PropertyTransformationScope.transform(
+                        content: ContentKey,
+                        element: ElementKey,
+                        transition: TransitionState.Transition,
+                        transitionScope: CoroutineScope,
+                    ): IntSize {
+                        result = appearDirection(content, element, transition)
+                        return IntSize.Zero
+                    }
+                }
+            }
+        }
+
+        val state = runOnUiThread {
+            MutableSceneTransitionLayoutStateForTests(
+                initialScene,
+                transitions { transitionBuilder(x) },
+                initialOverlays,
+            )
+        }
+        lateinit var coroutineScope: CoroutineScope
+
+        setContent {
+            coroutineScope = rememberCoroutineScope()
+            SceneTransitionLayout(state) {
+                scene(TestScenes.SceneA) { SceneAContent() }
+                scene(TestScenes.SceneB) { SceneBContent() }
+                overlay(TestOverlays.OverlayA) { OverlayAContent() }
+                overlay(TestOverlays.OverlayB) {}
+            }
+        }
+
+        waitForIdle()
+        mainClock.autoAdvance = false
+        var keepOnAnimating = true
+        var iterationCount = 0
+        while (keepOnAnimating) {
+            runOnUiThread { keepOnAnimating = runTransition(state, coroutineScope, iterationCount) }
+            composeRule.mainClock.advanceTimeByFrame()
+            waitForIdle()
+            iterationCount++
+        }
+        waitForIdle()
+
+        return result
+    }
+
+    private class TestTransformation(specFactory: SpecFactory) :
+        CustomPropertyTransformation<Offset> {
+        override val property = PropertyTransformation.Property.Offset
+
+        val motionValue =
+            TransitionScopedMechanicsAdapter(createSpec = specFactory, stableThreshold = 1f)
+
+        override fun PropertyTransformationScope.transform(
+            content: ContentKey,
+            element: ElementKey,
+            transition: TransitionState.Transition,
+            transitionScope: CoroutineScope,
+        ): Offset {
+            val yOffset =
+                with(motionValue) { update(content, element, transition, transitionScope) }
+
+            return Offset(x = 0f, y = yOffset)
+        }
+    }
+
+    private fun assertOffsetMatchesGolden(transition: TransitionBuilder.() -> Unit) {
+        val recordingSpec =
+            TransitionRecordingSpec(recordBefore = false, recordAfter = true) {
+                featureOfElement(TestElements.Foo, yOffsetFeature)
+            }
+
+        val motion =
+            motionRule.recordTransition(
+                fromSceneContent = { SceneAContent() },
+                toSceneContent = { SceneBContent() },
+                transition = transition,
+                recordingSpec = recordingSpec,
+                layoutModifier = Modifier.size(50.dp),
+            )
+
+        motionRule.assertThat(motion).timeSeriesMatchesGolden()
+    }
+
+    companion object {
+
+        @Composable
+        fun ContentScope.SceneAContent() {
+            Box(modifier = Modifier.fillMaxSize())
+        }
+
+        @Composable
+        fun ContentScope.SceneBContent() {
+            Box(modifier = Modifier.fillMaxSize()) {
+                Box(Modifier.element(TestElements.Foo).size(50.dp).background(Color.Red))
+            }
+        }
+
+        @Composable
+        fun ContentScope.OverlayAContent() {
+            Box(Modifier.element(TestElements.Bar).size(50.dp).background(Color.Red))
+        }
+
+        @Composable
+        fun ContentScope.OverlayBContent() {
+            Box(modifier = Modifier.size(50.dp).background(Color.Green))
+        }
+
+        val TestSpring = SpringParameters(1200f, 1f)
+
+        val yOffsetFeature =
+            FeatureCapture<SemanticsNode, Float>("yOffset") {
+                DataPoint.of(it.lastOffsetForTesting?.y, DataPointTypes.float)
+            }
+    }
+}
+
+typealias DirectionAssertionTransition = TransitionBuilder.(container: ElementKey) -> Unit
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/reveal/ContentRevealTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/reveal/ContentRevealTest.kt
new file mode 100644
index 0000000..f4e2328
--- /dev/null
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/reveal/ContentRevealTest.kt
@@ -0,0 +1,279 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.compose.animation.scene.reveal
+
+import android.platform.test.annotations.MotionTest
+import androidx.compose.foundation.background
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.rememberCoroutineScope
+import androidx.compose.ui.Alignment
+import androidx.compose.ui.Modifier
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.platform.testTag
+import androidx.compose.ui.test.TouchInjectionScope
+import androidx.compose.ui.test.onNodeWithTag
+import androidx.compose.ui.test.swipe
+import androidx.compose.ui.test.swipeDown
+import androidx.compose.ui.test.swipeUp
+import androidx.compose.ui.test.swipeWithVelocity
+import androidx.compose.ui.unit.DpSize
+import androidx.compose.ui.unit.dp
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import com.android.compose.animation.scene.ContentScope
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.FeatureCaptures.elementAlpha
+import com.android.compose.animation.scene.MutableSceneTransitionLayoutStateForTests
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneTransitionLayoutForTesting
+import com.android.compose.animation.scene.Swipe
+import com.android.compose.animation.scene.featureOfElement
+import com.android.compose.animation.scene.transitions
+import com.android.mechanics.behavior.EdgeContainerExpansionSpec
+import com.android.mechanics.behavior.edgeContainerExpansionBackground
+import kotlin.math.sin
+import kotlinx.coroutines.CoroutineScope
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import platform.test.motion.compose.ComposeFeatureCaptures.dpSize
+import platform.test.motion.compose.ComposeFeatureCaptures.positionInRoot
+import platform.test.motion.compose.ComposeRecordingSpec
+import platform.test.motion.compose.MotionControl
+import platform.test.motion.compose.MotionControlScope
+import platform.test.motion.compose.createFixedConfigurationComposeMotionTestRule
+import platform.test.motion.compose.recordMotion
+import platform.test.motion.compose.runTest
+import platform.test.motion.testing.createGoldenPathManager
+
+@RunWith(AndroidJUnit4::class)
+@MotionTest
+class ContentRevealTest {
+
+    private val goldenPaths =
+        createGoldenPathManager("frameworks/base/packages/SystemUI/compose/scene/tests/goldens")
+
+    @get:Rule val motionRule = createFixedConfigurationComposeMotionTestRule(goldenPaths)
+
+    private val fakeHaptics = FakeHaptics()
+
+    @Test
+    fun verticalReveal_triggeredRevealOpenTransition() {
+        assertVerticalContainerRevealMotion(TriggeredRevealMotion(SceneClosed, SceneOpen))
+    }
+
+    @Test
+    fun verticalReveal_triggeredRevealCloseTransition() {
+        assertVerticalContainerRevealMotion(TriggeredRevealMotion(SceneOpen, SceneClosed))
+    }
+
+    @Test
+    fun verticalReveal_gesture_magneticDetachAndReattach() {
+        assertVerticalContainerRevealMotion(
+            GestureRevealMotion(SceneClosed) {
+                val gestureDurationMillis = 1000L
+                swipe(
+                    curve = {
+                        val progress = it / gestureDurationMillis.toFloat()
+                        val y = sin(progress * Math.PI).toFloat() * 100.dp.toPx()
+                        Offset(centerX, y)
+                    },
+                    gestureDurationMillis,
+                )
+            }
+        )
+    }
+
+    @Test
+    fun verticalReveal_gesture_dragOpen() {
+        assertVerticalContainerRevealMotion(
+            GestureRevealMotion(SceneClosed) {
+                swipeDown(endY = 200.dp.toPx(), durationMillis = 500)
+            }
+        )
+    }
+
+    @Test
+    fun verticalReveal_gesture_flingOpen() {
+        assertVerticalContainerRevealMotion(
+            GestureRevealMotion(SceneClosed) {
+                val end = Offset(centerX, 80.dp.toPx())
+                swipeWithVelocity(start = topCenter, end = end, endVelocity = FlingVelocity.toPx())
+            }
+        )
+    }
+
+    @Test
+    fun verticalReveal_gesture_dragFullyClose() {
+        assertVerticalContainerRevealMotion(
+            GestureRevealMotion(SceneOpen) {
+                swipeUp(200.dp.toPx(), 0.dp.toPx(), durationMillis = 500)
+            }
+        )
+    }
+
+    @Test
+    fun verticalReveal_gesture_dragHalfClose() {
+        assertVerticalContainerRevealMotion(
+            GestureRevealMotion(SceneOpen) {
+                swipeUp(350.dp.toPx(), 100.dp.toPx(), durationMillis = 500)
+            }
+        )
+    }
+
+    @Test
+    fun verticalReveal_gesture_flingClose() {
+        assertVerticalContainerRevealMotion(
+            GestureRevealMotion(SceneOpen) {
+                val start = Offset(centerX, 260.dp.toPx())
+                val end = Offset(centerX, 200.dp.toPx())
+                swipeWithVelocity(start, end, FlingVelocity.toPx())
+            }
+        )
+    }
+
+    private interface RevealMotion {
+        val startScene: SceneKey
+    }
+
+    private class TriggeredRevealMotion(
+        override val startScene: SceneKey,
+        val targetScene: SceneKey,
+    ) : RevealMotion
+
+    private class GestureRevealMotion(
+        override val startScene: SceneKey,
+        val gestureControl: TouchInjectionScope.() -> Unit,
+    ) : RevealMotion
+
+    private fun assertVerticalContainerRevealMotion(testInstructions: RevealMotion) =
+        motionRule.runTest {
+            val transitions = transitions {
+                from(SceneClosed, to = SceneOpen) {
+                    verticalContainerReveal(RevealElement, MotionSpec, fakeHaptics)
+                }
+            }
+
+            val state =
+                toolkit.composeContentTestRule.runOnUiThread {
+                    MutableSceneTransitionLayoutStateForTests(
+                        testInstructions.startScene,
+                        transitions,
+                    )
+                }
+            lateinit var coroutineScope: CoroutineScope
+
+            val recordTransition: suspend MotionControlScope.() -> Unit = {
+                when (testInstructions) {
+                    is TriggeredRevealMotion -> {
+                        val transition =
+                            toolkit.composeContentTestRule.runOnUiThread {
+                                state.setTargetScene(
+                                    testInstructions.targetScene,
+                                    animationScope = coroutineScope,
+                                )
+                            }
+                        checkNotNull(transition).second.join()
+                    }
+
+                    is GestureRevealMotion -> {
+                        performTouchInputAsync(
+                            onNodeWithTag("stl"),
+                            testInstructions.gestureControl,
+                        )
+                        awaitCondition { !state.isTransitioning() }
+                    }
+                }
+            }
+            val recordingSpec =
+                ComposeRecordingSpec(
+                    recordBefore = false,
+                    recordAfter = false,
+                    motionControl = MotionControl(recording = recordTransition),
+                ) {
+                    featureOfElement(RevealElement, positionInRoot)
+                    featureOfElement(RevealElement, dpSize)
+                    featureOfElement(RevealElement, elementAlpha)
+                }
+
+            val motion =
+                recordMotion(
+                    content = {
+                        coroutineScope = rememberCoroutineScope()
+                        SceneTransitionLayoutForTesting(
+                            state,
+                            modifier =
+                                Modifier.padding(50.dp)
+                                    .background(Color.Yellow)
+                                    .size(ContainerSize.width, ContainerSize.height + 200.dp)
+                                    .testTag("stl"),
+                        ) {
+                            scene(
+                                SceneClosed,
+                                mapOf(Swipe.Down to SceneOpen),
+                                content = { ClosedContainer() },
+                            )
+                            scene(
+                                SceneOpen,
+                                mapOf(Swipe.Up to SceneClosed),
+                                content = { OpenContainer() },
+                            )
+                        }
+                    },
+                    recordingSpec,
+                )
+
+            assertThat(motion).timeSeriesMatchesGolden()
+        }
+
+    @Composable
+    fun ContentScope.ClosedContainer() {
+        Box(modifier = Modifier.fillMaxSize())
+    }
+
+    @Composable
+    fun ContentScope.OpenContainer() {
+        Box(contentAlignment = Alignment.TopCenter, modifier = Modifier.fillMaxSize()) {
+            Box(
+                modifier =
+                    Modifier.element(RevealElement)
+                        .size(ContainerSize)
+                        .edgeContainerExpansionBackground(Color.DarkGray, MotionSpec)
+            )
+        }
+    }
+
+    private class FakeHaptics : ContainerRevealHaptics {
+        override fun onRevealThresholdCrossed(revealed: Boolean) {}
+    }
+
+    companion object {
+        val ContainerSize = DpSize(200.dp, 400.dp)
+
+        val FlingVelocity = 1000.dp // dp/sec
+
+        val SceneClosed = SceneKey("SceneA")
+        val SceneOpen = SceneKey("SceneB")
+
+        val RevealElement = ElementKey("RevealElement")
+        val MotionSpec = EdgeContainerExpansionSpec()
+    }
+}
diff --git a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
index ea6f208..3b008ac 100644
--- a/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
+++ b/packages/SystemUI/compose/scene/tests/src/com/android/compose/animation/scene/transformation/AnchoredSizeTest.kt
@@ -31,27 +31,21 @@
 import com.android.compose.animation.scene.TransitionRecordingSpec
 import com.android.compose.animation.scene.featureOfElement
 import com.android.compose.animation.scene.recordTransition
-import org.junit.ClassRule
 import org.junit.Rule
 import org.junit.Test
 import org.junit.runner.RunWith
 import platform.test.motion.compose.ComposeFeatureCaptures
-import platform.test.motion.compose.createComposeMotionTestRule
+import platform.test.motion.compose.createFixedConfigurationComposeMotionTestRule
 import platform.test.motion.testing.createGoldenPathManager
-import platform.test.screenshot.ResetDeviceEmulationRule
 
 @RunWith(AndroidJUnit4::class)
 @MotionTest
 class AnchoredSizeTest {
 
-    companion object {
-        @JvmField @ClassRule val cleanupRule: ResetDeviceEmulationRule = ResetDeviceEmulationRule()
-    }
-
     private val goldenPaths =
         createGoldenPathManager("frameworks/base/packages/SystemUI/compose/scene/tests/goldens")
 
-    @get:Rule val motionRule = createComposeMotionTestRule(goldenPaths)
+    @get:Rule val motionRule = createFixedConfigurationComposeMotionTestRule(goldenPaths)
 
     @Test
     fun testAnchoredSizeEnter() {
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
index 9bb3bac..365567b 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/DefaultClockController.kt
@@ -17,7 +17,6 @@
 import android.content.res.Resources
 import android.graphics.Color
 import android.graphics.Rect
-import android.graphics.RectF
 import android.icu.text.NumberFormat
 import android.util.TypedValue
 import android.view.LayoutInflater
@@ -29,6 +28,7 @@
 import com.android.systemui.plugins.clocks.ClockAnimations
 import com.android.systemui.plugins.clocks.ClockConfig
 import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockEventListener
 import com.android.systemui.plugins.clocks.ClockEvents
 import com.android.systemui.plugins.clocks.ClockFaceConfig
 import com.android.systemui.plugins.clocks.ClockFaceController
@@ -102,7 +102,7 @@
         isDarkTheme: Boolean,
         dozeFraction: Float,
         foldFraction: Float,
-        onBoundsChanged: (RectF) -> Unit,
+        clockListener: ClockEventListener?,
     ) {
         largeClock.recomputePadding(null)
 
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
index 6dfd226..5acd446 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/FlexClockController.kt
@@ -16,13 +16,13 @@
 
 package com.android.systemui.shared.clocks
 
-import android.graphics.RectF
 import com.android.systemui.animation.GSFAxes
 import com.android.systemui.customization.R
 import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.AxisType
 import com.android.systemui.plugins.clocks.ClockConfig
 import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockEventListener
 import com.android.systemui.plugins.clocks.ClockEvents
 import com.android.systemui.plugins.clocks.ClockFontAxis
 import com.android.systemui.plugins.clocks.ClockFontAxis.Companion.merge
@@ -107,11 +107,11 @@
         isDarkTheme: Boolean,
         dozeFraction: Float,
         foldFraction: Float,
-        onBoundsChanged: (RectF) -> Unit,
+        clockListener: ClockEventListener?,
     ) {
         events.onFontAxesChanged(clockCtx.settings.axes)
         smallClock.run {
-            layerController.onViewBoundsChanged = onBoundsChanged
+            layerController.onViewBoundsChanged = { clockListener?.onBoundsChanged(it) }
             events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme))
             animations.doze(dozeFraction)
             animations.fold(foldFraction)
@@ -119,7 +119,7 @@
         }
 
         largeClock.run {
-            layerController.onViewBoundsChanged = onBoundsChanged
+            layerController.onViewBoundsChanged = { clockListener?.onBoundsChanged(it) }
             events.onThemeChanged(theme.copy(isDarkTheme = isDarkTheme))
             animations.doze(dozeFraction)
             animations.fold(foldFraction)
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
index c765ea9..2dc3e2b 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/FlexClockView.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.shared.clocks.CanvasUtil.use
 import com.android.systemui.shared.clocks.ClockContext
 import com.android.systemui.shared.clocks.DigitTranslateAnimator
+import com.android.systemui.shared.clocks.VPoint
 import com.android.systemui.shared.clocks.VPointF
 import com.android.systemui.shared.clocks.VPointF.Companion.max
 import com.android.systemui.shared.clocks.VPointF.Companion.times
@@ -109,13 +110,11 @@
         shouldMeasureChildren: Boolean,
     ): VPointF {
         maxChildSize = VPointF(-1, -1)
-        fun SimpleDigitalClockTextView.getSize() = VPointF(measuredWidth, measuredHeight)
-
         childViews.forEach { textView ->
             if (shouldMeasureChildren) {
                 textView.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
             }
-            maxChildSize = max(maxChildSize, textView.getSize())
+            maxChildSize = max(maxChildSize, textView.measuredSize)
         }
         aodTranslate = VPointF.ZERO
         // TODO(b/364680879): Cleanup
@@ -180,8 +179,8 @@
         )
 
     private fun updateMeasuredSize(
-        widthMeasureSpec: Int = measuredWidthAndState,
-        heightMeasureSpec: Int = measuredHeightAndState,
+        widthMeasureSpec: Int,
+        heightMeasureSpec: Int,
         shouldMeasureChildren: Boolean,
     ) {
         val size = calculateSize(widthMeasureSpec, heightMeasureSpec, shouldMeasureChildren)
@@ -357,7 +356,18 @@
     }
 
     fun animateFidget(x: Float, y: Float) {
-        childViews.forEach { view -> view.animateFidget(x, y) }
+        val touchPt = VPointF(x, y)
+        val ints = intArrayOf(0, 0)
+        childViews
+            .sortedBy { view ->
+                view.getLocationInWindow(ints)
+                val loc = VPoint(ints[0], ints[1])
+                val center = loc + view.measuredSize / 2f
+                (center - touchPt).length()
+            }
+            .forEachIndexed { i, view ->
+                view.animateFidget(FIDGET_DELAYS[min(i, FIDGET_DELAYS.size - 1)])
+            }
     }
 
     private fun updateLocale(locale: Locale) {
@@ -441,6 +451,8 @@
         val AOD_HORIZONTAL_TRANSLATE_RATIO = -0.15F
         val AOD_VERTICAL_TRANSLATE_RATIO = 0.075F
 
+        val FIDGET_DELAYS = listOf(0L, 75L, 150L, 225L)
+
         // Delays. Each digit's animation should have a slight delay, so we get a nice
         // "stepping" effect. When moving right, the second digit of the hour should move first.
         // When moving left, the first digit of the hour should move first. The lists encode
diff --git a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
index abe5cc2..fae17a5 100644
--- a/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
+++ b/packages/SystemUI/customization/src/com/android/systemui/shared/clocks/view/SimpleDigitalClockTextView.kt
@@ -372,7 +372,9 @@
         updateTextBoundsForTextAnimator()
     }
 
-    fun animateFidget(x: Float, y: Float) {
+    fun animateFidget(x: Float, y: Float) = animateFidget(0L)
+
+    fun animateFidget(delay: Long) {
         if (!this::textAnimator.isInitialized || textAnimator.isRunning) {
             // Skip fidget animation if other animation is already playing.
             return
@@ -381,13 +383,13 @@
         logger.animateFidget(x, y)
         clockCtx.vibrator?.vibrate(FIDGET_HAPTICS)
 
-        // TODO(b/374306512): Delay each glyph's animation based on x/y position
         textAnimator.setTextStyle(
             TextAnimator.Style(fVar = fidgetFontVariation),
             TextAnimator.Animation(
                 animate = isAnimationEnabled,
                 duration = FIDGET_ANIMATION_DURATION,
                 interpolator = FIDGET_INTERPOLATOR,
+                startDelay = delay,
                 onAnimationEnd = {
                     textAnimator.setTextStyle(
                         TextAnimator.Style(fVar = lsFontVariation),
@@ -430,8 +432,10 @@
 
     /** Returns the interpolated text bounding rect based on interpolation progress */
     private fun getInterpolatedTextBounds(progress: Float = getInterpolatedProgress()): RectF {
-        if (!textAnimator.isRunning || progress >= 1f) {
-            return RectF(targetTextBounds)
+        if (progress <= 0f) {
+            return prevTextBounds
+        } else if (!textAnimator.isRunning || progress >= 1f) {
+            return targetTextBounds
         }
 
         return RectF().apply {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
index 0cfb36d..446891a 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/AuthContainerViewTest.kt
@@ -531,20 +531,23 @@
 
     @Test
     fun testLayoutParams_hasSecureWindowFlag() {
-        val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
+        val layoutParams =
+            AuthContainerView.getLayoutParams(windowToken, "", false /* isCredentialView */)
         assertThat((layoutParams.flags and WindowManager.LayoutParams.FLAG_SECURE) != 0).isTrue()
     }
 
     @Test
     fun testLayoutParams_hasShowWhenLockedFlag() {
-        val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
+        val layoutParams =
+            AuthContainerView.getLayoutParams(windowToken, "", false /* isCredentialView */)
         assertThat((layoutParams.flags and WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED) != 0)
             .isTrue()
     }
 
     @Test
     fun testLayoutParams_hasDimbehindWindowFlag() {
-        val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
+        val layoutParams =
+            AuthContainerView.getLayoutParams(windowToken, "", false /* isCredentialView */)
         val lpFlags = layoutParams.flags
         val lpDimAmount = layoutParams.dimAmount
 
@@ -554,7 +557,8 @@
 
     @Test
     fun testLayoutParams_excludesImeInsets() {
-        val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
+        val layoutParams =
+            AuthContainerView.getLayoutParams(windowToken, "", false /* isCredentialView */)
         assertThat((layoutParams.fitInsetsTypes and WindowInsets.Type.ime()) == 0).isTrue()
     }
 
@@ -706,7 +710,8 @@
 
     @Test
     fun testLayoutParams_hasCutoutModeAlwaysFlag() {
-        val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
+        val layoutParams =
+            AuthContainerView.getLayoutParams(windowToken, "", false /* isCredentialView */)
         val lpFlags = layoutParams.flags
 
         assertThat(
@@ -717,7 +722,8 @@
 
     @Test
     fun testLayoutParams_excludesSystemBarInsets() {
-        val layoutParams = AuthContainerView.getLayoutParams(windowToken, "")
+        val layoutParams =
+            AuthContainerView.getLayoutParams(windowToken, "", false /* isCredentialView */)
         assertThat((layoutParams.fitInsetsTypes and WindowInsets.Type.systemBars()) == 0).isTrue()
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
index aeea99b..a2f5a30 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsControllerTest.java
@@ -193,8 +193,6 @@
     @Mock
     private UdfpsOverlayInteractor mUdfpsOverlayInteractor;
     @Mock
-    private UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
-    @Mock
     private SelectedUserInteractor mSelectedUserInteractor;
 
     // Capture listeners so that they can be used to send events
@@ -321,7 +319,6 @@
                 mAlternateBouncerInteractor,
                 mInputManager,
                 mock(DeviceEntryFaceAuthInteractor.class),
-                mUdfpsKeyguardAccessibilityDelegate,
                 mSelectedUserInteractor,
                 mKeyguardTransitionInteractor,
                 mDeviceEntryUdfpsTouchOverlayViewModel,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegateTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegateTest.kt
deleted file mode 100644
index 921ff09..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegateTest.kt
+++ /dev/null
@@ -1,86 +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.biometrics
-
-import android.testing.TestableLooper
-import android.view.View
-import android.view.accessibility.AccessibilityNodeInfo
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
-import com.android.systemui.util.mockito.argumentCaptor
-import org.junit.Assert.assertEquals
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers.anyBoolean
-import org.mockito.Mock
-import org.mockito.Mockito.mock
-import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
-
-@RunWith(AndroidJUnit4::class)
-@SmallTest
-@TestableLooper.RunWithLooper
-class UdfpsKeyguardAccessibilityDelegateTest : SysuiTestCase() {
-
-    @Mock private lateinit var keyguardViewManager: StatusBarKeyguardViewManager
-    @Mock private lateinit var hostView: View
-    private lateinit var underTest: UdfpsKeyguardAccessibilityDelegate
-
-    @Before
-    fun setUp() {
-        MockitoAnnotations.initMocks(this)
-        underTest =
-            UdfpsKeyguardAccessibilityDelegate(
-                context.resources,
-                keyguardViewManager,
-            )
-    }
-
-    @Test
-    fun onInitializeAccessibilityNodeInfo_clickActionAdded() {
-        // WHEN node is initialized
-        val mockedNodeInfo = mock(AccessibilityNodeInfo::class.java)
-        underTest.onInitializeAccessibilityNodeInfo(hostView, mockedNodeInfo)
-
-        // THEN a11y action is added
-        val argumentCaptor = argumentCaptor<AccessibilityNodeInfo.AccessibilityAction>()
-        verify(mockedNodeInfo).addAction(argumentCaptor.capture())
-
-        // AND the a11y action is a click action
-        assertEquals(
-            AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id,
-            argumentCaptor.value.id
-        )
-    }
-
-    @Test
-    fun performAccessibilityAction_actionClick_showsPrimaryBouncer() {
-        // WHEN click action is performed
-        val mockedNodeInfo = mock(AccessibilityNodeInfo::class.java)
-        underTest.performAccessibilityAction(
-            hostView,
-            AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id,
-            null
-        )
-
-        // THEN primary bouncer shows
-        verify(keyguardViewManager).showPrimaryBouncer(anyBoolean())
-    }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
index 682ad0c5..754011b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorTest.kt
@@ -125,7 +125,9 @@
                 bluetoothTileDialogAudioSharingRepository.emitAudioSourceStateUpdate()
                 runCurrent()
 
-                assertThat(value).isNull()
+                assertThat(value).isEqualTo(Unit)
+                verify(bluetoothTileDialogLogger).logAudioSharingStateChanged(true)
+                verify(bluetoothTileDialogLogger).logAudioSourceStateUpdate()
             }
         }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
index 587f3cc8..159c15b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepositoryTest.kt
@@ -62,6 +62,7 @@
             AudioSharingRepositoryImpl(
                 kosmos.localBluetoothManager,
                 kosmos.audioSharingRepository,
+                kosmos.bluetoothTileDialogLogger,
                 kosmos.testDispatcher,
             )
     }
@@ -95,6 +96,8 @@
                 audioSharingRepository.setAudioSharingAvailable(true)
                 underTest.startAudioSharing()
                 verify(leAudioBroadcastProfile).startPrivateBroadcast()
+                verify(bluetoothTileDialogLogger)
+                    .logAudioSharingRequest(AudioSharingRequest.START_BROADCAST)
             }
         }
 
@@ -105,6 +108,8 @@
                 audioSharingRepository.setAudioSharingAvailable(false)
                 underTest.startAudioSharing()
                 verify(leAudioBroadcastProfile, never()).startPrivateBroadcast()
+                verify(bluetoothTileDialogLogger, never())
+                    .logAudioSharingRequest(AudioSharingRequest.START_BROADCAST)
             }
         }
 
@@ -117,6 +122,8 @@
                 audioSharingRepository.setAudioSharingAvailable(true)
                 underTest.stopAudioSharing()
                 verify(leAudioBroadcastProfile).stopLatestBroadcast()
+                verify(bluetoothTileDialogLogger)
+                    .logAudioSharingRequest(AudioSharingRequest.STOP_BROADCAST)
             }
         }
 
@@ -140,6 +147,7 @@
                 runCurrent()
 
                 verify(leAudioBroadcastAssistant, never()).allConnectedDevices
+                verify(bluetoothTileDialogLogger, never()).logAudioSharingRequest(any())
             }
         }
 
@@ -157,6 +165,7 @@
                 runCurrent()
 
                 verify(leAudioBroadcastAssistant, never()).allConnectedDevices
+                verify(bluetoothTileDialogLogger, never()).logAudioSharingRequest(any())
             }
         }
 
@@ -177,6 +186,7 @@
                 runCurrent()
 
                 verify(leAudioBroadcastAssistant, never()).addSource(any(), any(), anyBoolean())
+                verify(bluetoothTileDialogLogger, never()).logAudioSharingRequest(any())
             }
         }
 
@@ -198,6 +208,8 @@
                 runCurrent()
 
                 verify(leAudioBroadcastAssistant).addSource(bluetoothDevice, metadata, false)
+                verify(bluetoothTileDialogLogger)
+                    .logAudioSharingRequest(AudioSharingRequest.ADD_SOURCE)
             }
         }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ActionIntentCreatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ActionIntentCreatorTest.kt
new file mode 100644
index 0000000..239e026
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/ActionIntentCreatorTest.kt
@@ -0,0 +1,150 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.clipboardoverlay
+
+import android.content.ClipData
+import android.content.ComponentName
+import android.content.Intent
+import android.net.Uri
+import android.text.SpannableString
+import androidx.test.filters.SmallTest
+import androidx.test.runner.AndroidJUnit4
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class ActionIntentCreatorTest : SysuiTestCase() {
+    val creator = ActionIntentCreator()
+
+    @Test
+    fun test_getTextEditorIntent() {
+        val intent = creator.getTextEditorIntent(context)
+        assertEquals(ComponentName(context, EditTextActivity::class.java), intent.component)
+        assertFlags(intent, Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+    }
+
+    @Test
+    fun test_getRemoteCopyIntent() {
+        context.getOrCreateTestableResources().addOverride(R.string.config_remoteCopyPackage, "")
+
+        val clipData = ClipData.newPlainText("Test", "Test Item")
+        var intent = creator.getRemoteCopyIntent(clipData, context)
+
+        assertEquals(null, intent.component)
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS)
+        assertEquals(clipData, intent.clipData)
+
+        // Try again with a remote copy component
+        val fakeComponent =
+            ComponentName("com.android.remotecopy", "com.android.remotecopy.RemoteCopyActivity")
+        context
+            .getOrCreateTestableResources()
+            .addOverride(R.string.config_remoteCopyPackage, fakeComponent.flattenToString())
+
+        intent = creator.getRemoteCopyIntent(clipData, context)
+        assertEquals(fakeComponent, intent.component)
+    }
+
+    @Test
+    fun test_getImageEditIntent() {
+        context.getOrCreateTestableResources().addOverride(R.string.config_screenshotEditor, "")
+        val fakeUri = Uri.parse("content://foo")
+        var intent = creator.getImageEditIntent(fakeUri, context)
+
+        assertEquals(Intent.ACTION_EDIT, intent.action)
+        assertEquals("image/*", intent.type)
+        assertEquals(null, intent.component)
+        assertEquals("clipboard", intent.getStringExtra("edit_source"))
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS)
+
+        // try again with an editor component
+        val fakeComponent =
+            ComponentName("com.android.remotecopy", "com.android.remotecopy.RemoteCopyActivity")
+        context
+            .getOrCreateTestableResources()
+            .addOverride(R.string.config_screenshotEditor, fakeComponent.flattenToString())
+        intent = creator.getImageEditIntent(fakeUri, context)
+        assertEquals(fakeComponent, intent.component)
+    }
+
+    @Test
+    fun test_getShareIntent_plaintext() {
+        val clipData = ClipData.newPlainText("Test", "Test Item")
+        val intent = creator.getShareIntent(clipData, context)
+
+        assertEquals(Intent.ACTION_CHOOSER, intent.action)
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS)
+        val target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+        assertEquals("Test Item", target?.getStringExtra(Intent.EXTRA_TEXT))
+        assertEquals("text/plain", target?.type)
+    }
+
+    @Test
+    fun test_getShareIntent_html() {
+        val clipData = ClipData.newHtmlText("Test", "Some HTML", "<b>Some HTML</b>")
+        val intent = creator.getShareIntent(clipData, getContext())
+
+        assertEquals(Intent.ACTION_CHOOSER, intent.action)
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS)
+        val target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+        assertEquals("Some HTML", target?.getStringExtra(Intent.EXTRA_TEXT))
+        assertEquals("text/plain", target?.type)
+    }
+
+    @Test
+    fun test_getShareIntent_image() {
+        val uri = Uri.parse("content://something")
+        val clipData = ClipData("Test", arrayOf("image/png"), ClipData.Item(uri))
+        val intent = creator.getShareIntent(clipData, context)
+
+        assertEquals(Intent.ACTION_CHOOSER, intent.action)
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS)
+        val target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+        assertEquals(uri, target?.getParcelableExtra(Intent.EXTRA_STREAM, Uri::class.java))
+        assertEquals(uri, target?.clipData?.getItemAt(0)?.uri)
+        assertEquals("image/png", target?.type)
+    }
+
+    @Test
+    fun test_getShareIntent_spannableText() {
+        val clipData = ClipData.newPlainText("Test", SpannableString("Test Item"))
+        val intent = creator.getShareIntent(clipData, context)
+
+        assertEquals(Intent.ACTION_CHOOSER, intent.action)
+        assertFlags(intent, EXTERNAL_INTENT_FLAGS)
+        val target = intent.getParcelableExtra(Intent.EXTRA_INTENT, Intent::class.java)
+        assertEquals("Test Item", target?.getStringExtra(Intent.EXTRA_TEXT))
+        assertEquals("text/plain", target?.type)
+    }
+
+    // Assert that the given flags are set
+    private fun assertFlags(intent: Intent, flags: Int) {
+        assertTrue((intent.flags and flags) == flags)
+    }
+
+    companion object {
+        private const val EXTERNAL_INTENT_FLAGS: Int =
+            (Intent.FLAG_ACTIVITY_NEW_TASK or
+                Intent.FLAG_ACTIVITY_CLEAR_TASK or
+                Intent.FLAG_GRANT_READ_URI_PERMISSION)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/DefaultIntentCreatorTest.java
similarity index 87%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/DefaultIntentCreatorTest.java
index ea6cb3b..126b3fa 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/IntentCreatorTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/clipboardoverlay/DefaultIntentCreatorTest.java
@@ -36,13 +36,15 @@
 
 @SmallTest
 @RunWith(AndroidJUnit4.class)
-public class IntentCreatorTest extends SysuiTestCase {
+public class DefaultIntentCreatorTest extends SysuiTestCase {
     private static final int EXTERNAL_INTENT_FLAGS = Intent.FLAG_ACTIVITY_NEW_TASK
             | Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_GRANT_READ_URI_PERMISSION;
 
+    private final DefaultIntentCreator mIntentCreator  = new DefaultIntentCreator();
+
     @Test
     public void test_getTextEditorIntent() {
-        Intent intent = IntentCreator.getTextEditorIntent(getContext());
+        Intent intent = mIntentCreator.getTextEditorIntent(getContext());
         assertEquals(new ComponentName(getContext(), EditTextActivity.class),
                 intent.getComponent());
         assertFlags(intent, Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
@@ -54,7 +56,7 @@
                 "");
 
         ClipData clipData = ClipData.newPlainText("Test", "Test Item");
-        Intent intent = IntentCreator.getRemoteCopyIntent(clipData, getContext());
+        Intent intent = mIntentCreator.getRemoteCopyIntent(clipData, getContext());
 
         assertEquals(null, intent.getComponent());
         assertFlags(intent, EXTERNAL_INTENT_FLAGS);
@@ -66,7 +68,7 @@
         getContext().getOrCreateTestableResources().addOverride(R.string.config_remoteCopyPackage,
                 fakeComponent.flattenToString());
 
-        intent = IntentCreator.getRemoteCopyIntent(clipData, getContext());
+        intent = mIntentCreator.getRemoteCopyIntent(clipData, getContext());
         assertEquals(fakeComponent, intent.getComponent());
     }
 
@@ -75,7 +77,7 @@
         getContext().getOrCreateTestableResources().addOverride(R.string.config_screenshotEditor,
                 "");
         Uri fakeUri = Uri.parse("content://foo");
-        Intent intent = IntentCreator.getImageEditIntent(fakeUri, getContext());
+        Intent intent = mIntentCreator.getImageEditIntent(fakeUri, getContext());
 
         assertEquals(Intent.ACTION_EDIT, intent.getAction());
         assertEquals("image/*", intent.getType());
@@ -88,14 +90,14 @@
                 "com.android.remotecopy.RemoteCopyActivity");
         getContext().getOrCreateTestableResources().addOverride(R.string.config_screenshotEditor,
                 fakeComponent.flattenToString());
-        intent = IntentCreator.getImageEditIntent(fakeUri, getContext());
+        intent = mIntentCreator.getImageEditIntent(fakeUri, getContext());
         assertEquals(fakeComponent, intent.getComponent());
     }
 
     @Test
     public void test_getShareIntent_plaintext() {
         ClipData clipData = ClipData.newPlainText("Test", "Test Item");
-        Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+        Intent intent = mIntentCreator.getShareIntent(clipData, getContext());
 
         assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
         assertFlags(intent, EXTERNAL_INTENT_FLAGS);
@@ -108,7 +110,7 @@
     public void test_getShareIntent_html() {
         ClipData clipData = ClipData.newHtmlText("Test", "Some HTML",
                 "<b>Some HTML</b>");
-        Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+        Intent intent = mIntentCreator.getShareIntent(clipData, getContext());
 
         assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
         assertFlags(intent, EXTERNAL_INTENT_FLAGS);
@@ -122,7 +124,7 @@
         Uri uri = Uri.parse("content://something");
         ClipData clipData = new ClipData("Test", new String[]{"image/png"},
                 new ClipData.Item(uri));
-        Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+        Intent intent = mIntentCreator.getShareIntent(clipData, getContext());
 
         assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
         assertFlags(intent, EXTERNAL_INTENT_FLAGS);
@@ -135,7 +137,7 @@
     @Test
     public void test_getShareIntent_spannableText() {
         ClipData clipData = ClipData.newPlainText("Test", new SpannableString("Test Item"));
-        Intent intent = IntentCreator.getShareIntent(clipData, getContext());
+        Intent intent = mIntentCreator.getShareIntent(clipData, getContext());
 
         assertEquals(Intent.ACTION_CHOOSER, intent.getAction());
         assertFlags(intent, EXTERNAL_INTENT_FLAGS);
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/common/domain/interactor/SysUIStatePerDisplayInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/domain/interactor/SysUIStatePerDisplayInteractorTest.kt
new file mode 100644
index 0000000..f64f13d
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/common/domain/interactor/SysUIStatePerDisplayInteractorTest.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.common.domain.interactor
+
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.model.StateChange
+import com.android.systemui.model.fakeSysUIStatePerDisplayRepository
+import com.android.systemui.model.sysUiStateFactory
+import com.android.systemui.model.sysuiStateInteractor
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import kotlinx.coroutines.runBlocking
+import org.junit.Before
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SysUIStatePerDisplayInteractorTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+
+    val stateRepository = kosmos.fakeSysUIStatePerDisplayRepository
+    val state0 = kosmos.sysUiStateFactory.create(0)
+    val state1 = kosmos.sysUiStateFactory.create(1)
+    val state2 = kosmos.sysUiStateFactory.create(2)
+
+    val underTest = kosmos.sysuiStateInteractor
+
+    @Before
+    fun setup() {
+        stateRepository.apply {
+            add(0, state0)
+            add(1, state1)
+            add(2, state2)
+        }
+        runBlocking {
+            kosmos.displayRepository.apply {
+                addDisplay(0)
+                addDisplay(1)
+                addDisplay(2)
+            }
+        }
+    }
+
+    @Test
+    fun setFlagsExclusivelyToDisplay_setsFlagsOnTargetStateAndClearsTheOthers() {
+        val targetDisplayId = 0
+        val stateChange = StateChange().setFlag(1L, true)
+
+        underTest.setFlagsExclusivelyToDisplay(targetDisplayId, stateChange)
+
+        assertThat(state0.isFlagEnabled(1)).isTrue()
+        assertThat(state1.isFlagEnabled(1)).isFalse()
+        assertThat(state2.isFlagEnabled(1)).isFalse()
+
+        underTest.setFlagsExclusivelyToDisplay(1, stateChange)
+
+        assertThat(state0.isFlagEnabled(1)).isFalse()
+        assertThat(state1.isFlagEnabled(1)).isTrue()
+        assertThat(state2.isFlagEnabled(1)).isFalse()
+
+        underTest.setFlagsExclusivelyToDisplay(2, stateChange)
+
+        assertThat(state0.isFlagEnabled(1)).isFalse()
+        assertThat(state1.isFlagEnabled(1)).isFalse()
+        assertThat(state2.isFlagEnabled(1)).isTrue()
+
+        underTest.setFlagsExclusivelyToDisplay(3, stateChange)
+
+        assertThat(state0.isFlagEnabled(1)).isFalse()
+        assertThat(state1.isFlagEnabled(1)).isFalse()
+        assertThat(state2.isFlagEnabled(1)).isFalse()
+    }
+
+    @Test
+    fun setFlagsExclusivelyToDisplay_multipleFlags_setsFlagsOnTargetStateAndClearsTheOthers() {
+        val stateChange = StateChange().setFlag(1L, true).setFlag(2L, true)
+
+        underTest.setFlagsExclusivelyToDisplay(1, stateChange)
+
+        assertThat(state0.isFlagEnabled(1)).isFalse()
+        assertThat(state0.isFlagEnabled(2)).isFalse()
+        assertThat(state1.isFlagEnabled(1)).isTrue()
+        assertThat(state1.isFlagEnabled(2)).isTrue()
+        assertThat(state2.isFlagEnabled(1)).isFalse()
+        assertThat(state2.isFlagEnabled(1)).isFalse()
+    }
+
+    @Test
+    fun setFlagsExclusivelyToDisplay_clearsFlags() {
+        state0.setFlag(1, true).setFlag(2, true).commitUpdate()
+        state1.setFlag(1, true).setFlag(2, true).commitUpdate()
+        state2.setFlag(1, true).setFlag(2, true).commitUpdate()
+
+        val stateChange = StateChange().setFlag(1L, false)
+
+        underTest.setFlagsExclusivelyToDisplay(1, stateChange)
+
+        // Sets it as false in display 1, but also the others.
+        assertThat(state0.isFlagEnabled(1)).isFalse()
+        assertThat(state1.isFlagEnabled(1)).isFalse()
+        assertThat(state2.isFlagEnabled(1)).isFalse()
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
index f47aa6b..8dc7a33 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/communal/view/viewmodel/CommunalViewModelTest.kt
@@ -32,6 +32,8 @@
 import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.bouncer.data.repository.fakeKeyguardBouncerRepository
+import com.android.systemui.common.data.repository.batteryRepository
+import com.android.systemui.common.data.repository.fake
 import com.android.systemui.communal.data.model.CommunalSmartspaceTimer
 import com.android.systemui.communal.data.repository.FakeCommunalMediaRepository
 import com.android.systemui.communal.data.repository.FakeCommunalSceneRepository
@@ -48,6 +50,7 @@
 import com.android.systemui.communal.domain.interactor.communalSceneInteractor
 import com.android.systemui.communal.domain.interactor.communalSettingsInteractor
 import com.android.systemui.communal.domain.interactor.communalTutorialInteractor
+import com.android.systemui.communal.domain.interactor.setCommunalV2ConfigEnabled
 import com.android.systemui.communal.domain.model.CommunalContentModel
 import com.android.systemui.communal.shared.log.CommunalMetricsLogger
 import com.android.systemui.communal.shared.model.CommunalContentSize
@@ -73,6 +76,8 @@
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.keyguard.ui.transitions.blurConfig
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runTest
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.log.logcatLogBuffer
@@ -96,6 +101,7 @@
 import com.android.systemui.testKosmos
 import com.android.systemui.user.data.repository.FakeUserRepository
 import com.android.systemui.user.data.repository.fakeUserRepository
+import com.android.systemui.util.settings.fakeSettings
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.test.advanceTimeBy
@@ -940,6 +946,36 @@
             assertThat(isUiBlurred).isFalse()
         }
 
+    @Test
+    @EnableFlags(FLAG_GLANCEABLE_HUB_V2)
+    fun swipeToCommunal() =
+        kosmos.runTest {
+            setCommunalV2ConfigEnabled(true)
+            val mainUser = fakeUserRepository.asMainUser()
+            fakeKeyguardRepository.setKeyguardShowing(true)
+            fakeUserRepository.setUserUnlocked(mainUser.id, true)
+            fakeUserTracker.set(userInfos = listOf(mainUser), selectedUserIndex = 0)
+            fakeSettings.putIntForUser(
+                Settings.Secure.SCREENSAVER_ACTIVATE_ON_SLEEP,
+                1,
+                mainUser.id,
+            )
+
+            val viewModel = createViewModel()
+            val swipeToHubEnabled by collectLastValue(viewModel.swipeToHubEnabled)
+            assertThat(swipeToHubEnabled).isFalse()
+
+            batteryRepository.fake.setDevicePluggedIn(true)
+            assertThat(swipeToHubEnabled).isTrue()
+
+            keyguardTransitionRepository.sendTransitionStep(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.AOD,
+                transitionState = TransitionState.STARTED,
+            )
+            assertThat(swipeToHubEnabled).isFalse()
+        }
+
     private suspend fun setIsMainUser(isMainUser: Boolean) {
         val user = if (isMainUser) MAIN_USER_INFO else SECONDARY_USER_INFO
         with(userRepository) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayInstanceRepositoryImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayInstanceRepositoryImplTest.kt
new file mode 100644
index 0000000..e41d46c
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/display/data/repository/PerDisplayInstanceRepositoryImplTest.kt
@@ -0,0 +1,119 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyString
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.verify
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class PerDisplayInstanceRepositoryImplTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+    private val testScope = kosmos.testScope
+    private val fakeDisplayRepository = kosmos.displayRepository
+    private val fakePerDisplayInstanceProviderWithTeardown =
+        kosmos.fakePerDisplayInstanceProviderWithTeardown
+
+    private val underTest: PerDisplayInstanceRepositoryImpl<TestPerDisplayInstance> =
+        kosmos.fakePerDisplayInstanceRepository
+
+    @Before
+    fun addDisplays() = runBlocking {
+        fakeDisplayRepository += createDisplay(DEFAULT_DISPLAY_ID)
+        fakeDisplayRepository += createDisplay(NON_DEFAULT_DISPLAY_ID)
+    }
+
+    @Test
+    fun forDisplay_defaultDisplay_multipleCalls_returnsSameInstance() =
+        testScope.runTest {
+            val instance = underTest[DEFAULT_DISPLAY_ID]
+
+            assertThat(underTest[DEFAULT_DISPLAY_ID]).isSameInstanceAs(instance)
+        }
+
+    @Test
+    fun forDisplay_nonDefaultDisplay_multipleCalls_returnsSameInstance() =
+        testScope.runTest {
+            val instance = underTest[NON_DEFAULT_DISPLAY_ID]
+
+            assertThat(underTest[NON_DEFAULT_DISPLAY_ID]).isSameInstanceAs(instance)
+        }
+
+    @Test
+    fun forDisplay_nonDefaultDisplay_afterDisplayRemoved_returnsNewInstance() =
+        testScope.runTest {
+            val instance = underTest[NON_DEFAULT_DISPLAY_ID]
+
+            fakeDisplayRepository -= NON_DEFAULT_DISPLAY_ID
+            fakeDisplayRepository += createDisplay(NON_DEFAULT_DISPLAY_ID)
+
+            assertThat(underTest[NON_DEFAULT_DISPLAY_ID]).isNotSameInstanceAs(instance)
+        }
+
+    @Test
+    fun forDisplay_nonExistingDisplayId_returnsNull() =
+        testScope.runTest { assertThat(underTest[NON_EXISTING_DISPLAY_ID]).isNull() }
+
+    @Test
+    fun forDisplay_afterDisplayRemoved_destroyInstanceInvoked() =
+        testScope.runTest {
+            val instance = underTest[NON_DEFAULT_DISPLAY_ID]
+
+            fakeDisplayRepository -= NON_DEFAULT_DISPLAY_ID
+
+            assertThat(fakePerDisplayInstanceProviderWithTeardown.destroyed)
+                .containsExactly(instance)
+        }
+
+    @Test
+    fun forDisplay_withoutDisplayRemoval_destroyInstanceIsNotInvoked() =
+        testScope.runTest {
+            underTest[NON_DEFAULT_DISPLAY_ID]
+
+            assertThat(fakePerDisplayInstanceProviderWithTeardown.destroyed).isEmpty()
+        }
+
+    @Test
+    fun start_registersDumpable() {
+        verify(kosmos.dumpManager).registerNormalDumpable(anyString(), eq(underTest))
+    }
+
+    private fun createDisplay(displayId: Int): Display =
+        display(type = Display.TYPE_INTERNAL, id = displayId)
+
+    companion object {
+        private const val DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY
+        private const val NON_DEFAULT_DISPLAY_ID = DEFAULT_DISPLAY_ID + 1
+        private const val NON_EXISTING_DISPLAY_ID = DEFAULT_DISPLAY_ID + 2
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt
index 0197a1e..c72afc7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaCarouselInteractorTest.kt
@@ -16,26 +16,17 @@
 
 package com.android.systemui.media.controls.domain.interactor
 
-import android.R
-import android.graphics.drawable.Icon
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
-import com.android.internal.logging.InstanceId
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.media.controls.MediaTestHelper
 import com.android.systemui.media.controls.data.repository.MediaFilterRepository
 import com.android.systemui.media.controls.data.repository.mediaFilterRepository
 import com.android.systemui.media.controls.domain.pipeline.interactor.MediaCarouselInteractor
-import com.android.systemui.media.controls.domain.pipeline.interactor.MediaRecommendationsInteractor
 import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor
-import com.android.systemui.media.controls.domain.pipeline.interactor.mediaRecommendationsInteractor
-import com.android.systemui.media.controls.shared.model.MediaCommonModel
 import com.android.systemui.media.controls.shared.model.MediaData
 import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel
-import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
-import com.android.systemui.media.controls.shared.model.SmartspaceMediaLoadingModel
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.test.runTest
@@ -52,16 +43,6 @@
 
     private val mediaFilterRepository: MediaFilterRepository =
         with(kosmos) { mediaFilterRepository }
-    private val mediaRecommendationsInteractor: MediaRecommendationsInteractor =
-        kosmos.mediaRecommendationsInteractor
-    val icon = Icon.createWithResource(context, R.drawable.ic_media_play)
-    private val mediaRecommendation =
-        SmartspaceMediaData(
-            targetId = KEY_MEDIA_SMARTSPACE,
-            isActive = true,
-            packageName = PACKAGE_NAME,
-            recommendations = MediaTestHelper.getValidRecommendationList(icon),
-        )
 
     private val underTest: MediaCarouselInteractor = kosmos.mediaCarouselInteractor
 
@@ -119,81 +100,6 @@
         }
 
     @Test
-    fun addActiveRecommendation_inactiveMedia() =
-        testScope.runTest {
-            val hasActiveMediaOrRecommendation by
-                collectLastValue(underTest.hasActiveMediaOrRecommendation)
-            val hasAnyMediaOrRecommendation by
-                collectLastValue(underTest.hasAnyMediaOrRecommendation)
-            val currentMedia by collectLastValue(underTest.currentMedia)
-
-            val userMedia = MediaData(active = false)
-            val recsLoadingModel = SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE, true)
-            val mediaLoadingModel = MediaDataLoadingModel.Loaded(userMedia.instanceId)
-
-            mediaFilterRepository.setRecommendation(mediaRecommendation)
-            mediaFilterRepository.setRecommendationsLoadingState(recsLoadingModel)
-
-            assertThat(hasActiveMediaOrRecommendation).isTrue()
-            assertThat(hasAnyMediaOrRecommendation).isTrue()
-            assertThat(currentMedia)
-                .containsExactly(MediaCommonModel.MediaRecommendations(recsLoadingModel))
-
-            mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
-            mediaFilterRepository.addMediaDataLoadingState(mediaLoadingModel)
-            mediaFilterRepository.setOrderedMedia()
-
-            assertThat(hasActiveMediaOrRecommendation).isTrue()
-            assertThat(hasAnyMediaOrRecommendation).isTrue()
-            assertThat(currentMedia)
-                .containsExactly(
-                    MediaCommonModel.MediaRecommendations(recsLoadingModel),
-                    MediaCommonModel.MediaControl(mediaLoadingModel, true),
-                )
-                .inOrder()
-        }
-
-    @Test
-    fun addActiveRecommendation_thenInactive() =
-        testScope.runTest {
-            val hasActiveMediaOrRecommendation by
-                collectLastValue(underTest.hasActiveMediaOrRecommendation)
-            val hasAnyMediaOrRecommendation by
-                collectLastValue(underTest.hasAnyMediaOrRecommendation)
-
-            mediaFilterRepository.setRecommendation(mediaRecommendation)
-
-            assertThat(hasActiveMediaOrRecommendation).isTrue()
-            assertThat(hasAnyMediaOrRecommendation).isTrue()
-
-            mediaFilterRepository.setRecommendation(mediaRecommendation.copy(isActive = false))
-
-            assertThat(hasActiveMediaOrRecommendation).isFalse()
-            assertThat(hasAnyMediaOrRecommendation).isFalse()
-        }
-
-    @Test
-    fun addActiveRecommendation_thenInvalid() =
-        testScope.runTest {
-            val hasActiveMediaOrRecommendation by
-                collectLastValue(underTest.hasActiveMediaOrRecommendation)
-            val hasAnyMediaOrRecommendation by
-                collectLastValue(underTest.hasAnyMediaOrRecommendation)
-
-            mediaFilterRepository.setRecommendation(mediaRecommendation)
-
-            assertThat(hasActiveMediaOrRecommendation).isTrue()
-            assertThat(hasAnyMediaOrRecommendation).isTrue()
-
-            mediaFilterRepository.setRecommendation(
-                mediaRecommendation.copy(recommendations = listOf())
-            )
-
-            assertThat(hasActiveMediaOrRecommendation).isFalse()
-            assertThat(hasAnyMediaOrRecommendation).isFalse()
-        }
-
-    @Test
     fun hasAnyMedia_noMediaSet_returnsFalse() =
         testScope.runTest { assertThat(underTest.hasAnyMedia()).isFalse() }
 
@@ -208,47 +114,4 @@
     @Test
     fun hasActiveMediaOrRecommendation_nothingSet_returnsFalse() =
         testScope.runTest { assertThat(underTest.hasActiveMediaOrRecommendation.value).isFalse() }
-
-    @Test
-    fun loadMediaFromRec() =
-        testScope.runTest {
-            val currentMedia by collectLastValue(underTest.currentMedia)
-            val instanceId = InstanceId.fakeInstanceId(123)
-            val data =
-                MediaData(
-                    active = true,
-                    instanceId = instanceId,
-                    packageName = PACKAGE_NAME,
-                    notificationKey = KEY,
-                )
-            val smartspaceLoadingModel = SmartspaceMediaLoadingModel.Loaded(KEY_MEDIA_SMARTSPACE)
-            val mediaLoadingModel = MediaDataLoadingModel.Loaded(instanceId)
-
-            mediaFilterRepository.setRecommendation(mediaRecommendation)
-            mediaFilterRepository.setRecommendationsLoadingState(smartspaceLoadingModel)
-            mediaRecommendationsInteractor.switchToMediaControl(PACKAGE_NAME)
-            mediaFilterRepository.addSelectedUserMediaEntry(data)
-            mediaFilterRepository.addMediaDataLoadingState(mediaLoadingModel)
-
-            assertThat(currentMedia)
-                .containsExactly(MediaCommonModel.MediaRecommendations(smartspaceLoadingModel))
-                .inOrder()
-
-            mediaFilterRepository.addSelectedUserMediaEntry(data.copy(isPlaying = true))
-            mediaFilterRepository.addMediaDataLoadingState(mediaLoadingModel)
-
-            assertThat(currentMedia)
-                .containsExactly(
-                    MediaCommonModel.MediaControl(mediaLoadingModel, isMediaFromRec = true),
-                    MediaCommonModel.MediaRecommendations(smartspaceLoadingModel),
-                )
-                .inOrder()
-        }
-
-    companion object {
-        private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
-        private const val PACKAGE_NAME = "com.android.example"
-        private const val KEY = "key"
-        private const val SURFACE = 4
-    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaRecommendationsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaRecommendationsInteractorTest.kt
deleted file mode 100644
index 2265c01..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/domain/interactor/MediaRecommendationsInteractorTest.kt
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.controls.domain.interactor
-
-import android.R
-import android.content.ComponentName
-import android.content.Intent
-import android.content.applicationContext
-import android.graphics.drawable.Icon
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.animation.Expandable
-import com.android.systemui.broadcast.broadcastSender
-import com.android.systemui.broadcast.mockBroadcastSender
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.media.controls.MediaTestHelper
-import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl
-import com.android.systemui.media.controls.domain.pipeline.interactor.MediaRecommendationsInteractor
-import com.android.systemui.media.controls.domain.pipeline.interactor.MediaRecommendationsInteractor.Companion.EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME
-import com.android.systemui.media.controls.domain.pipeline.interactor.mediaRecommendationsInteractor
-import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter
-import com.android.systemui.media.controls.shared.model.MediaRecModel
-import com.android.systemui.media.controls.shared.model.MediaRecommendationsModel
-import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
-import com.android.systemui.plugins.activityStarter
-import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.runTest
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.doNothing
-import org.mockito.Mockito.spy
-import org.mockito.Mockito.verify
-import org.mockito.kotlin.eq
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class MediaRecommendationsInteractorTest : SysuiTestCase() {
-
-    private val spyContext = spy(context)
-    private val kosmos = testKosmos().apply { applicationContext = spyContext }
-    private val testScope = kosmos.testScope
-
-    private val mediaDataFilter: MediaDataFilterImpl = with(kosmos) { mediaDataFilter }
-    private val activityStarter = kosmos.activityStarter
-    private val icon: Icon = Icon.createWithResource(context, R.drawable.ic_media_play)
-    private val smartspaceMediaData: SmartspaceMediaData =
-        SmartspaceMediaData(
-            targetId = KEY_MEDIA_SMARTSPACE,
-            isActive = true,
-            packageName = PACKAGE_NAME,
-            recommendations = MediaTestHelper.getValidRecommendationList(icon),
-        )
-
-    private val underTest: MediaRecommendationsInteractor =
-        with(kosmos) {
-            broadcastSender = mockBroadcastSender
-            kosmos.mediaRecommendationsInteractor
-        }
-
-    @Test
-    fun addRecommendation_smartspaceMediaDataUpdate() =
-        testScope.runTest {
-            val recommendations by collectLastValue(underTest.recommendations)
-
-            val model =
-                MediaRecommendationsModel(
-                    key = KEY_MEDIA_SMARTSPACE,
-                    packageName = PACKAGE_NAME,
-                    areRecommendationsValid = true,
-                    mediaRecs =
-                        listOf(
-                            MediaRecModel(icon = icon),
-                            MediaRecModel(icon = icon),
-                            MediaRecModel(icon = icon),
-                        ),
-                )
-
-            mediaDataFilter.onSmartspaceMediaDataLoaded(KEY_MEDIA_SMARTSPACE, smartspaceMediaData)
-
-            assertThat(recommendations).isEqualTo(model)
-        }
-
-    @Test
-    fun addInvalidRecommendation() =
-        testScope.runTest {
-            val recommendations by collectLastValue(underTest.recommendations)
-            val inValidData = smartspaceMediaData.copy(recommendations = listOf())
-
-            mediaDataFilter.onSmartspaceMediaDataLoaded(KEY_MEDIA_SMARTSPACE, smartspaceMediaData)
-            assertThat(recommendations?.areRecommendationsValid).isTrue()
-
-            mediaDataFilter.onSmartspaceMediaDataLoaded(KEY_MEDIA_SMARTSPACE, inValidData)
-            assertThat(recommendations?.areRecommendationsValid).isFalse()
-            assertThat(recommendations?.mediaRecs?.isEmpty()).isTrue()
-        }
-
-    @Test
-    fun removeRecommendation_noTrampolineActivity() {
-        val intent = Intent()
-
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-
-        mediaDataFilter.onSmartspaceMediaDataLoaded(KEY_MEDIA_SMARTSPACE, smartspaceMediaData)
-        underTest.removeMediaRecommendations(KEY_MEDIA_SMARTSPACE, intent, 0)
-
-        verify(kosmos.mockBroadcastSender).sendBroadcast(eq(intent))
-    }
-
-    @Test
-    fun removeRecommendation_usingTrampolineActivity() {
-        doNothing().whenever(spyContext).startActivity(any())
-        val intent = Intent()
-
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-        intent.component = ComponentName(PACKAGE_NAME, EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME)
-
-        underTest.removeMediaRecommendations(KEY_MEDIA_SMARTSPACE, intent, 0)
-
-        verify(spyContext).startActivity(eq(intent))
-    }
-
-    @Test
-    fun startSettings() {
-        underTest.startSettings()
-
-        verify(activityStarter).startActivity(any(), eq(true))
-    }
-
-    @Test
-    fun startClickIntent() {
-        doNothing().whenever(spyContext).startActivity(any())
-        val intent = Intent()
-        val expandable = mock<Expandable>()
-
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-
-        mediaDataFilter.onSmartspaceMediaDataLoaded(KEY_MEDIA_SMARTSPACE, smartspaceMediaData)
-        underTest.startClickIntent(expandable, intent)
-
-        verify(spyContext).startActivity(eq(intent))
-    }
-
-    companion object {
-        private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
-        private const val PACKAGE_NAME = "com.example.app"
-        private const val SURFACE = 4
-    }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/util/MediaDiffUtilTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/util/MediaDiffUtilTest.kt
index 005424b..faa62c2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/util/MediaDiffUtilTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/util/MediaDiffUtilTest.kt
@@ -23,7 +23,6 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.media.controls.ui.viewmodel.MediaCommonViewModel
 import com.android.systemui.media.controls.ui.viewmodel.mediaControlViewModel
-import com.android.systemui.media.controls.ui.viewmodel.mediaRecommendationsViewModel
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import org.junit.Assert.fail
@@ -56,25 +55,6 @@
     }
 
     @Test
-    fun newMediaRecommendationsAdded() {
-        val mediaRecs = createMediaRecommendations(KEY_MEDIA_SMARTSPACE, true)
-        val oldList = listOf<MediaCommonViewModel>()
-        val newList = listOf(mediaRecs)
-        val mediaLoadedCallback = MediaViewModelCallback(oldList, newList)
-        val mediaLoadedListUpdateCallback =
-            MediaViewModelListUpdateCallback(
-                oldList,
-                newList,
-                { commonViewModel, _ -> assertThat(commonViewModel).isEqualTo(mediaRecs) },
-                { commonViewModel, _ -> fail("Unexpected to update $commonViewModel") },
-                { fail("Unexpected to remove $it") },
-                { commonViewModel, _, _ -> fail("Unexpected to move $commonViewModel ") },
-            )
-
-        DiffUtil.calculateDiff(mediaLoadedCallback).dispatchUpdatesTo(mediaLoadedListUpdateCallback)
-    }
-
-    @Test
     fun updateMediaControl_contentChanged() {
         val mediaControl = createMediaControl(InstanceId.fakeInstanceId(123), true)
         val oldList = listOf(mediaControl)
@@ -94,25 +74,6 @@
     }
 
     @Test
-    fun updateMediaRecommendations_contentChanged() {
-        val mediaRecs = createMediaRecommendations(KEY_MEDIA_SMARTSPACE, true)
-        val oldList = listOf(mediaRecs)
-        val newList = listOf(mediaRecs.copy(key = KEY_MEDIA_SMARTSPACE_2))
-        val mediaLoadedCallback = MediaViewModelCallback(oldList, newList)
-        val mediaLoadedListUpdateCallback =
-            MediaViewModelListUpdateCallback(
-                oldList,
-                newList,
-                { commonViewModel, _ -> fail("Unexpected to add $commonViewModel") },
-                { commonViewModel, _ -> assertThat(commonViewModel).isNotEqualTo(mediaRecs) },
-                { fail("Unexpected to remove $it") },
-                { commonViewModel, _, _ -> fail("Unexpected to move $commonViewModel ") },
-            )
-
-        DiffUtil.calculateDiff(mediaLoadedCallback).dispatchUpdatesTo(mediaLoadedListUpdateCallback)
-    }
-
-    @Test
     fun mediaControlMoved() {
         val mediaControl1 = createMediaControl(InstanceId.fakeInstanceId(123), true)
         val mediaControl2 = createMediaControl(InstanceId.fakeInstanceId(456), false)
@@ -133,27 +94,6 @@
     }
 
     @Test
-    fun mediaRecommendationsMoved() {
-        val mediaControl1 = createMediaControl(InstanceId.fakeInstanceId(123), true)
-        val mediaControl2 = createMediaControl(InstanceId.fakeInstanceId(456), false)
-        val mediaRecs = createMediaRecommendations(KEY_MEDIA_SMARTSPACE, true)
-        val oldList = listOf(mediaRecs, mediaControl1, mediaControl2)
-        val newList = listOf(mediaControl1, mediaControl2, mediaRecs)
-        val mediaLoadedCallback = MediaViewModelCallback(oldList, newList)
-        val mediaLoadedListUpdateCallback =
-            MediaViewModelListUpdateCallback(
-                oldList,
-                newList,
-                { commonViewModel, _ -> fail("Unexpected to add $commonViewModel") },
-                { commonViewModel, _ -> fail("Unexpected to update $commonViewModel") },
-                { fail("Unexpected to remove $it") },
-                { commonViewModel, _, _ -> assertThat(commonViewModel).isEqualTo(mediaRecs) },
-            )
-
-        DiffUtil.calculateDiff(mediaLoadedCallback).dispatchUpdatesTo(mediaLoadedListUpdateCallback)
-    }
-
-    @Test
     fun mediaControlRemoved() {
         val mediaControl = createMediaControl(InstanceId.fakeInstanceId(123), true)
         val oldList = listOf(mediaControl)
@@ -172,25 +112,6 @@
         DiffUtil.calculateDiff(mediaLoadedCallback).dispatchUpdatesTo(mediaLoadedListUpdateCallback)
     }
 
-    @Test
-    fun mediaRecommendationsRemoved() {
-        val mediaRecs = createMediaRecommendations(KEY_MEDIA_SMARTSPACE_2, false)
-        val oldList = listOf(mediaRecs)
-        val newList = listOf<MediaCommonViewModel>()
-        val mediaLoadedCallback = MediaViewModelCallback(oldList, newList)
-        val mediaLoadedListUpdateCallback =
-            MediaViewModelListUpdateCallback(
-                oldList,
-                newList,
-                { commonViewModel, _ -> fail("Unexpected to add $commonViewModel") },
-                { commonViewModel, _ -> fail("Unexpected to update $commonViewModel") },
-                { commonViewModel -> assertThat(commonViewModel).isEqualTo(mediaRecs) },
-                { commonViewModel, _, _ -> fail("Unexpected to move $commonViewModel ") },
-            )
-
-        DiffUtil.calculateDiff(mediaLoadedCallback).dispatchUpdatesTo(mediaLoadedListUpdateCallback)
-    }
-
     private fun createMediaControl(
         instanceId: InstanceId,
         immediatelyUpdateUi: Boolean,
@@ -201,26 +122,7 @@
             controlViewModel = kosmos.mediaControlViewModel,
             onAdded = {},
             onRemoved = {},
-            onUpdated = {}
+            onUpdated = {},
         )
     }
-
-    private fun createMediaRecommendations(
-        key: String,
-        loadingEnabled: Boolean,
-    ): MediaCommonViewModel.MediaRecommendations {
-        return MediaCommonViewModel.MediaRecommendations(
-            key = key,
-            loadingEnabled = loadingEnabled,
-            recsViewModel = kosmos.mediaRecommendationsViewModel,
-            onAdded = {},
-            onRemoved = {},
-            onUpdated = {}
-        )
-    }
-
-    companion object {
-        private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
-        private const val KEY_MEDIA_SMARTSPACE_2 = "MEDIA_SMARTSPACE_ID_2"
-    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt
index fb5bbf4..e56b114 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelTest.kt
@@ -19,23 +19,18 @@
 import android.R
 import android.content.packageManager
 import android.content.pm.ApplicationInfo
-import android.graphics.drawable.Icon
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.InstanceId
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.kosmos.testScope
-import com.android.systemui.media.controls.MediaTestHelper
 import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl
 import com.android.systemui.media.controls.domain.pipeline.interactor.mediaCarouselInteractor
-import com.android.systemui.media.controls.domain.pipeline.interactor.mediaRecommendationsInteractor
 import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter
 import com.android.systemui.media.controls.shared.mediaLogger
 import com.android.systemui.media.controls.shared.mockMediaLogger
 import com.android.systemui.media.controls.shared.model.MediaData
-import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
-import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider
 import com.android.systemui.statusbar.notificationLockscreenUserManager
 import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.any
@@ -62,15 +57,7 @@
     private val mediaDataFilter: MediaDataFilterImpl = kosmos.mediaDataFilter
     private val notificationLockscreenUserManager = kosmos.notificationLockscreenUserManager
     private val packageManager = kosmos.packageManager
-    private val icon = Icon.createWithResource(context, R.drawable.ic_media_play)
     private val drawable = context.getDrawable(R.drawable.ic_media_play)
-    private val smartspaceMediaData: SmartspaceMediaData =
-        SmartspaceMediaData(
-            targetId = KEY_MEDIA_SMARTSPACE,
-            isActive = true,
-            packageName = PACKAGE_NAME,
-            recommendations = MediaTestHelper.getValidRecommendationList(icon),
-        )
 
     private val underTest: MediaCarouselViewModel = kosmos.mediaCarouselViewModel
 
@@ -121,53 +108,6 @@
         }
 
     @Test
-    fun loadMediaControlsAndRecommendations_mediaItemsAreUpdated() =
-        testScope.runTest {
-            val sortedMedia by collectLastValue(underTest.mediaItems)
-            val instanceId1 = InstanceId.fakeInstanceId(123)
-            val instanceId2 = InstanceId.fakeInstanceId(456)
-
-            loadMediaControl(KEY, instanceId1)
-            loadMediaControl(KEY_2, instanceId2)
-            loadMediaRecommendations()
-
-            val firstMediaControl = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl
-            val secondMediaControl = sortedMedia?.get(1) as MediaCommonViewModel.MediaControl
-            val recsCard = sortedMedia?.get(2) as MediaCommonViewModel.MediaRecommendations
-            assertThat(firstMediaControl.instanceId).isEqualTo(instanceId2)
-            assertThat(secondMediaControl.instanceId).isEqualTo(instanceId1)
-            assertThat(recsCard.key).isEqualTo(KEY_MEDIA_SMARTSPACE)
-        }
-
-    @Test
-    fun recommendationClicked_switchToPlayer() =
-        testScope.runTest {
-            val sortedMedia by collectLastValue(underTest.mediaItems)
-            kosmos.visualStabilityProvider.isReorderingAllowed = false
-            val instanceId = InstanceId.fakeInstanceId(123)
-
-            loadMediaRecommendations()
-            kosmos.mediaRecommendationsInteractor.switchToMediaControl(PACKAGE_NAME)
-
-            var recsCard = sortedMedia?.get(0) as MediaCommonViewModel.MediaRecommendations
-            assertThat(sortedMedia).hasSize(1)
-            assertThat(recsCard.key).isEqualTo(KEY_MEDIA_SMARTSPACE)
-
-            loadMediaControl(KEY, instanceId, false)
-
-            recsCard = sortedMedia?.get(0) as MediaCommonViewModel.MediaRecommendations
-            assertThat(sortedMedia).hasSize(1)
-            assertThat(recsCard.key).isEqualTo(KEY_MEDIA_SMARTSPACE)
-
-            loadMediaControl(KEY, instanceId, true)
-
-            val mediaControl = sortedMedia?.get(0) as MediaCommonViewModel.MediaControl
-            assertThat(sortedMedia).hasSize(2)
-            assertThat(mediaControl.instanceId).isEqualTo(instanceId)
-            assertThat(mediaControl.isMediaFromRec).isTrue()
-        }
-
-    @Test
     fun addMediaControlThenRemove_mediaEventsAreLogged() =
         testScope.runTest {
             val sortedMedia by collectLastValue(underTest.mediaItems)
@@ -199,31 +139,6 @@
             verify(kosmos.mediaLogger).logMediaCardRemoved(eq(instanceId))
         }
 
-    @Test
-    fun addMediaRecommendationThenRemove_mediaEventsAreLogged() =
-        testScope.runTest {
-            val sortedMedia by collectLastValue(underTest.mediaItems)
-
-            loadMediaRecommendations()
-
-            val mediaRecommendations =
-                sortedMedia?.get(0) as MediaCommonViewModel.MediaRecommendations
-            assertThat(mediaRecommendations.key).isEqualTo(KEY_MEDIA_SMARTSPACE)
-
-            // when media recommendation is added to carousel
-            mediaRecommendations.onAdded(mediaRecommendations)
-
-            verify(kosmos.mediaLogger).logMediaRecommendationCardAdded(eq(KEY_MEDIA_SMARTSPACE))
-
-            mediaDataFilter.onSmartspaceMediaDataRemoved(KEY, true)
-            assertThat(sortedMedia).isEmpty()
-
-            // when media recommendation is removed from carousel
-            mediaRecommendations.onRemoved(true)
-
-            verify(kosmos.mediaLogger).logMediaRecommendationCardRemoved(eq(KEY_MEDIA_SMARTSPACE))
-        }
-
     private fun loadMediaControl(key: String, instanceId: InstanceId, isPlaying: Boolean = true) {
         whenever(notificationLockscreenUserManager.isCurrentProfile(USER_ID)).thenReturn(true)
         whenever(notificationLockscreenUserManager.isProfileAvailable(USER_ID)).thenReturn(true)
@@ -239,15 +154,10 @@
         mediaDataFilter.onMediaDataLoaded(key, key, mediaData)
     }
 
-    private fun loadMediaRecommendations(key: String = KEY_MEDIA_SMARTSPACE) {
-        mediaDataFilter.onSmartspaceMediaDataLoaded(key, smartspaceMediaData)
-    }
-
     companion object {
         private const val USER_ID = 0
         private const val KEY = "key"
         private const val KEY_2 = "key2"
         private const val PACKAGE_NAME = "com.example.app"
-        private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModelTest.kt
deleted file mode 100644
index 51b1911..0000000
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModelTest.kt
+++ /dev/null
@@ -1,88 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.controls.ui.viewmodel
-
-import android.R
-import android.content.packageManager
-import android.content.pm.ApplicationInfo
-import android.graphics.drawable.Icon
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.filters.SmallTest
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.coroutines.collectLastValue
-import com.android.systemui.kosmos.testScope
-import com.android.systemui.media.controls.MediaTestHelper
-import com.android.systemui.media.controls.domain.pipeline.MediaDataFilterImpl
-import com.android.systemui.media.controls.domain.pipeline.mediaDataFilter
-import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
-import com.android.systemui.testKosmos
-import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.eq
-import com.android.systemui.util.mockito.whenever
-import com.google.common.truth.Truth.assertThat
-import kotlinx.coroutines.test.runTest
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.ArgumentMatchers
-import org.mockito.Mockito
-
-@SmallTest
-@RunWith(AndroidJUnit4::class)
-class MediaRecommendationsViewModelTest : SysuiTestCase() {
-
-    private val kosmos = testKosmos()
-    private val testScope = kosmos.testScope
-
-    private val mediaDataFilter: MediaDataFilterImpl = kosmos.mediaDataFilter
-    private val packageManager = kosmos.packageManager
-    private val icon: Icon = Icon.createWithResource(context, R.drawable.ic_media_play)
-    private val drawable = context.getDrawable(R.drawable.ic_media_play)
-    private val smartspaceMediaData: SmartspaceMediaData =
-        SmartspaceMediaData(
-            targetId = KEY_MEDIA_SMARTSPACE,
-            isActive = true,
-            packageName = PACKAGE_NAME,
-            recommendations = MediaTestHelper.getValidRecommendationList(icon),
-        )
-
-    private val underTest: MediaRecommendationsViewModel = kosmos.mediaRecommendationsViewModel
-
-    @Test
-    fun loadRecommendations_recsCardViewModelIsLoaded() =
-        testScope.runTest {
-            whenever(packageManager.getApplicationIcon(Mockito.anyString())).thenReturn(drawable)
-            whenever(packageManager.getApplicationIcon(any(ApplicationInfo::class.java)))
-                .thenReturn(drawable)
-            whenever(packageManager.getApplicationInfo(eq(PACKAGE_NAME), ArgumentMatchers.anyInt()))
-                .thenReturn(ApplicationInfo())
-            whenever(packageManager.getApplicationLabel(any())).thenReturn(PACKAGE_NAME)
-            val recsCardViewModel by collectLastValue(underTest.mediaRecsCard)
-
-            context.setMockPackageManager(packageManager)
-
-            mediaDataFilter.onSmartspaceMediaDataLoaded(KEY_MEDIA_SMARTSPACE, smartspaceMediaData)
-
-            assertThat(recsCardViewModel).isNotNull()
-            assertThat(recsCardViewModel?.mediaRecs?.size)
-                .isEqualTo(smartspaceMediaData.recommendations.size)
-        }
-
-    companion object {
-        private const val KEY_MEDIA_SMARTSPACE = "MEDIA_SMARTSPACE_ID"
-        private const val PACKAGE_NAME = "com.example.app"
-    }
-}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SceneContainerPluginTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SceneContainerPluginTest.kt
new file mode 100644
index 0000000..b2e29cf
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SceneContainerPluginTest.kt
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.model
+
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.EnableSceneContainer
+import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.fakeSceneDataSource
+import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository
+import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@EnableSceneContainer
+class SceneContainerPluginTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private val shadeDisplayRepository = kosmos.fakeShadeDisplaysRepository
+    private val sceneDataSource = kosmos.fakeSceneDataSource
+
+    private val underTest = kosmos.sceneContainerPlugin
+
+    @Test
+    @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    fun flagValueOverride_differentDisplayId_alwaysFalse() {
+        sceneDataSource.changeScene(Scenes.Shade)
+
+        shadeDisplayRepository.setDisplayId(1)
+
+        assertThat(
+                underTest.flagValueOverride(
+                    flag = SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE,
+                    displayId = 2,
+                )
+            )
+            .isFalse()
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    fun flagValueOverride_sameDisplayId_returnsTrue() {
+        sceneDataSource.changeScene(Scenes.Shade)
+
+        shadeDisplayRepository.setDisplayId(1)
+
+        assertThat(
+                underTest.flagValueOverride(
+                    flag = SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE,
+                    displayId = 1,
+                )
+            )
+            .isTrue()
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    fun flagValueOverride_differentDisplayId_shadeGoesAroundFlagOff_returnsTrue() {
+        sceneDataSource.changeScene(Scenes.Shade)
+
+        shadeDisplayRepository.setDisplayId(1)
+
+        assertThat(
+                underTest.flagValueOverride(
+                    flag = SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE,
+                    displayId = 2,
+                )
+            )
+            .isTrue()
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateDispatcherTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateDispatcherTest.kt
new file mode 100644
index 0000000..b82f5fc
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateDispatcherTest.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.model
+
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SysUIStateDispatcherTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos()
+
+    private val stateFactory = kosmos.sysUiStateFactory
+    private val state0 = stateFactory.create(Display.DEFAULT_DISPLAY)
+    private val state1 = stateFactory.create(DISPLAY_1)
+    private val state2 = stateFactory.create(DISPLAY_2)
+    private val underTest = kosmos.sysUIStateDispatcher
+
+    private val flagsChanges = mutableMapOf<Int, Long>() // display id -> flag value
+    private val callback =
+        SysUiState.SysUiStateCallback { sysUiFlags, displayId ->
+            flagsChanges[displayId] = sysUiFlags
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    fun registerUnregisterListener_notifiedOfChanges_receivedForAllDisplayIdsWithOneCallback() {
+        underTest.registerListener(callback)
+
+        state1.setFlag(FLAG_1, true).commitUpdate()
+        state2.setFlag(FLAG_2, true).commitUpdate()
+
+        assertThat(flagsChanges).containsExactly(DISPLAY_1, FLAG_1, DISPLAY_2, FLAG_2)
+
+        underTest.unregisterListener(callback)
+
+        state1.setFlag(0, true).commitUpdate()
+
+        // Didn't change
+        assertThat(flagsChanges).containsExactly(DISPLAY_1, FLAG_1, DISPLAY_2, FLAG_2)
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    fun registerUnregisterListener_notifiedOfChangesForNonDefaultDisplay_NotPropagated() {
+        underTest.registerListener(callback)
+
+        state1.setFlag(FLAG_1, true).commitUpdate()
+
+        assertThat(flagsChanges).isEmpty()
+
+        state0.setFlag(FLAG_1, true).commitUpdate()
+
+        assertThat(flagsChanges).containsExactly(Display.DEFAULT_DISPLAY, FLAG_1)
+    }
+
+    private companion object {
+        const val DISPLAY_1 = 1
+        const val DISPLAY_2 = 2
+        const val FLAG_1 = 10L
+        const val FLAG_2 = 20L
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateOverrideTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateOverrideTest.kt
new file mode 100644
index 0000000..24bd8ad
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUIStateOverrideTest.kt
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.model
+
+import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlin.test.Test
+import org.junit.Before
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers
+import org.mockito.Mockito.never
+import org.mockito.kotlin.any
+import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.reset
+import org.mockito.kotlin.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class SysUIStateOverrideTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private val defaultState = kosmos.sysUiState
+    private val callbackOnOverride = mock<SysUiState.SysUiStateCallback>()
+    private val dumpManager = kosmos.dumpManager
+
+    private val underTest = kosmos.sysUiStateOverrideFactory.invoke(DISPLAY_1)
+
+    @Before
+    fun setup() {
+        underTest.start()
+        underTest.addCallback(callbackOnOverride)
+        reset(callbackOnOverride)
+    }
+
+    @Test
+    fun setFlag_setOnDefaultState_propagatedToOverride() {
+        defaultState.setFlag(FLAG_1, true).commitUpdate()
+
+        verify(callbackOnOverride).onSystemUiStateChanged(FLAG_1, Display.DEFAULT_DISPLAY)
+        verify(callbackOnOverride).onSystemUiStateChanged(FLAG_1, DISPLAY_1)
+    }
+
+    @Test
+    fun setFlag_onOverride_overridesDefaultOnes() {
+        defaultState.setFlag(FLAG_1, false).setFlag(FLAG_2, true).commitUpdate()
+        underTest.setFlag(FLAG_1, true).setFlag(FLAG_2, false).commitUpdate()
+
+        assertThat(underTest.isFlagEnabled(FLAG_1)).isTrue()
+        assertThat(underTest.isFlagEnabled(FLAG_2)).isFalse()
+
+        assertThat(defaultState.isFlagEnabled(FLAG_1)).isFalse()
+        assertThat(defaultState.isFlagEnabled(FLAG_2)).isTrue()
+    }
+
+    @Test
+    fun destroy_callbacksForDefaultStateNotReceivedAnymore() {
+        defaultState.setFlag(FLAG_1, true).commitUpdate()
+
+        verify(callbackOnOverride).onSystemUiStateChanged(FLAG_1, Display.DEFAULT_DISPLAY)
+
+        reset(callbackOnOverride)
+        underTest.destroy()
+        defaultState.setFlag(FLAG_1, false).commitUpdate()
+
+        verify(callbackOnOverride, never()).onSystemUiStateChanged(FLAG_1, Display.DEFAULT_DISPLAY)
+    }
+
+    @Test
+    fun init_registersWithDumpManager() {
+        verify(dumpManager).registerNormalDumpable(any(), eq(underTest))
+    }
+
+    @Test
+    fun destroy_unregistersWithDumpManager() {
+        underTest.destroy()
+
+        verify(dumpManager).unregisterDumpable(ArgumentMatchers.anyString())
+    }
+
+    private companion object {
+        const val DISPLAY_1 = 1
+        const val FLAG_1 = 1L
+        const val FLAG_2 = 2L
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt
index a3be9e3..09588f9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateExtTest.kt
@@ -20,7 +20,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.settings.FakeDisplayTracker
 import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import org.junit.Test
@@ -32,20 +31,11 @@
 
     private val kosmos = testKosmos()
 
-    private val underTest =
-        SysUiState(
-            FakeDisplayTracker(context),
-            kosmos.sceneContainerPlugin,
-        )
+    private val underTest = kosmos.sysUiState
 
     @Test
     fun updateFlags() {
-        underTest.updateFlags(
-            Display.DEFAULT_DISPLAY,
-            1L to true,
-            2L to false,
-            3L to true,
-        )
+        underTest.updateFlags(Display.DEFAULT_DISPLAY, 1L to true, 2L to false, 3L to true)
 
         assertThat(underTest.flags and 1L).isNotEqualTo(0L)
         assertThat(underTest.flags and 2L).isEqualTo(0L)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateTest.java
index 9a78bd9..5bb7f36 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/model/SysUiStateTest.java
@@ -19,16 +19,23 @@
 
 import static android.view.Display.DEFAULT_DISPLAY;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyString;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.never;
+import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
 
+import android.view.Display;
+
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.dump.DumpManager;
 import com.android.systemui.kosmos.KosmosJavaAdapter;
-import com.android.systemui.settings.FakeDisplayTracker;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -46,21 +53,33 @@
     private KosmosJavaAdapter mKosmos;
     private SysUiState.SysUiStateCallback mCallback;
     private SysUiState mFlagsContainer;
+    private SceneContainerPlugin mSceneContainerPlugin;
+    private DumpManager mDumpManager;
+    private SysUIStateDispatcher mSysUIStateDispatcher;
+
+    private SysUiState createInstance(int displayId) {
+        var sysuiState = new SysUiStateImpl(displayId, mSceneContainerPlugin, mDumpManager,
+                mSysUIStateDispatcher);
+        sysuiState.addCallback(mCallback);
+        return sysuiState;
+    }
 
     @Before
     public void setup() {
-        FakeDisplayTracker displayTracker = new FakeDisplayTracker(mContext);
         mKosmos = new KosmosJavaAdapter(this);
-        mFlagsContainer = new SysUiState(displayTracker, mKosmos.getSceneContainerPlugin());
+        mFlagsContainer = mKosmos.getSysuiState();
+        mSceneContainerPlugin = mKosmos.getSceneContainerPlugin();
         mCallback = mock(SysUiState.SysUiStateCallback.class);
-        mFlagsContainer.addCallback(mCallback);
+        mDumpManager = mock(DumpManager.class);
+        mSysUIStateDispatcher = mKosmos.getSysUIStateDispatcher();
+        mFlagsContainer = createInstance(DEFAULT_DISPLAY);
     }
 
     @Test
     public void addSingle_setFlag() {
         setFlags(FLAG_1);
 
-        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1);
+        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1, DEFAULT_DISPLAY);
     }
 
     @Test
@@ -68,22 +87,19 @@
         setFlags(FLAG_1);
         setFlags(FLAG_2);
 
-        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1);
-        verify(mCallback, times(1))
-                .onSystemUiStateChanged(FLAG_1 | FLAG_2);
+        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1, DEFAULT_DISPLAY);
+        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1 | FLAG_2, DEFAULT_DISPLAY);
     }
 
     @Test
     public void addMultipleRemoveOne_setFlag() {
         setFlags(FLAG_1);
         setFlags(FLAG_2);
-        mFlagsContainer.setFlag(FLAG_1, false)
-                .commitUpdate(DISPLAY_ID);
+        mFlagsContainer.setFlag(FLAG_1, false).commitUpdate(DISPLAY_ID);
 
-        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1);
-        verify(mCallback, times(1))
-                .onSystemUiStateChanged(FLAG_1 | FLAG_2);
-        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_2);
+        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1, DEFAULT_DISPLAY);
+        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1 | FLAG_2, DEFAULT_DISPLAY);
+        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_2, DEFAULT_DISPLAY);
     }
 
     @Test
@@ -91,19 +107,18 @@
         setFlags(FLAG_1, FLAG_2, FLAG_3, FLAG_4);
 
         int expected = FLAG_1 | FLAG_2 | FLAG_3 | FLAG_4;
-        verify(mCallback, times(1)).onSystemUiStateChanged(expected);
+        verify(mCallback, times(1)).onSystemUiStateChanged(expected, DEFAULT_DISPLAY);
     }
 
     @Test
     public void addMultipleRemoveOne_setFlags() {
         setFlags(FLAG_1, FLAG_2, FLAG_3, FLAG_4);
-        mFlagsContainer.setFlag(FLAG_2, false)
-                .commitUpdate(DISPLAY_ID);
+        mFlagsContainer.setFlag(FLAG_2, false).commitUpdate(DISPLAY_ID);
 
         int expected1 = FLAG_1 | FLAG_2 | FLAG_3 | FLAG_4;
-        verify(mCallback, times(1)).onSystemUiStateChanged(expected1);
+        verify(mCallback, times(1)).onSystemUiStateChanged(expected1, DEFAULT_DISPLAY);
         int expected2 = FLAG_1 | FLAG_3 | FLAG_4;
-        verify(mCallback, times(1)).onSystemUiStateChanged(expected2);
+        verify(mCallback, times(1)).onSystemUiStateChanged(expected2, DEFAULT_DISPLAY);
     }
 
     @Test
@@ -112,13 +127,39 @@
         setFlags(FLAG_1, FLAG_2, FLAG_3, FLAG_4);
 
         int expected = FLAG_1 | FLAG_2 | FLAG_3 | FLAG_4;
-        verify(mCallback, times(0)).onSystemUiStateChanged(expected);
+        verify(mCallback, times(0)).onSystemUiStateChanged(expected, DEFAULT_DISPLAY);
+    }
+
+    @Test
+    public void setFlag_receivedForDefaultDisplay() {
+        setFlags(FLAG_1);
+
+        verify(mCallback, times(1)).onSystemUiStateChanged(FLAG_1, DEFAULT_DISPLAY);
+    }
+
+
+    @Test
+    public void init_registersWithDumpManager() {
+        mFlagsContainer.start();
+
+        verify(mDumpManager).registerNormalDumpable(any(), eq(mFlagsContainer));
+    }
+
+    @Test
+    public void destroy_unregistersWithDumpManager() {
+        mFlagsContainer.destroy();
+
+        verify(mDumpManager).unregisterDumpable(anyString());
     }
 
     private void setFlags(int... flags) {
-        for (int i = 0; i < flags.length; i++) {
-            mFlagsContainer.setFlag(flags[i], true);
+        setFlags(mFlagsContainer, flags);
+    }
+
+    private void setFlags(SysUiState instance, int... flags) {
+        for (int flag : flags) {
+            instance.setFlag(flag, true);
         }
-        mFlagsContainer.commitUpdate(DISPLAY_ID);
+        instance.commitUpdate();
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/view/WindowRootViewKeyEventHandlerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/view/WindowRootViewKeyEventHandlerTest.kt
new file mode 100644
index 0000000..18ebd4d
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/scene/ui/view/WindowRootViewKeyEventHandlerTest.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.ui.view
+
+import android.view.KeyEvent
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.classifier.fakeFalsingCollector
+import com.android.systemui.keyevent.domain.interactor.mockSysUIKeyEventHandler
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.testKosmos
+import org.junit.Assert.assertEquals
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class WindowRootViewKeyEventHandlerTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+    private val underTest: WindowRootViewKeyEventHandler = kosmos.windowRootViewKeyEventHandler
+
+    @Test
+    fun dispatchKeyEvent_forwardsDispatchKeyEvent() =
+        kosmos.runTest {
+            val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
+            underTest.dispatchKeyEvent(keyEvent)
+            verify(mockSysUIKeyEventHandler).dispatchKeyEvent(keyEvent)
+        }
+
+    @Test
+    fun dispatchKeyEventPreIme_forwardsDispatchKeyEventPreIme() =
+        kosmos.runTest {
+            val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
+            underTest.dispatchKeyEventPreIme(keyEvent)
+            verify(mockSysUIKeyEventHandler).dispatchKeyEventPreIme(keyEvent)
+        }
+
+    @Test
+    fun interceptMediaKey_forwardsInterceptMediaKey() =
+        kosmos.runTest {
+            val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP)
+            underTest.interceptMediaKey(keyEvent)
+            verify(mockSysUIKeyEventHandler).interceptMediaKey(keyEvent)
+        }
+
+    @Test
+    fun collectKeyEvent_forwardsCollectKeyEvent() =
+        kosmos.runTest {
+            val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A)
+            underTest.collectKeyEvent(keyEvent)
+            assertEquals(keyEvent, fakeFalsingCollector.lastKeyEvent)
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt
index 0448ad5..0a82f72 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/screenshot/DefaultScreenshotActionsProviderTest.kt
@@ -30,6 +30,9 @@
 import com.google.common.truth.Truth.assertThat
 import java.util.UUID
 import kotlin.test.Test
+import kotlinx.coroutines.test.TestCoroutineScheduler
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
 import org.junit.runner.RunWith
 import org.mockito.Mockito.verifyNoMoreInteractions
 import org.mockito.kotlin.any
@@ -43,10 +46,19 @@
 
 @RunWith(AndroidJUnit4::class)
 class DefaultScreenshotActionsProviderTest : SysuiTestCase() {
+    private val scheduler = TestCoroutineScheduler()
+    private val mainDispatcher = UnconfinedTestDispatcher(scheduler)
+    private val testScope = TestScope(mainDispatcher)
     private val actionExecutor = mock<ActionExecutor>()
     private val uiEventLogger = mock<UiEventLogger>()
     private val actionsCallback = mock<ScreenshotActionsController.ActionsCallback>()
-    private val actionIntentCreator = ActionIntentCreator(context, context.packageManager)
+    private val actionIntentCreator =
+        ActionIntentCreator(
+            context,
+            context.packageManager,
+            testScope.backgroundScope,
+            mainDispatcher,
+        )
 
     private val request = ScreenshotData.forTesting(userHandle = UserHandle.OWNER)
     private val validResult = ScreenshotSavedResult(Uri.EMPTY, Process.myUserHandle(), 0)
@@ -198,6 +210,7 @@
             context,
             uiEventLogger,
             actionIntentCreator,
+            testScope,
             UUID.randomUUID(),
             request,
             actionExecutor,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index d852a9d..94db429 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -17,7 +17,9 @@
 package com.android.systemui.shade;
 
 import static android.content.res.Configuration.ORIENTATION_PORTRAIT;
+import static android.view.Display.TYPE_INTERNAL;
 
+import static com.android.systemui.display.data.repository.FakeDisplayRepositoryKt.display;
 import static com.android.systemui.log.LogBufferHelperKt.logcatLogBuffer;
 
 import static com.google.common.truth.Truth.assertThat;
@@ -47,6 +49,7 @@
 import android.os.PowerManager;
 import android.os.UserManager;
 import android.util.DisplayMetrics;
+import android.view.Display;
 import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
@@ -70,6 +73,7 @@
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
 import com.android.systemui.classifier.FalsingCollectorFake;
 import com.android.systemui.classifier.FalsingManagerFake;
+import com.android.systemui.common.domain.interactor.SysUIStateDisplaysInteractor;
 import com.android.systemui.common.ui.view.TouchHandlingView;
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryFaceAuthInteractor;
 import com.android.systemui.deviceentry.domain.interactor.DeviceEntryUdfpsInteractor;
@@ -291,6 +295,7 @@
     @Mock private NaturalScrollingSettingObserver mNaturalScrollingSettingObserver;
     @Mock private LargeScreenHeaderHelper mLargeScreenHeaderHelper;
     @Mock private StatusBarLongPressGestureDetector mStatusBarLongPressGestureDetector;
+    @Mock protected SysUIStateDisplaysInteractor mSysUIStateDisplaysInteractor;
     protected final int mMaxUdfpsBurnInOffsetY = 5;
     protected FakeFeatureFlagsClassic mFeatureFlags = new FakeFeatureFlagsClassic();
     protected KeyguardClockInteractor mKeyguardClockInteractor;
@@ -435,6 +440,9 @@
             return null;
         }).when(mView).setOnTouchListener(any(NotificationPanelViewController.TouchHandler.class));
 
+        var displayMock = display(TYPE_INTERNAL, /* flags= */ 0, /* id= */Display.DEFAULT_DISPLAY,
+                /* state= */ null);
+        when(mView.getDisplay()).thenReturn(displayMock);
         // Any edge transition
         when(mKeyguardTransitionInteractor.transition(any()))
                 .thenReturn(emptyFlow());
@@ -565,6 +573,7 @@
                 mShadeRepository,
                 mSysUIUnfoldComponent,
                 mSysUiState,
+                mSysUIStateDisplaysInteractor,
                 mKeyguardUnlockAnimationController,
                 mKeyguardIndicationController,
                 mNotificationListContainer,
@@ -589,7 +598,8 @@
                 mKeyguardClockPositionAlgorithm,
                 mMSDLPlayer,
                 mBrightnessMirrorShowingRepository,
-                new BlurConfig(0f, 0f));
+                new BlurConfig(0f, 0f),
+                () -> mKosmos.getFakeShadeDisplaysRepository());
         mNotificationPanelViewController.initDependencies(
                 mCentralSurfaces,
                 null,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index 354c23d..89263fc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -16,10 +16,16 @@
 
 package com.android.systemui.shade;
 
+import static android.view.Display.TYPE_INTERNAL;
+
+import static com.android.systemui.display.data.repository.FakeDisplayRepositoryKt.display;
 import static com.android.systemui.statusbar.StatusBarState.KEYGUARD;
 
 import static com.google.common.truth.Truth.assertThat;
 
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.atLeastOnce;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
@@ -28,6 +34,7 @@
 import static org.mockito.Mockito.when;
 
 import android.os.Build;
+import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.testing.TestableLooper;
 import android.view.HapticFeedbackConstants;
@@ -38,6 +45,7 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.systemui.DejankUtils;
+import com.android.systemui.Flags;
 import com.android.systemui.flags.DisableSceneContainer;
 
 import com.google.android.msdl.data.model.MSDLToken;
@@ -182,4 +190,25 @@
 
         assertThat(mMSDLPlayer.getLatestTokenPlayed()).isEqualTo(MSDLToken.FAILURE);
     }
+
+    @Test
+    @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    public void updateSystemUiStateFlags_updatesSysuiStateInteractor() {
+        var DISPLAY_ID = 10;
+        mKosmos.getFakeShadeDisplaysRepository().setPendingDisplayId(DISPLAY_ID);
+
+        mNotificationPanelViewController.updateSystemUiStateFlags();
+
+        verify(mSysUIStateDisplaysInteractor).setFlagsExclusivelyToDisplay(eq(DISPLAY_ID), any());
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    public void updateSystemUiStateFlags_flagOff_doesNotUpdateSysuiStateInteractor() {
+        mNotificationPanelViewController.updateSystemUiStateFlags();
+
+        verify(mSysUIStateDisplaysInteractor, never()).setFlagsExclusivelyToDisplay(anyInt(),
+                any());
+    }
+
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
index 59e3a2e..4398359 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/NotificationShadeWindowViewTest.kt
@@ -42,6 +42,7 @@
 import com.android.systemui.keyguard.shared.model.KeyguardState.DREAMING
 import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
 import com.android.systemui.res.R
+import com.android.systemui.scene.ui.view.WindowRootViewKeyEventHandler
 import com.android.systemui.settings.brightness.data.repository.BrightnessMirrorShowingRepository
 import com.android.systemui.settings.brightness.domain.interactor.BrightnessMirrorShowingInteractorPassThrough
 import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
@@ -69,7 +70,6 @@
 import com.android.systemui.unfold.SysUIUnfoldComponent
 import com.android.systemui.unfold.UnfoldTransitionProgressProvider
 import com.android.systemui.util.mockito.any
-import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
 import com.android.systemui.util.time.FakeSystemClock
 import com.android.systemui.window.ui.viewmodel.WindowRootViewModel
@@ -85,12 +85,12 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.Captor
 import org.mockito.Mock
-import org.mockito.Mockito
 import org.mockito.Mockito.never
 import org.mockito.Mockito.spy
 import org.mockito.Mockito.verify
 import org.mockito.MockitoAnnotations
 import org.mockito.kotlin.eq
+import org.mockito.kotlin.mock
 
 @RunWith(AndroidJUnit4::class)
 @RunWithLooper(setAsMainLooper = true)
@@ -175,13 +175,14 @@
         featureFlags.set(Flags.SPLIT_SHADE_SUBPIXEL_OPTIMIZATION, true)
         mSetFlagsRule.enableFlags(AConfigFlags.FLAG_REVAMPED_BOUNCER_MESSAGES)
         testScope = TestScope()
+        val falsingCollector = FalsingCollectorFake()
         controller =
             NotificationShadeWindowViewController(
                 blurUtils,
                 windowRootViewModelFactory,
                 choreographer,
                 lockscreenShadeTransitionController,
-                FalsingCollectorFake(),
+                falsingCollector,
                 statusBarStateController,
                 dockManager,
                 notificationShadeDepthController,
@@ -212,7 +213,7 @@
                 NotificationLaunchAnimationInteractor(NotificationLaunchAnimationRepository()),
                 featureFlags,
                 FakeSystemClock(),
-                Mockito.mock(SysUIKeyEventHandler::class.java),
+                WindowRootViewKeyEventHandler({ mock<SysUIKeyEventHandler>() }, falsingCollector),
                 quickSettingsController,
                 primaryBouncerInteractor,
                 alternateBouncerInteractor,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
index 9498daa..c635c7f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepositoryTest.kt
@@ -67,7 +67,7 @@
     fun policy_changing_propagatedFromTheLatestPolicy() =
         testScope.runTest {
             val underTest = createUnderTest()
-            val displayIds by collectValues(underTest.displayId)
+            val displayIds by collectValues(underTest.pendingDisplayId)
 
             assertThat(displayIds).containsExactly(0)
 
@@ -98,7 +98,7 @@
                 DEVELOPMENT_SHADE_DISPLAY_AWARENESS,
                 FakeShadeDisplayPolicy.name,
             )
-            val displayId by collectLastValue(underTest.displayId)
+            val displayId by collectLastValue(underTest.pendingDisplayId)
 
             displayRepository.addDisplay(displayId = 1)
 
@@ -161,7 +161,7 @@
                 FakeShadeDisplayPolicy.name,
             )
 
-            val displayId by collectLastValue(underTest.displayId)
+            val displayId by collectLastValue(underTest.pendingDisplayId)
 
             displayRepository.addDisplays(display(id = 2, type = TYPE_EXTERNAL))
             FakeShadeDisplayPolicy.setDisplayId(2)
@@ -176,4 +176,17 @@
 
             assertThat(displayId).isEqualTo(2)
         }
+
+    @Test
+    fun onDisplayChangedSucceeded_displayIdChanges() =
+        testScope.runTest {
+            val underTest = createUnderTest()
+            val displayId by collectLastValue(underTest.displayId)
+
+            assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
+
+            underTest.onDisplayChangedSucceeded(1)
+
+            assertThat(displayId).isEqualTo(1)
+        }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
index fd6bc98..f51d41b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/data/repository/ShadePrimaryDisplayCommandTest.kt
@@ -69,7 +69,7 @@
     @Test
     fun commandShadeDisplayOverride_resetsDisplayId() =
         testScope.runTest {
-            val displayId by collectLastValue(shadeDisplaysRepository.displayId)
+            val displayId by collectLastValue(shadeDisplaysRepository.pendingDisplayId)
             assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
 
             val newDisplayId = 2
@@ -87,7 +87,7 @@
     @Test
     fun commandShadeDisplayOverride_anyExternalDisplay_notOnDefaultAnymore() =
         testScope.runTest {
-            val displayId by collectLastValue(shadeDisplaysRepository.displayId)
+            val displayId by collectLastValue(shadeDisplaysRepository.pendingDisplayId)
             assertThat(displayId).isEqualTo(Display.DEFAULT_DISPLAY)
             val newDisplayId = 2
             displayRepository.addDisplay(displayId = newDisplayId)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
index 0ad60b6..03f546b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractorTest.kt
@@ -22,7 +22,6 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.common.ui.data.repository.configurationRepository
 import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.kosmos.useUnconfinedTestDispatcher
@@ -82,7 +81,7 @@
     fun start_shadeInCorrectPosition_notAddedOrRemoved() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(0)
+            positionRepository.setPendingDisplayId(0)
 
             underTest.start()
 
@@ -93,18 +92,19 @@
     fun start_shadeInWrongPosition_changes() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(1)
+            positionRepository.setPendingDisplayId(1)
 
             underTest.start()
 
             verify(shadeContext).reparentToDisplay(eq(1))
+            assertThat(positionRepository.displayId.value).isEqualTo(1)
         }
 
     @Test
     fun start_shadeInWrongPosition_logsStartToLatencyTracker() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(1)
+            positionRepository.setPendingDisplayId(1)
 
             underTest.start()
 
@@ -115,7 +115,7 @@
     fun start_shadeInWrongPosition_someNotificationsVisible_hiddenThenShown() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(1)
+            positionRepository.setPendingDisplayId(1)
             activeNotificationRepository.setActiveNotifs(1)
 
             underTest.start()
@@ -129,7 +129,7 @@
     fun start_shadeInWrongPosition_someNotificationsVisible_waitsForInflationsBeforeShowingNssl() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(1)
+            positionRepository.setPendingDisplayId(1)
             activeNotificationRepository.setActiveNotifs(1)
 
             val endRebinding = notificationRebindingTracker.trackRebinding("test")
@@ -155,7 +155,7 @@
     fun start_shadeInWrongPosition_noNotifications_nsslNotHidden() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(1)
+            positionRepository.setPendingDisplayId(1)
             activeNotificationRepository.setActiveNotifs(0)
 
             underTest.start()
@@ -170,7 +170,7 @@
     fun start_shadeInWrongPosition_waitsUntilMovedToDisplayReceived() =
         testScope.runTest {
             whenever(display.displayId).thenReturn(0)
-            positionRepository.setDisplayId(1)
+            positionRepository.setPendingDisplayId(1)
             activeNotificationRepository.setActiveNotifs(1)
 
             underTest.start()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
index 4f30103..fad6658 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/clocks/DefaultClockProviderTest.kt
@@ -108,7 +108,7 @@
         verify(mockSmallClockView).setColors(DOZE_COLOR, Color.MAGENTA)
         verify(mockLargeClockView).setColors(DOZE_COLOR, Color.MAGENTA)
 
-        clock.initialize(true, 0f, 0f, {})
+        clock.initialize(true, 0f, 0f, null)
 
         val expectedColor = 0
         verify(mockSmallClockView).setColors(DOZE_COLOR, expectedColor)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
index 4bd02e0..17509dc 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/ConditionExtensionsTest.kt
@@ -19,6 +19,10 @@
 @RunWith(AndroidJUnit4::class)
 class ConditionExtensionsTest : SysuiTestCase() {
     private lateinit var testScope: TestScope
+    private val testCallback =
+        Condition.Callback {
+            // This is a no-op
+        }
 
     @Before
     fun setUp() {
@@ -33,7 +37,7 @@
 
             assertThat(condition.isConditionSet).isFalse()
 
-            condition.start()
+            condition.testStart()
             assertThat(condition.isConditionSet).isTrue()
             assertThat(condition.isConditionMet).isTrue()
         }
@@ -46,7 +50,7 @@
 
             assertThat(condition.isConditionSet).isFalse()
 
-            condition.start()
+            condition.testStart()
             assertThat(condition.isConditionSet).isTrue()
             assertThat(condition.isConditionMet).isFalse()
         }
@@ -56,7 +60,7 @@
         testScope.runTest {
             val flow = emptyFlow<Boolean>()
             val condition = flow.toCondition(scope = this, Condition.START_EAGERLY)
-            condition.start()
+            condition.testStop()
 
             assertThat(condition.isConditionSet).isFalse()
             assertThat(condition.isConditionMet).isFalse()
@@ -72,7 +76,7 @@
                     strategy = Condition.START_EAGERLY,
                     initialValue = true,
                 )
-            condition.start()
+            condition.testStart()
 
             assertThat(condition.isConditionSet).isTrue()
             assertThat(condition.isConditionMet).isTrue()
@@ -88,7 +92,7 @@
                     strategy = Condition.START_EAGERLY,
                     initialValue = false,
                 )
-            condition.start()
+            condition.testStart()
 
             assertThat(condition.isConditionSet).isTrue()
             assertThat(condition.isConditionMet).isFalse()
@@ -99,7 +103,7 @@
         testScope.runTest {
             val flow = MutableStateFlow(false)
             val condition = flow.toCondition(scope = this, strategy = Condition.START_EAGERLY)
-            condition.start()
+            condition.testStart()
 
             assertThat(condition.isConditionSet).isTrue()
             assertThat(condition.isConditionMet).isFalse()
@@ -110,7 +114,7 @@
             flow.value = false
             assertThat(condition.isConditionMet).isFalse()
 
-            condition.stop()
+            condition.testStop()
         }
 
     @Test
@@ -120,10 +124,18 @@
             val condition = flow.toCondition(scope = this, strategy = Condition.START_EAGERLY)
             assertThat(flow.subscriptionCount.value).isEqualTo(0)
 
-            condition.start()
+            condition.testStart()
             assertThat(flow.subscriptionCount.value).isEqualTo(1)
 
-            condition.stop()
+            condition.testStop()
             assertThat(flow.subscriptionCount.value).isEqualTo(0)
         }
+
+    fun Condition.testStart() {
+        addCallback(testCallback)
+    }
+
+    fun Condition.testStop() {
+        removeCallback(testCallback)
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/FakeCondition.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/FakeCondition.java
index 5416536..da660e2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/FakeCondition.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/shared/condition/FakeCondition.java
@@ -40,7 +40,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
index 3eec1cd..f54c28f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerTest.java
@@ -200,6 +200,7 @@
     private NotificationEntry mSecondaryUserNotif;
     private NotificationEntry mWorkProfileNotif;
     private NotificationEntry mSensitiveContentNotif;
+    private NotificationEntry mSensitiveNotifWithOldCreationTime;
     private long mSensitiveNotifPostTime;
     private final FakeFeatureFlagsClassic mFakeFeatureFlags = new FakeFeatureFlagsClassic();
     private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
@@ -274,6 +275,20 @@
                 .setSensitiveContent(true)
                 .setVisibilityOverride(VISIBILITY_NO_OVERRIDE).build());
         mSensitiveNotifPostTime = mSensitiveContentNotif.getSbn().getNotification().getWhen();
+
+        mSensitiveNotifWithOldCreationTime = new NotificationEntryBuilder()
+                .setNotification(notifWithPrivateVisibility)
+                .setUser(new UserHandle(mCurrentUser.id))
+                .setPostTime(System.currentTimeMillis())
+                // creation time of at least -2 hours, no matter what the current value of
+                // SystemClock.currentTimeMillis
+                .setCreationTime(-1 * TimeUnit.HOURS.toMillis(2))
+                .build();
+        mSensitiveNotifWithOldCreationTime.setRanking(
+                new RankingBuilder(mCurrentUserNotif.getRanking())
+                .setChannel(channel)
+                .setSensitiveContent(true)
+                .setVisibilityOverride(VISIBILITY_NO_OVERRIDE).build());
         when(mNotifCollection.getEntry(mWorkProfileNotif.getKey())).thenReturn(mWorkProfileNotif);
         when(mKeyguardInteractorLazy.get()).thenReturn(mKeyguardInteractor);
         when(mKeyguardInteractor.isKeyguardDismissible())
@@ -653,6 +668,23 @@
 
     @Test
     @EnableFlags(LockscreenOtpRedaction.FLAG_NAME)
+    public void testNewSensitiveNotification_notRedactedIfOldCreationTime() {
+        // Allow private notifications for this user
+        mSettings.putIntForUser(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1,
+                mCurrentUser.id);
+        changeSetting(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS);
+        mLockscreenUserManager.mLocked.set(true);
+        // Claim the device was last unlocked 1 hour ago. Old enough to redact, but newer than the
+        // old creation time in the notification (which is -2 hours)
+        mLockscreenUserManager.mLastLockTime
+                .set(mSensitiveNotifPostTime - TimeUnit.HOURS.toMillis(1));
+        mLockscreenUserManager.mConnectedToWifi.set(false);
+        assertEquals(REDACTION_TYPE_NONE,
+                mLockscreenUserManager.getRedactionType(mSensitiveNotifWithOldCreationTime));
+    }
+
+    @Test
+    @EnableFlags(LockscreenOtpRedaction.FLAG_NAME)
     public void testHasSensitiveContent_redacted() {
         // Allow private notifications for this user
         mSettings.putIntForUser(LOCK_SCREEN_ALLOW_PRIVATE_NOTIFICATIONS, 1,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
index fed6131..a7fe586 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationMediaManagerTest.kt
@@ -125,8 +125,7 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_NOTIFICATION_MEDIA_MANAGER_BACKGROUND_EXECUTION)
-    fun clearMediaNotification_flagOn_resetMediaMetadata() {
+    fun clearMediaNotification_resetMediaMetadata() {
         // set up media metadata.
         notificationMediaManager.mMediaListener.onMetadataChanged(MediaMetadata.Builder().build())
         backgroundExecutor.runAllReady()
@@ -138,17 +137,4 @@
         assertThat(notificationMediaManager.mediaMetadata).isNull()
         assertThat(notificationMediaManager.mMediaController).isNull()
     }
-
-    @Test
-    @DisableFlags(Flags.FLAG_NOTIFICATION_MEDIA_MANAGER_BACKGROUND_EXECUTION)
-    fun clearMediaNotification_flagOff_resetMediaMetadata() {
-        // set up media metadata.
-        notificationMediaManager.mMediaListener.onMetadataChanged(MediaMetadata.Builder().build())
-
-        // clear media notification.
-        notificationMediaManager.clearCurrentMediaNotification()
-
-        assertThat(notificationMediaManager.mediaMetadata).isNull()
-        assertThat(notificationMediaManager.mMediaController).isNull()
-    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index 326d8ff..8165d45 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -34,6 +34,7 @@
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.res.R
 import com.android.systemui.shade.ShadeExpansionChangeEvent
+import com.android.systemui.shared.Flags as SharedFlags
 import com.android.systemui.statusbar.phone.BiometricUnlockController
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.phone.ScrimController
@@ -43,10 +44,11 @@
 import com.android.systemui.testKosmos
 import com.android.systemui.util.WallpaperController
 import com.android.systemui.util.mockito.eq
-import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor
 import com.android.systemui.window.domain.interactor.WindowRootViewBlurInteractor
 import com.android.wm.shell.appzoomout.AppZoomOut
 import com.google.common.truth.Truth.assertThat
+import java.util.Optional
+import java.util.function.Consumer
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -67,8 +69,6 @@
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when`
 import org.mockito.junit.MockitoJUnit
-import java.util.Optional
-import java.util.function.Consumer
 
 @RunWith(AndroidJUnit4::class)
 @RunWithLooper
@@ -76,7 +76,6 @@
 class NotificationShadeDepthControllerTest : SysuiTestCase() {
     private val kosmos = testKosmos()
 
-    private val applicationScope = kosmos.testScope.backgroundScope
     @Mock private lateinit var windowRootViewBlurInteractor: WindowRootViewBlurInteractor
     @Mock private lateinit var statusBarStateController: StatusBarStateController
     @Mock private lateinit var blurUtils: BlurUtils
@@ -85,7 +84,6 @@
     @Mock private lateinit var keyguardInteractor: KeyguardInteractor
     @Mock private lateinit var choreographer: Choreographer
     @Mock private lateinit var wallpaperController: WallpaperController
-    @Mock private lateinit var wallpaperInteractor: WallpaperInteractor
     @Mock private lateinit var notificationShadeWindowController: NotificationShadeWindowController
     @Mock private lateinit var dumpManager: DumpManager
     @Mock private lateinit var appZoomOutOptional: Optional<AppZoomOut>
@@ -130,14 +128,12 @@
                 keyguardInteractor,
                 choreographer,
                 wallpaperController,
-                wallpaperInteractor,
                 notificationShadeWindowController,
                 dozeParameters,
                 context,
                 ResourcesSplitShadeStateController(),
                 windowRootViewBlurInteractor,
                 appZoomOutOptional,
-                applicationScope,
                 dumpManager,
                 configurationController,
             )
@@ -314,24 +310,22 @@
     }
 
     @Test
-    fun onDozeAmountChanged_doesNotApplyBlurWithAmbientAod() {
-        notificationShadeDepthController.wallpaperSupportsAmbientMode = false
-
-        statusBarStateListener.onDozeAmountChanged(1f, 1f)
-        notificationShadeDepthController.updateBlurCallback.doFrame(0)
-        verify(blurUtils).applyBlur(any(), eq(0), eq(false))
-    }
-
-    @Test
-    fun onDozeAmountChanged_appliesBlurWithAmbientAod() {
-        notificationShadeDepthController.wallpaperSupportsAmbientMode = true
-
+    @DisableFlags(SharedFlags.FLAG_AMBIENT_AOD)
+    fun onDozeAmountChanged_appliesBlur() {
         statusBarStateListener.onDozeAmountChanged(1f, 1f)
         notificationShadeDepthController.updateBlurCallback.doFrame(0)
         verify(blurUtils).applyBlur(any(), eq(maxBlur), eq(false))
     }
 
     @Test
+    @EnableFlags(SharedFlags.FLAG_AMBIENT_AOD)
+    fun onDozeAmountChanged_doesNotApplyBlurWithAmbientAod() {
+        statusBarStateListener.onDozeAmountChanged(1f, 1f)
+        notificationShadeDepthController.updateBlurCallback.doFrame(0)
+        verify(blurUtils).applyBlur(any(), eq(0), eq(false))
+    }
+
+    @Test
     fun setFullShadeTransition_appliesBlur_onlyIfSupported() {
         reset(blurUtils)
         `when`(blurUtils.blurRadiusOfRatio(anyFloat())).then { answer ->
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
index 7ed2bd3..0b9b297 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractorTest.kt
@@ -34,6 +34,8 @@
 import com.android.systemui.statusbar.notification.data.model.activeNotificationModel
 import com.android.systemui.statusbar.notification.data.repository.ActiveNotificationsStore
 import com.android.systemui.statusbar.notification.data.repository.activeNotificationListRepository
+import com.android.systemui.statusbar.notification.data.repository.addNotif
+import com.android.systemui.statusbar.notification.data.repository.removeNotif
 import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
 import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.android.systemui.statusbar.notification.shared.CallType
@@ -409,6 +411,63 @@
 
     @Test
     @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun shownNotificationChips_lastAppVisibleTimeMaintainedAcrossNotifAddsAndRemoves() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.shownNotificationChips)
+
+            val notif1Info = NotifInfo("notif1", mock<StatusBarIconView>(), uid = 100)
+            val notif2Info = NotifInfo("notif2", mock<StatusBarIconView>(), uid = 200)
+
+            // Have notif1's app start as showing and then hide later so we get the chip
+            activityManagerRepository.fake.startingIsAppVisibleValue = true
+            fakeSystemClock.setCurrentTimeMillis(9_000)
+            activeNotificationListRepository.addNotif(
+                activeNotificationModel(
+                    key = notif1Info.key,
+                    uid = notif1Info.uid,
+                    statusBarChipIcon = notif1Info.icon,
+                    promotedContent =
+                        PromotedNotificationContentModel.Builder(notif1Info.key).build(),
+                )
+            )
+            activityManagerRepository.fake.setIsAppVisible(notif1Info.uid, isAppVisible = false)
+
+            assertThat(latest!![0].key).isEqualTo(notif1Info.key)
+            assertThat(latest!![0].lastAppVisibleTime).isEqualTo(9_000)
+
+            // WHEN a new notification is added
+            activityManagerRepository.fake.startingIsAppVisibleValue = true
+            fakeSystemClock.setCurrentTimeMillis(10_000)
+            activeNotificationListRepository.addNotif(
+                activeNotificationModel(
+                    key = notif2Info.key,
+                    uid = notif2Info.uid,
+                    statusBarChipIcon = notif2Info.icon,
+                    promotedContent =
+                        PromotedNotificationContentModel.Builder(notif2Info.key).build(),
+                )
+            )
+            activityManagerRepository.fake.setIsAppVisible(notif2Info.uid, isAppVisible = false)
+
+            // THEN the new notification is first
+            assertThat(latest!![0].key).isEqualTo(notif2Info.key)
+            assertThat(latest!![0].lastAppVisibleTime).isEqualTo(10_000)
+
+            // And THEN the original notification maintains its lastAppVisibleTime
+            assertThat(latest!![1].key).isEqualTo(notif1Info.key)
+            assertThat(latest!![1].lastAppVisibleTime).isEqualTo(9_000)
+
+            // WHEN notif1 is removed
+            fakeSystemClock.setCurrentTimeMillis(11_000)
+            activeNotificationListRepository.removeNotif(notif1Info.key)
+
+            // THEN notif2 still has its lastAppVisibleTime
+            assertThat(latest!![0].key).isEqualTo(notif2Info.key)
+            assertThat(latest!![0].lastAppVisibleTime).isEqualTo(10_000)
+        }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
     fun shownNotificationChips_sortedByLastAppVisibleTime() =
         kosmos.runTest {
             val latest by collectLastValue(underTest.shownNotificationChips)
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
index 1b5b0d6..e2d1498 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModelTest.kt
@@ -16,18 +16,19 @@
 
 package com.android.systemui.statusbar.chips.ui.viewmodel
 
+import android.content.Context
 import android.content.DialogInterface
 import android.content.packageManager
 import android.content.pm.PackageManager
 import android.graphics.Bitmap
 import android.graphics.drawable.BitmapDrawable
 import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
 import android.view.View
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.Expandable
+import com.android.systemui.common.shared.model.ContentDescription.Companion.loadContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.collectLastValue
@@ -181,7 +182,7 @@
 
             val latest by collectLastValue(underTest.primaryChip)
 
-            assertIsCallChip(latest, notificationKey)
+            assertIsCallChip(latest, notificationKey, context)
         }
 
     @Test
@@ -196,7 +197,7 @@
 
             val latest by collectLastValue(underTest.primaryChip)
 
-            assertIsCallChip(latest, callNotificationKey)
+            assertIsCallChip(latest, callNotificationKey, context)
 
             // WHEN the higher priority media projection chip is added
             mediaProjectionState.value =
@@ -241,7 +242,7 @@
             mediaProjectionState.value = MediaProjectionState.NotProjecting
 
             // THEN the lower priority call is used
-            assertIsCallChip(latest, callNotificationKey)
+            assertIsCallChip(latest, callNotificationKey, context)
         }
 
     /** Regression test for b/347726238. */
@@ -395,18 +396,29 @@
             assertThat(icon.res).isEqualTo(R.drawable.ic_present_to_all)
         }
 
-        fun assertIsCallChip(latest: OngoingActivityChipModel?, notificationKey: String) {
+        fun assertIsCallChip(
+            latest: OngoingActivityChipModel?,
+            notificationKey: String,
+            context: Context,
+        ) {
             assertThat(latest).isInstanceOf(OngoingActivityChipModel.Active::class.java)
             assertThat((latest as OngoingActivityChipModel.Active).key).isEqualTo(notificationKey)
 
             if (StatusBarConnectedDisplays.isEnabled) {
                 assertNotificationIcon(latest, notificationKey)
-                return
+            } else {
+                val contentDescription =
+                    if (latest.icon is OngoingActivityChipModel.ChipIcon.SingleColorIcon) {
+                        ((latest.icon) as OngoingActivityChipModel.ChipIcon.SingleColorIcon)
+                            .impl
+                            .contentDescription
+                    } else {
+                        (latest.icon as OngoingActivityChipModel.ChipIcon.StatusBarView)
+                            .contentDescription
+                    }
+                assertThat(contentDescription.loadContentDescription(context))
+                    .contains(context.getString(R.string.ongoing_call_content_description))
             }
-            val icon =
-                ((latest.icon) as OngoingActivityChipModel.ChipIcon.SingleColorIcon).impl
-                    as Icon.Resource
-            assertThat(icon.res).isEqualTo(com.android.internal.R.drawable.ic_phone)
         }
 
         private fun assertNotificationIcon(
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
index 2887de3..96c4a59 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsWithNotifsViewModelTest.kt
@@ -48,6 +48,7 @@
 import com.android.systemui.statusbar.chips.notification.domain.interactor.statusBarNotificationChipsInteractor
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.notification.ui.viewmodel.NotifChipsViewModelTest.Companion.assertIsNotifChip
+import com.android.systemui.statusbar.chips.screenrecord.ui.viewmodel.ScreenRecordChipViewModel
 import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
 import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModelLegacy
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
@@ -172,6 +173,18 @@
         }
 
     @Test
+    fun visibleChipKeys_allInactive() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.visibleChipKeys)
+
+            screenRecordState.value = ScreenRecordModel.DoingNothing
+            mediaProjectionState.value = MediaProjectionState.NotProjecting
+            setNotifs(emptyList())
+
+            assertThat(latest).isEmpty()
+        }
+
+    @Test
     fun primaryChip_screenRecordShow_restHidden_screenRecordShown() =
         kosmos.runTest {
             screenRecordState.value = ScreenRecordModel.Recording
@@ -241,10 +254,24 @@
             val unused by collectLastValue(underTest.chips)
 
             assertIsScreenRecordChip(latest!!.primary)
-            assertIsCallChip(latest!!.secondary, callNotificationKey)
+            assertIsCallChip(latest!!.secondary, callNotificationKey, context)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
         }
 
+    @Test
+    fun visibleChipKeys_screenRecordShowAndCallShow_hasBothKeys() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.visibleChipKeys)
+
+            val callNotificationKey = "call"
+            screenRecordState.value = ScreenRecordModel.Recording
+            addOngoingCallState(callNotificationKey)
+
+            assertThat(latest)
+                .containsExactly(ScreenRecordChipViewModel.KEY, callNotificationKey)
+                .inOrder()
+        }
+
     @EnableChipsModernization
     @Test
     fun chips_screenRecordAndCallActive_inThatOrder() =
@@ -258,7 +285,7 @@
 
             assertThat(latest!!.active.size).isEqualTo(2)
             assertIsScreenRecordChip(latest!!.active[0])
-            assertIsCallChip(latest!!.active[1], callNotificationKey)
+            assertIsCallChip(latest!!.active[1], callNotificationKey, context)
             assertThat(latest!!.overflow).isEmpty()
             assertThat(latest!!.inactive.size).isEqualTo(2)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
@@ -590,7 +617,7 @@
             val unused by collectLastValue(underTest.chips)
 
             assertIsShareToAppChip(latest!!.primary)
-            assertIsCallChip(latest!!.secondary, callNotificationKey)
+            assertIsCallChip(latest!!.secondary, callNotificationKey, context)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
         }
 
@@ -609,7 +636,7 @@
 
             assertThat(latest!!.active.size).isEqualTo(2)
             assertIsShareToAppChip(latest!!.active[0])
-            assertIsCallChip(latest!!.active[1], callNotificationKey)
+            assertIsCallChip(latest!!.active[1], callNotificationKey, context)
             assertThat(latest!!.overflow).isEmpty()
             assertThat(latest!!.inactive.size).isEqualTo(2)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
@@ -627,7 +654,7 @@
 
             val latest by collectLastValue(underTest.primaryChip)
 
-            assertIsCallChip(latest, callNotificationKey)
+            assertIsCallChip(latest, callNotificationKey, context)
         }
 
     @DisableChipsModernization
@@ -644,7 +671,7 @@
             val latest by collectLastValue(underTest.chipsLegacy)
             val unused by collectLastValue(underTest.chips)
 
-            assertIsCallChip(latest!!.primary, callNotificationKey)
+            assertIsCallChip(latest!!.primary, callNotificationKey, context)
             assertThat(latest!!.secondary)
                 .isInstanceOf(OngoingActivityChipModel.Inactive::class.java)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
@@ -664,7 +691,7 @@
             val unused by collectLastValue(underTest.chipsLegacy)
 
             assertThat(latest!!.active.size).isEqualTo(1)
-            assertIsCallChip(latest!!.active[0], callNotificationKey)
+            assertIsCallChip(latest!!.active[0], callNotificationKey, context)
             assertThat(latest!!.overflow).isEmpty()
             assertThat(latest!!.inactive.size).isEqualTo(3)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
@@ -864,6 +891,37 @@
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModelLegacy())
         }
 
+    @Test
+    fun visibleChipKeys_threePromotedNotifs_topTwoInList() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.visibleChipKeys)
+
+            setNotifs(
+                listOf(
+                    activeNotificationModel(
+                        key = "firstNotif",
+                        statusBarChipIcon = createStatusBarIconViewOrNull(),
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("firstNotif").build(),
+                    ),
+                    activeNotificationModel(
+                        key = "secondNotif",
+                        statusBarChipIcon = createStatusBarIconViewOrNull(),
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("secondNotif").build(),
+                    ),
+                    activeNotificationModel(
+                        key = "thirdNotif",
+                        statusBarChipIcon = createStatusBarIconViewOrNull(),
+                        promotedContent =
+                            PromotedNotificationContentModel.Builder("thirdNotif").build(),
+                    ),
+                )
+            )
+
+            assertThat(latest).containsExactly("firstNotif", "secondNotif").inOrder()
+        }
+
     @DisableChipsModernization
     @Test
     fun chipsLegacy_callAndPromotedNotifs_primaryIsCallSecondaryIsNotif() =
@@ -892,7 +950,7 @@
                 )
             )
 
-            assertIsCallChip(latest!!.primary, callNotificationKey)
+            assertIsCallChip(latest!!.primary, callNotificationKey, context)
             assertIsNotifChip(latest!!.secondary, context, firstIcon, "firstNotif")
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
         }
@@ -926,7 +984,7 @@
             )
 
             assertThat(latest!!.active.size).isEqualTo(2)
-            assertIsCallChip(latest!!.active[0], callNotificationKey)
+            assertIsCallChip(latest!!.active[0], callNotificationKey, context)
             assertIsNotifChip(latest!!.active[1], context, firstIcon, "firstNotif")
             assertThat(latest!!.overflow.size).isEqualTo(1)
             assertIsNotifChip(latest!!.overflow[0], context, secondIcon, "secondNotif")
@@ -953,10 +1011,31 @@
             )
 
             assertIsScreenRecordChip(latest!!.primary)
-            assertIsCallChip(latest!!.secondary, callNotificationKey)
+            assertIsCallChip(latest!!.secondary, callNotificationKey, context)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
         }
 
+    @Test
+    fun visibleChipKeys_screenRecordAndCallAndPromotedNotifs_topTwoInList() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.visibleChipKeys)
+
+            val callNotificationKey = "call"
+            addOngoingCallState(callNotificationKey)
+            screenRecordState.value = ScreenRecordModel.Recording
+            activeNotificationListRepository.addNotif(
+                activeNotificationModel(
+                    key = "notif",
+                    statusBarChipIcon = createStatusBarIconViewOrNull(),
+                    promotedContent = PromotedNotificationContentModel.Builder("notif").build(),
+                )
+            )
+
+            assertThat(latest)
+                .containsExactly(ScreenRecordChipViewModel.KEY, callNotificationKey)
+                .inOrder()
+        }
+
     @EnableChipsModernization
     @Test
     fun chips_screenRecordAndCallAndPromotedNotif_notifInOverflow() =
@@ -978,7 +1057,7 @@
 
             assertThat(latest!!.active.size).isEqualTo(2)
             assertIsScreenRecordChip(latest!!.active[0])
-            assertIsCallChip(latest!!.active[1], callNotificationKey)
+            assertIsCallChip(latest!!.active[1], callNotificationKey, context)
             assertThat(latest!!.overflow.size).isEqualTo(1)
             assertIsNotifChip(latest!!.overflow[0], context, notifIcon, "notif")
             assertThat(latest!!.inactive.size).isEqualTo(2)
@@ -1013,7 +1092,7 @@
             addOngoingCallState(callNotificationKey)
 
             // THEN the higher priority call chip is used
-            assertIsCallChip(latest, callNotificationKey)
+            assertIsCallChip(latest, callNotificationKey, context)
 
             // WHEN the higher priority media projection chip is added
             mediaProjectionState.value =
@@ -1066,7 +1145,7 @@
             mediaProjectionState.value = MediaProjectionState.NotProjecting
 
             // THEN the lower priority call is used
-            assertIsCallChip(latest, callNotificationKey)
+            assertIsCallChip(latest, callNotificationKey, context)
 
             // WHEN the higher priority call is removed
             removeOngoingCallState(key = callNotificationKey)
@@ -1107,7 +1186,7 @@
 
             // THEN the higher priority call chip is used as primary and notif is demoted to
             // secondary
-            assertIsCallChip(latest!!.primary, callNotificationKey)
+            assertIsCallChip(latest!!.primary, callNotificationKey, context)
             assertIsNotifChip(latest!!.secondary, context, notifIcon, "notif")
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
 
@@ -1122,7 +1201,7 @@
             // THEN the higher priority media projection chip is used as primary and call is demoted
             // to secondary (and notif is dropped altogether)
             assertIsShareToAppChip(latest!!.primary)
-            assertIsCallChip(latest!!.secondary, callNotificationKey)
+            assertIsCallChip(latest!!.secondary, callNotificationKey, context)
             assertThat(unused).isEqualTo(MultipleOngoingActivityChipsModel())
 
             // WHEN the higher priority screen record chip is added
@@ -1185,7 +1264,7 @@
 
             // THEN the higher priority call chip and notif are active in that order
             assertThat(latest!!.active.size).isEqualTo(2)
-            assertIsCallChip(latest!!.active[0], callNotificationKey)
+            assertIsCallChip(latest!!.active[0], callNotificationKey, context)
             assertIsNotifChip(latest!!.active[1], context, notifIcon, "notif")
             assertThat(latest!!.overflow).isEmpty()
             assertThat(latest!!.inactive.size).isEqualTo(3)
@@ -1203,7 +1282,7 @@
             // notif is demoted to overflow
             assertThat(latest!!.active.size).isEqualTo(2)
             assertIsShareToAppChip(latest!!.active[0])
-            assertIsCallChip(latest!!.active[1], callNotificationKey)
+            assertIsCallChip(latest!!.active[1], callNotificationKey, context)
             assertThat(latest!!.overflow.size).isEqualTo(1)
             assertIsNotifChip(latest!!.overflow[0], context, notifIcon, "notif")
             assertThat(latest!!.inactive.size).isEqualTo(2)
@@ -1216,7 +1295,7 @@
             // media projection and notif are demoted in overflow
             assertThat(latest!!.active.size).isEqualTo(2)
             assertIsScreenRecordChip(latest!!.active[0])
-            assertIsCallChip(latest!!.active[1], callNotificationKey)
+            assertIsCallChip(latest!!.active[1], callNotificationKey, context)
             assertThat(latest!!.overflow.size).isEqualTo(2)
             assertIsShareToAppChip(latest!!.overflow[0])
             assertIsNotifChip(latest!!.overflow[1], context, notifIcon, "notif")
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarOrchestratorStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarOrchestratorStoreTest.kt
index 06650f2..b2b28a2 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarOrchestratorStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarOrchestratorStoreTest.kt
@@ -50,11 +50,11 @@
     @Before fun addDisplays() = runBlocking { fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY) }
 
     @Test
-    fun displayRemoved_stopsInstance() =
+    fun systemDecorationRemovedEvent_stopsInstance() =
         testScope.runTest {
             val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
-            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+            fakeDisplayRepository.triggerRemoveSystemDecorationEvent(DEFAULT_DISPLAY)
 
             verify(instance).stop()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarterTest.kt
index fee939d..18a2d07 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarterTest.kt
@@ -17,8 +17,7 @@
 package com.android.systemui.statusbar.core
 
 import android.platform.test.annotations.EnableFlags
-import android.view.Display
-import android.view.mockIWindowManager
+import android.view.Display.DEFAULT_DISPLAY
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
@@ -29,6 +28,8 @@
 import com.android.systemui.testKosmos
 import com.google.common.truth.Expect
 import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
@@ -37,11 +38,11 @@
 import org.junit.runner.RunWith
 import org.mockito.kotlin.never
 import org.mockito.kotlin.verify
-import org.mockito.kotlin.whenever
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
+@OptIn(ExperimentalCoroutinesApi::class)
 class MultiDisplayStatusBarStarterTest : SysuiTestCase() {
     @get:Rule val expect: Expect = Expect.create()
 
@@ -52,293 +53,116 @@
     private val fakeInitializerStore = kosmos.fakeStatusBarInitializerStore
     private val fakePrivacyDotStore = kosmos.fakePrivacyDotWindowControllerStore
     private val fakeLightBarStore = kosmos.fakeLightBarControllerStore
-    private val windowManager = kosmos.mockIWindowManager
 
     // Lazy, so that @EnableFlags is set before initializer is instantiated.
     private val underTest by lazy { kosmos.multiDisplayStatusBarStarter }
 
     @Before
-    fun setup() {
-        whenever(windowManager.shouldShowSystemDecors(Display.DEFAULT_DISPLAY)).thenReturn(true)
-        whenever(windowManager.shouldShowSystemDecors(DISPLAY_1)).thenReturn(true)
-        whenever(windowManager.shouldShowSystemDecors(DISPLAY_2)).thenReturn(true)
-        whenever(windowManager.shouldShowSystemDecors(DISPLAY_3)).thenReturn(true)
-        whenever(windowManager.shouldShowSystemDecors(DISPLAY_4_NO_SYSTEM_DECOR)).thenReturn(false)
+    fun setUp() = runBlocking {
+        fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY)
+        fakeDisplayRepository.addDisplay(DISPLAY_2)
     }
 
     @Test
-    fun start_startsInitializersForCurrentDisplays() =
+    fun start_triggerAddDisplaySystemDecoration_startsInitializersForDisplay() =
         testScope.runTest {
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_1)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_2)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-
             underTest.start()
             runCurrent()
 
+            fakeDisplayRepository.triggerAddDisplaySystemDecorationEvent(
+                displayId = DEFAULT_DISPLAY
+            )
+            fakeDisplayRepository.triggerAddDisplaySystemDecorationEvent(displayId = DISPLAY_2)
+
             expect
-                .that(fakeInitializerStore.forDisplay(displayId = DISPLAY_1).startedByCoreStartable)
+                .that(
+                    fakeInitializerStore
+                        .forDisplay(displayId = DEFAULT_DISPLAY)
+                        .startedByCoreStartable
+                )
                 .isTrue()
             expect
                 .that(fakeInitializerStore.forDisplay(displayId = DISPLAY_2).startedByCoreStartable)
                 .isTrue()
-            expect
-                .that(
-                    fakeInitializerStore
-                        .forDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-                        .startedByCoreStartable
-                )
-                .isFalse()
         }
 
     @Test
-    fun start_startsOrchestratorForCurrentDisplays() =
+    fun start_triggerAddDisplaySystemDecoration_startsOrchestratorForDisplay() =
         testScope.runTest {
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_1)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_2)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-
             underTest.start()
             runCurrent()
 
-            verify(fakeOrchestratorFactory.createdOrchestratorForDisplay(displayId = DISPLAY_1)!!)
+            fakeDisplayRepository.triggerAddDisplaySystemDecorationEvent(
+                displayId = DEFAULT_DISPLAY
+            )
+            fakeDisplayRepository.triggerAddDisplaySystemDecorationEvent(displayId = DISPLAY_2)
+            runCurrent()
+
+            verify(
+                    fakeOrchestratorFactory.createdOrchestratorForDisplay(
+                        displayId = DEFAULT_DISPLAY
+                    )!!
+                )
                 .start()
             verify(fakeOrchestratorFactory.createdOrchestratorForDisplay(displayId = DISPLAY_2)!!)
                 .start()
-            assertThat(
-                    fakeOrchestratorFactory.createdOrchestratorForDisplay(
-                        displayId = DISPLAY_4_NO_SYSTEM_DECOR
-                    )
-                )
-                .isNull()
         }
 
     @Test
-    fun start_startsPrivacyDotForCurrentDisplays() =
+    fun start_triggerAddDisplaySystemDecoration_startsPrivacyDotForNonDefaultDisplay() =
         testScope.runTest {
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_1)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_2)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-
             underTest.start()
             runCurrent()
 
-            verify(fakePrivacyDotStore.forDisplay(displayId = DISPLAY_1)).start()
+            fakeDisplayRepository.triggerAddDisplaySystemDecorationEvent(displayId = DISPLAY_2)
+
             verify(fakePrivacyDotStore.forDisplay(displayId = DISPLAY_2)).start()
-            verify(fakePrivacyDotStore.forDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR), never())
-                .start()
         }
 
     @Test
-    fun start_doesNotStartLightBarControllerForCurrentDisplays() =
+    fun start_triggerAddDisplaySystemDecoration_doesNotStartPrivacyDotForDefaultDisplay() =
         testScope.runTest {
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_1)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_2)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-
             underTest.start()
             runCurrent()
 
-            verify(fakeLightBarStore.forDisplay(displayId = DISPLAY_1), never()).start()
+            fakeDisplayRepository.triggerAddDisplaySystemDecorationEvent(
+                displayId = DEFAULT_DISPLAY
+            )
+
+            verify(fakePrivacyDotStore.forDisplay(displayId = DEFAULT_DISPLAY), never()).start()
+        }
+
+    @Test
+    fun start_triggerAddDisplaySystemDecoration_doesNotStartLightBarControllerForDisplays() =
+        testScope.runTest {
+            underTest.start()
+            runCurrent()
+
+            fakeDisplayRepository.triggerAddDisplaySystemDecorationEvent(
+                displayId = DEFAULT_DISPLAY
+            )
+            fakeDisplayRepository.triggerAddDisplaySystemDecorationEvent(displayId = DISPLAY_2)
+
+            verify(fakeLightBarStore.forDisplay(displayId = DEFAULT_DISPLAY), never()).start()
             verify(fakeLightBarStore.forDisplay(displayId = DISPLAY_2), never()).start()
-            verify(fakeLightBarStore.forDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR), never())
-                .start()
         }
 
     @Test
-    fun start_createsLightBarControllerForCurrentDisplays() =
-        testScope.runTest {
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_1)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_2)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-
-            underTest.start()
-            runCurrent()
-
-            assertThat(fakeLightBarStore.perDisplayMocks.keys).containsExactly(1, DISPLAY_2)
-        }
-
-    @Test
-    fun start_doesNotStartPrivacyDotForDefaultDisplay() =
-        testScope.runTest {
-            fakeDisplayRepository.addDisplay(displayId = Display.DEFAULT_DISPLAY)
-
-            underTest.start()
-            runCurrent()
-
-            verify(fakePrivacyDotStore.forDisplay(displayId = Display.DEFAULT_DISPLAY), never())
-                .start()
-        }
-
-    @Test
-    fun displayAdded_orchestratorForNewDisplay() =
+    fun start_triggerAddDisplaySystemDecoration_createsLightBarControllerForDisplay() =
         testScope.runTest {
             underTest.start()
             runCurrent()
 
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_3)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-            runCurrent()
+            fakeDisplayRepository.triggerAddDisplaySystemDecorationEvent(
+                displayId = DEFAULT_DISPLAY
+            )
+            fakeDisplayRepository.triggerAddDisplaySystemDecorationEvent(displayId = DISPLAY_2)
 
-            verify(fakeOrchestratorFactory.createdOrchestratorForDisplay(displayId = DISPLAY_3)!!)
-                .start()
-            assertThat(
-                    fakeOrchestratorFactory.createdOrchestratorForDisplay(
-                        displayId = DISPLAY_4_NO_SYSTEM_DECOR
-                    )
-                )
-                .isNull()
-        }
-
-    @Test
-    fun displayAdded_initializerForNewDisplay() =
-        testScope.runTest {
-            underTest.start()
-            runCurrent()
-
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_3)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-            runCurrent()
-
-            expect
-                .that(fakeInitializerStore.forDisplay(displayId = DISPLAY_3).startedByCoreStartable)
-                .isTrue()
-            expect
-                .that(
-                    fakeInitializerStore
-                        .forDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-                        .startedByCoreStartable
-                )
-                .isFalse()
-        }
-
-    @Test
-    fun displayAdded_privacyDotForNewDisplay() =
-        testScope.runTest {
-            underTest.start()
-            runCurrent()
-
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_3)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-            runCurrent()
-
-            verify(fakePrivacyDotStore.forDisplay(displayId = DISPLAY_3)).start()
-            verify(fakePrivacyDotStore.forDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR), never())
-                .start()
-        }
-
-    @Test
-    fun displayAdded_lightBarForNewDisplayCreate() =
-        testScope.runTest {
-            underTest.start()
-            runCurrent()
-
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_3)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-            runCurrent()
-
-            assertThat(fakeLightBarStore.perDisplayMocks.keys).containsExactly(DISPLAY_3)
-        }
-
-    @Test
-    fun displayAdded_lightBarForNewDisplayStart() =
-        testScope.runTest {
-            underTest.start()
-            runCurrent()
-
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_3)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-            runCurrent()
-
-            verify(fakeLightBarStore.forDisplay(displayId = DISPLAY_3), never()).start()
-            verify(fakeLightBarStore.forDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR), never())
-                .start()
-        }
-
-    @Test
-    fun displayAddedDuringStart_initializerForNewDisplay() =
-        testScope.runTest {
-            underTest.start()
-
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_3)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-            runCurrent()
-
-            expect
-                .that(fakeInitializerStore.forDisplay(displayId = DISPLAY_3).startedByCoreStartable)
-                .isTrue()
-            expect
-                .that(
-                    fakeInitializerStore
-                        .forDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-                        .startedByCoreStartable
-                )
-                .isFalse()
-        }
-
-    @Test
-    fun displayAddedDuringStart_orchestratorForNewDisplay() =
-        testScope.runTest {
-            underTest.start()
-
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_3)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-            runCurrent()
-
-            verify(fakeOrchestratorFactory.createdOrchestratorForDisplay(displayId = DISPLAY_3)!!)
-                .start()
-            assertThat(
-                    fakeOrchestratorFactory.createdOrchestratorForDisplay(
-                        displayId = DISPLAY_4_NO_SYSTEM_DECOR
-                    )
-                )
-                .isNull()
-        }
-
-    @Test
-    fun displayAddedDuringStart_privacyDotForNewDisplay() =
-        testScope.runTest {
-            underTest.start()
-
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_3)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-            runCurrent()
-
-            verify(fakePrivacyDotStore.forDisplay(displayId = DISPLAY_3)).start()
-            verify(fakePrivacyDotStore.forDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR), never())
-                .start()
-        }
-
-    @Test
-    fun displayAddedDuringStart_lightBarForNewDisplayCreate() =
-        testScope.runTest {
-            underTest.start()
-
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_3)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-            runCurrent()
-
-            assertThat(fakeLightBarStore.perDisplayMocks.keys).containsExactly(DISPLAY_3)
-        }
-
-    @Test
-    fun displayAddedDuringStart_lightBarForNewDisplayStart() =
-        testScope.runTest {
-            underTest.start()
-
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_3)
-            fakeDisplayRepository.addDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR)
-            runCurrent()
-
-            verify(fakeLightBarStore.forDisplay(displayId = DISPLAY_3), never()).start()
-            verify(fakeLightBarStore.forDisplay(displayId = DISPLAY_4_NO_SYSTEM_DECOR), never())
-                .start()
+            assertThat(fakeLightBarStore.perDisplayMocks.keys)
+                .containsExactly(DEFAULT_DISPLAY, DISPLAY_2)
         }
 
     companion object {
-        const val DISPLAY_1 = 1
         const val DISPLAY_2 = 2
-        const val DISPLAY_3 = 3
-        const val DISPLAY_4_NO_SYSTEM_DECOR = 4
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt
index 884c35c..500332f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/LightBarControllerStoreImplTest.kt
@@ -65,11 +65,11 @@
         }
 
     @Test
-    fun displayRemoved_stopsInstance() =
+    fun systemDecorationRemovedEvent_stopsInstance() =
         testScope.runTest {
             val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
-            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+            fakeDisplayRepository.triggerRemoveSystemDecorationEvent(DEFAULT_DISPLAY)
 
             verify(instance).stop()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt
index f37648a..62ead9b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayDarkIconDispatcherStoreTest.kt
@@ -62,11 +62,11 @@
         }
 
     @Test
-    fun displayRemoved_stopsInstance() =
+    fun systemDecorationRemovedEvent_stopsInstance() =
         testScope.runTest {
             val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
-            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+            fakeDisplayRepository.triggerRemoveSystemDecorationEvent(DEFAULT_DISPLAY)
 
             verify(instance).stop()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt
index e0a1f27..486a845 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarContentInsetsProviderStoreTest.kt
@@ -65,11 +65,11 @@
         }
 
     @Test
-    fun displayRemoved_stopsInstance() =
+    fun systemDecorationRemovedEvent_stopsInstance() =
         testScope.runTest {
             val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
-            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+            fakeDisplayRepository.triggerRemoveSystemDecorationEvent(DEFAULT_DISPLAY)
 
             verify(instance).stop()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
index 11fd902..2c474da 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/MultiDisplayStatusBarModeRepositoryStoreTest.kt
@@ -59,11 +59,11 @@
         }
 
     @Test
-    fun displayRemoved_stopsInstance() =
+    fun systemDecorationRemovedEvent_stopsInstance() =
         testScope.runTest {
             val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
-            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+            fakeDisplayRepository.triggerRemoveSystemDecorationEvent(DEFAULT_DISPLAY)
 
             verify(instance).stop()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStoreImplTest.kt
index a5b7fc2..bc7d47c 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStoreImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStoreImplTest.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.display.data.repository.displayRepository
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.testKosmos
 import kotlinx.coroutines.runBlocking
@@ -36,7 +37,7 @@
 @RunWith(AndroidJUnit4::class)
 @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
 class PrivacyDotWindowControllerStoreImplTest : SysuiTestCase() {
-    private val kosmos = testKosmos()
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val testScope = kosmos.testScope
     private val underTest by lazy { kosmos.privacyDotWindowControllerStoreImpl }
 
@@ -58,11 +59,11 @@
     }
 
     @Test
-    fun displayRemoved_stopsInstance() =
+    fun systemDecorationRemovedEvent_stopsInstance() =
         testScope.runTest {
             val instance = underTest.forDisplay(DISPLAY_2)!!
 
-            kosmos.displayRepository.removeDisplay(DISPLAY_2)
+            kosmos.displayRepository.triggerRemoveSystemDecorationEvent(DISPLAY_2)
 
             verify(instance).stop()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayStoreImplTest.kt
new file mode 100644
index 0000000..41ae377
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayStoreImplTest.kt
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.data.repository
+
+import android.view.Display
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@RunWith(AndroidJUnit4::class)
+@SmallTest
+class StatusBarPerDisplayStoreImplTest : SysuiTestCase() {
+
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+    private val testScope = kosmos.testScope
+    private val fakeDisplayRepository = kosmos.displayRepository
+
+    private val store = kosmos.fakeStatusBarPerDisplayStore
+
+    @Before
+    fun start() {
+        store.start()
+    }
+
+    @Before
+    fun addDisplays() = runBlocking {
+        fakeDisplayRepository.addDisplay(DEFAULT_DISPLAY_ID)
+        fakeDisplayRepository.addDisplay(NON_DEFAULT_DISPLAY_ID)
+    }
+
+    @Test
+    fun removeSystemDecoration_onDisplayRemovalActionInvoked() =
+        testScope.runTest {
+            val instance = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
+
+            fakeDisplayRepository.triggerRemoveSystemDecorationEvent(NON_DEFAULT_DISPLAY_ID)
+
+            assertThat(store.removalActions).containsExactly(instance)
+        }
+
+    @Test
+    fun removeSystemDecoration_twice_onDisplayRemovalActionInvokedOnce() =
+        testScope.runTest {
+            val instance = store.forDisplay(NON_DEFAULT_DISPLAY_ID)
+
+            fakeDisplayRepository.triggerRemoveSystemDecorationEvent(NON_DEFAULT_DISPLAY_ID)
+            fakeDisplayRepository.triggerRemoveSystemDecorationEvent(NON_DEFAULT_DISPLAY_ID)
+
+            assertThat(store.removalActions).containsExactly(instance)
+        }
+
+    @Test
+    fun forDisplay_withoutDisplayRemoval_onDisplayRemovalActionIsNotInvoked() =
+        testScope.runTest {
+            store.forDisplay(NON_DEFAULT_DISPLAY_ID)
+
+            assertThat(store.removalActions).isEmpty()
+        }
+
+    companion object {
+        private const val DEFAULT_DISPLAY_ID = Display.DEFAULT_DISPLAY
+        private const val NON_DEFAULT_DISPLAY_ID = DEFAULT_DISPLAY_ID + 1
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt
index 3cc592c..94394ed 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStoreImplTest.kt
@@ -62,11 +62,11 @@
         }
 
     @Test
-    fun displayRemoved_stopsInstance() =
+    fun systemDecorationRemovedEvent_stopsInstance() =
         testScope.runTest {
             val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
-            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+            fakeDisplayRepository.triggerRemoveSystemDecorationEvent(DEFAULT_DISPLAY)
 
             verify(instance).stop()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelTest.kt
index d36dbbe..d4518e7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelTest.kt
@@ -21,9 +21,10 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.flags.parameterizeSceneContainerFlag
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.collectLastValue
 import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testScope
 import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.lifecycle.activateIn
 import com.android.systemui.media.controls.data.repository.mediaFilterRepository
 import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
 import com.android.systemui.media.controls.shared.model.MediaData
@@ -47,7 +48,8 @@
 class MediaControlChipViewModelTest(flags: FlagsParameterization) : SysuiTestCase() {
     private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val mediaControlChipInteractor by lazy { kosmos.mediaControlChipInteractor }
-    private val Kosmos.underTest by Kosmos.Fixture { kosmos.mediaControlChipViewModel }
+    private val Kosmos.underTest by
+        Kosmos.Fixture { kosmos.mediaControlChipViewModelFactory.create() }
     @Captor lateinit var listener: ArgumentCaptor<MediaDataManager.Listener>
 
     companion object {
@@ -62,6 +64,7 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         mediaControlChipInteractor.initialize()
+        kosmos.underTest.activateIn(kosmos.testScope)
     }
 
     init {
@@ -71,7 +74,7 @@
     @Test
     fun chip_noActiveMedia_IsHidden() =
         kosmos.runTest {
-            val chip by collectLastValue(underTest.chip)
+            val chip = underTest.chip
 
             assertThat(chip).isInstanceOf(PopupChipModel.Hidden::class.java)
         }
@@ -79,30 +82,26 @@
     @Test
     fun chip_activeMedia_IsShown() =
         kosmos.runTest {
-            val chip by collectLastValue(underTest.chip)
-
             val userMedia = MediaData(active = true, song = "test")
             updateMedia(userMedia)
 
-            assertThat(chip).isInstanceOf(PopupChipModel.Shown::class.java)
+            assertThat(underTest.chip).isInstanceOf(PopupChipModel.Shown::class.java)
         }
 
     @Test
     fun chip_songNameChanges_chipTextUpdated() =
         kosmos.runTest {
-            val chip by collectLastValue(underTest.chip)
-
             val initialSongName = "Initial Song"
             val newSongName = "New Song"
             val userMedia = MediaData(active = true, song = initialSongName)
             updateMedia(userMedia)
-            assertThat(chip).isInstanceOf(PopupChipModel.Shown::class.java)
-            assertThat((chip as PopupChipModel.Shown).chipText).isEqualTo(initialSongName)
+            assertThat(underTest.chip).isInstanceOf(PopupChipModel.Shown::class.java)
+            assertThat((underTest.chip as PopupChipModel.Shown).chipText).isEqualTo(initialSongName)
 
             val updatedUserMedia = userMedia.copy(song = newSongName)
             updateMedia(updatedUserMedia)
 
-            assertThat((chip as PopupChipModel.Shown).chipText).isEqualTo(newSongName)
+            assertThat((underTest.chip as PopupChipModel.Shown).chipText).isEqualTo(newSongName)
         }
 
     private fun updateMedia(mediaData: MediaData) {
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt
new file mode 100644
index 0000000..134ab93
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/StatusBarPopupChipsViewModelTest.kt
@@ -0,0 +1,95 @@
+/*
+ * 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.featurepods.media.ui.viewmodel
+
+import android.platform.test.annotations.EnableFlags
+import androidx.compose.runtime.snapshots.Snapshot
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.lifecycle.activateIn
+import com.android.systemui.media.controls.data.repository.mediaFilterRepository
+import com.android.systemui.media.controls.shared.model.MediaData
+import com.android.systemui.media.controls.shared.model.MediaDataLoadingModel
+import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
+import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
+import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.statusBarPopupChipsViewModelFactory
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@EnableFlags(StatusBarPopupChips.FLAG_NAME)
+@RunWith(AndroidJUnit4::class)
+class StatusBarPopupChipsViewModelTest : SysuiTestCase() {
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
+    private val underTest = kosmos.statusBarPopupChipsViewModelFactory.create()
+
+    @Before
+    fun setUp() {
+        underTest.activateIn(kosmos.testScope)
+    }
+
+    @Test
+    fun shownPopupChips_allHidden_empty() =
+        kosmos.runTest {
+            val shownPopupChips = underTest.shownPopupChips
+            assertThat(shownPopupChips).isEmpty()
+        }
+
+    @Test
+    fun shownPopupChips_activeMedia_restHidden_mediaControlChipShown() =
+        kosmos.runTest {
+            val shownPopupChips = underTest.shownPopupChips
+            val userMedia = MediaData(active = true, song = "test")
+            val instanceId = userMedia.instanceId
+
+            mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
+            mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+
+            Snapshot.takeSnapshot {
+                assertThat(shownPopupChips).hasSize(1)
+                assertThat(shownPopupChips.first().chipId).isEqualTo(PopupChipId.MediaControl)
+            }
+        }
+
+    @Test
+    fun shownPopupChips_mediaChipToggled_popupShown() =
+        kosmos.runTest {
+            val shownPopupChips = underTest.shownPopupChips
+
+            val userMedia = MediaData(active = true, song = "test")
+            val instanceId = userMedia.instanceId
+
+            mediaFilterRepository.addSelectedUserMediaEntry(userMedia)
+            mediaFilterRepository.addMediaDataLoadingState(MediaDataLoadingModel.Loaded(instanceId))
+
+            Snapshot.takeSnapshot {
+                assertThat(shownPopupChips).hasSize(1)
+                val mediaChip = shownPopupChips.first()
+                assertThat(mediaChip.isPopupShown).isFalse()
+
+                mediaChip.showPopup.invoke()
+                assertThat(shownPopupChips.first().isPopupShown).isTrue()
+            }
+        }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
index 0f1cdac..fdc6657 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/NotificationStackAppearanceIntegrationTest.kt
@@ -31,6 +31,8 @@
 import com.android.systemui.scene.domain.interactor.sceneInteractor
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.scene.shared.model.fakeSceneDataSource
+import com.android.systemui.shade.domain.interactor.enableDualShade
+import com.android.systemui.shade.domain.interactor.enableSingleShade
 import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds
 import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimShape
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationTransitionThresholds.EXPANSION_FOR_DELAYED_STACK_FADE_IN
@@ -69,6 +71,7 @@
     @Test
     fun updateBounds() =
         testScope.runTest {
+            kosmos.enableSingleShade()
             val radius = MutableStateFlow(32)
             val leftOffset = MutableStateFlow(0)
             val shape by
@@ -106,7 +109,7 @@
                     )
                 )
 
-            // When: QuickSettings shows up full screen
+            // When: QuickSettings shows up full screen on single shade.
             fakeKeyguardRepository.setStatusBarState(StatusBarState.SHADE)
             val transitionState =
                 MutableStateFlow<ObservableTransitionState>(
@@ -115,6 +118,10 @@
             sceneInteractor.setTransitionState(transitionState)
             // Then: shape is null
             assertThat(shape).isNull()
+
+            // Same scenario on Dual Shade, shape should have clipping bounds
+            kosmos.enableDualShade()
+            assertThat(shape).isNotNull()
         }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt
similarity index 68%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt
index 83fd5dc..a13b864 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapterTest.kt
@@ -34,123 +34,122 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 @RunWithLooper
-class BundleEntryTest : SysuiTestCase() {
-    private lateinit var underTest: BundleEntry
+class BundleEntryAdapterTest : SysuiTestCase() {
+    private lateinit var underTest: BundleEntryAdapter
 
-    @get:Rule
-    val setFlagsRule = SetFlagsRule()
+    @get:Rule val setFlagsRule = SetFlagsRule()
 
     @Before
     fun setUp() {
-        underTest = BundleEntry("key")
+        underTest = BundleEntryAdapter(BundleEntry("key"))
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getParent_adapter() {
-        assertThat(underTest.entryAdapter.parent).isEqualTo(GroupEntry.ROOT_ENTRY)
+        assertThat(underTest.parent).isEqualTo(GroupEntry.ROOT_ENTRY)
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isTopLevelEntry_adapter() {
-        assertThat(underTest.entryAdapter.isTopLevelEntry).isTrue()
+        assertThat(underTest.isTopLevelEntry).isTrue()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getRow_adapter() {
-        assertThat(underTest.entryAdapter.row).isNull()
+        assertThat(underTest.row).isNull()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isGroupRoot_adapter() {
-        assertThat(underTest.entryAdapter.isGroupRoot).isTrue()
+        assertThat(underTest.isGroupRoot).isTrue()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getKey_adapter() {
-        assertThat(underTest.entryAdapter.key).isEqualTo("key")
+        assertThat(underTest.key).isEqualTo("key")
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isClearable_adapter() {
-        assertThat(underTest.entryAdapter.isClearable).isTrue()
+        assertThat(underTest.isClearable).isTrue()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getSummarization_adapter() {
-        assertThat(underTest.entryAdapter.summarization).isNull()
+        assertThat(underTest.summarization).isNull()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getContrastedColor_adapter() {
-        assertThat(underTest.entryAdapter.getContrastedColor(context, false, Color.WHITE))
+        assertThat(underTest.getContrastedColor(context, false, Color.WHITE))
             .isEqualTo(Notification.COLOR_DEFAULT)
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun canPeek_adapter() {
-        assertThat(underTest.entryAdapter.canPeek()).isFalse()
+        assertThat(underTest.canPeek()).isFalse()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getWhen_adapter() {
-        assertThat(underTest.entryAdapter.`when`).isEqualTo(0)
+        assertThat(underTest.`when`).isEqualTo(0)
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isColorized() {
-        assertThat(underTest.entryAdapter.isColorized).isFalse()
+        assertThat(underTest.isColorized).isFalse()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getSbn() {
-        assertThat(underTest.entryAdapter.sbn).isNull()
+        assertThat(underTest.sbn).isNull()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun canDragAndDrop() {
-        assertThat(underTest.entryAdapter.canDragAndDrop()).isFalse()
+        assertThat(underTest.canDragAndDrop()).isFalse()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isBubble() {
-        assertThat(underTest.entryAdapter.isBubbleCapable).isFalse()
+        assertThat(underTest.isBubbleCapable).isFalse()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getStyle() {
-        assertThat(underTest.entryAdapter.style).isNull()
+        assertThat(underTest.style).isNull()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun getSectionBucket() {
-        assertThat(underTest.entryAdapter.sectionBucket).isEqualTo(underTest.bucket)
+        assertThat(underTest.sectionBucket).isEqualTo(underTest.entry.bucket)
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isAmbient() {
-        assertThat(underTest.entryAdapter.isAmbient).isFalse()
+        assertThat(underTest.isAmbient).isFalse()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun canShowFullScreen() {
-        assertThat(underTest.entryAdapter.isFullScreenCapable()).isFalse()
+        assertThat(underTest.isFullScreenCapable()).isFalse()
     }
-}
\ No newline at end of file
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt
new file mode 100644
index 0000000..b6889af
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapterTest.kt
@@ -0,0 +1,370 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.collection
+
+import android.app.ActivityManager
+import android.app.Notification
+import android.app.NotificationManager
+import android.app.PendingIntent
+import android.os.UserHandle
+import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.SetFlagsRule
+import android.testing.TestableLooper.RunWithLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.RankingBuilder
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.entryAdapterFactory
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
+import com.android.systemui.statusbar.notification.stack.BUCKET_ALERTING
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Rule
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+@RunWithLooper
+class NotificationEntryAdapterTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private val factory: EntryAdapterFactory = kosmos.entryAdapterFactory
+    private lateinit var underTest: NotificationEntryAdapter
+
+    @get:Rule val setFlagsRule = SetFlagsRule()
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getParent_adapter() {
+        val ge = GroupEntryBuilder().build()
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .setParent(ge)
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.parent).isEqualTo(entry.parent)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isTopLevelEntry_adapter() {
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .setParent(GroupEntry.ROOT_ENTRY)
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isTopLevelEntry).isTrue()
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getKey_adapter() {
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.key).isEqualTo(entry.key)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getRow_adapter() {
+        val row = Mockito.mock(ExpandableNotificationRow::class.java)
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .build()
+        entry.row = row
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.row).isEqualTo(entry.row)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isGroupRoot_adapter_groupSummary() {
+        val row = Mockito.mock(ExpandableNotificationRow::class.java)
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setGroupSummary(true)
+                .setGroup("key")
+                .build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .setParent(GroupEntry.ROOT_ENTRY)
+                .build()
+        entry.row = row
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isGroupRoot).isFalse()
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isGroupRoot_adapter_groupChild() {
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setGroupSummary(true)
+                .setGroup("key")
+                .build()
+
+        val parent = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
+        val groupEntry = GroupEntryBuilder().setSummary(parent)
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .setParent(groupEntry.build())
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isGroupRoot).isFalse()
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isClearable_adapter() {
+        val row = Mockito.mock(ExpandableNotificationRow::class.java)
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .build()
+        entry.row = row
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isClearable).isEqualTo(entry.isClearable)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getSummarization_adapter() {
+        val row = Mockito.mock(ExpandableNotificationRow::class.java)
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .build()
+        val ranking = RankingBuilder(entry.ranking).setSummarization("hello").build()
+        entry.setRanking(ranking)
+        entry.row = row
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.summarization).isEqualTo("hello")
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getIcons_adapter() {
+        val row = Mockito.mock(ExpandableNotificationRow::class.java)
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setUser(UserHandle(ActivityManager.getCurrentUser()))
+                .build()
+        entry.row = row
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.icons).isEqualTo(entry.icons)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isColorized() {
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setColorized(true)
+                .build()
+
+        val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isColorized).isEqualTo(entry.sbn.notification.isColorized)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getSbn() {
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.sbn).isEqualTo(entry.sbn)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun canDragAndDrop() {
+        val pi = Mockito.mock(PendingIntent::class.java)
+        Mockito.`when`(pi.isActivity).thenReturn(true)
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setContentIntent(pi)
+                .build()
+
+        val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.canDragAndDrop()).isTrue()
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isBubble() {
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setFlag(Notification.FLAG_BUBBLE, true)
+                .build()
+
+        val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isBubbleCapable).isEqualTo(entry.isBubble)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getStyle() {
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setStyle(Notification.BigTextStyle())
+                .build()
+
+        val entry = NotificationEntryBuilder().setNotification(notification).build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.style).isEqualTo(entry.notificationStyle)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun getSectionBucket() {
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setStyle(Notification.BigTextStyle())
+                .build()
+
+        val entry = NotificationEntryBuilder().setNotification(notification).build()
+        entry.bucket = BUCKET_ALERTING
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.sectionBucket).isEqualTo(BUCKET_ALERTING)
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun isAmbient() {
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setImportance(NotificationManager.IMPORTANCE_MIN)
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isAmbient).isTrue()
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun canShowFullScreen() {
+        val notification: Notification =
+            Notification.Builder(mContext, "")
+                .setSmallIcon(R.drawable.ic_person)
+                .setFullScreenIntent(Mockito.mock(PendingIntent::class.java), true)
+                .build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setImportance(NotificationManager.IMPORTANCE_MIN)
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+        assertThat(underTest.isFullScreenCapable).isTrue()
+    }
+
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    fun onNotificationBubbleIconClicked() {
+        val notification: Notification =
+            Notification.Builder(mContext, "").setSmallIcon(R.drawable.ic_person).build()
+
+        val entry =
+            NotificationEntryBuilder()
+                .setNotification(notification)
+                .setImportance(NotificationManager.IMPORTANCE_MIN)
+                .build()
+
+        underTest = factory.create(entry) as NotificationEntryAdapter
+
+        underTest.onNotificationBubbleIconClicked()
+        verify((factory as? EntryAdapterFactoryImpl)?.getNotificationActivityStarter())
+            ?.onNotificationBubbleIconClicked(entry)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
index 4810813..790b2c3 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/NotificationEntryTest.java
@@ -21,24 +21,17 @@
 import static android.app.Notification.CATEGORY_EVENT;
 import static android.app.Notification.CATEGORY_MESSAGE;
 import static android.app.Notification.CATEGORY_REMINDER;
-import static android.app.Notification.FLAG_BUBBLE;
 import static android.app.Notification.FLAG_FSI_REQUESTED_BUT_DENIED;
 import static android.app.Notification.FLAG_PROMOTED_ONGOING;
-import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.NotificationManager.Policy.SUPPRESSED_EFFECT_AMBIENT;
 
 import static com.android.systemui.statusbar.NotificationEntryHelper.modifyRanking;
 import static com.android.systemui.statusbar.NotificationEntryHelper.modifySbn;
-import static com.android.systemui.statusbar.notification.stack.NotificationPriorityBucketKt.BUCKET_ALERTING;
-
-import static com.google.common.truth.Truth.assertThat;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.mock;
-import static org.mockito.Mockito.when;
 
 import android.app.ActivityManager;
 import android.app.Notification;
@@ -66,8 +59,6 @@
 import com.android.systemui.statusbar.SbnBuilder;
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi;
-import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
-import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
 import com.android.systemui.util.time.FakeSystemClock;
 
 import org.junit.Before;
@@ -458,336 +449,6 @@
         // no crash, good
     }
 
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getParent_adapter() {
-        GroupEntry ge = new GroupEntryBuilder()
-                .build();
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .setParent(ge)
-                .build();
-
-        assertThat(entry.getEntryAdapter().getParent()).isEqualTo(entry.getParent());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isTopLevelEntry_adapter() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .setParent(GroupEntry.ROOT_ENTRY)
-                .build();
-
-        assertThat(entry.getEntryAdapter().isTopLevelEntry()).isTrue();
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getKey_adapter() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
-
-        assertThat(entry.getEntryAdapter().getKey()).isEqualTo(entry.getKey());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getRow_adapter() {
-        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
-        entry.setRow(row);
-
-        assertThat(entry.getEntryAdapter().getRow()).isEqualTo(entry.getRow());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isGroupRoot_adapter_groupSummary() {
-        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setGroupSummary(true)
-                .setGroup("key")
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .setParent(GroupEntry.ROOT_ENTRY)
-                .build();
-        entry.setRow(row);
-
-        assertThat(entry.getEntryAdapter().isGroupRoot()).isFalse();
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isGroupRoot_adapter_groupChild() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setGroupSummary(true)
-                .setGroup("key")
-                .build();
-
-        NotificationEntry parent = new NotificationEntryBuilder()
-                .setParent(GroupEntry.ROOT_ENTRY)
-                .build();
-        GroupEntryBuilder groupEntry = new GroupEntryBuilder()
-                .setSummary(parent);
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .setParent(groupEntry.build())
-                .build();
-
-        assertThat(entry.getEntryAdapter().isGroupRoot()).isFalse();
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isClearable_adapter() {
-        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
-        entry.setRow(row);
-
-        assertThat(entry.getEntryAdapter().isClearable()).isEqualTo(entry.isClearable());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getSummarization_adapter() {
-        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
-        Ranking ranking = new RankingBuilder(entry.getRanking())
-                .setSummarization("hello")
-                .build();
-        entry.setRanking(ranking);
-        entry.setRow(row);
-
-        assertThat(entry.getEntryAdapter().getSummarization()).isEqualTo("hello");
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getIcons_adapter() {
-        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setPkg(TEST_PACKAGE_NAME)
-                .setOpPkg(TEST_PACKAGE_NAME)
-                .setUid(TEST_UID)
-                .setChannel(mChannel)
-                .setId(mId++)
-                .setNotification(notification)
-                .setUser(new UserHandle(ActivityManager.getCurrentUser()))
-                .build();
-        entry.setRow(row);
-
-        assertThat(entry.getEntryAdapter().getIcons()).isEqualTo(entry.getIcons());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isColorized() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setColorized(true)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .build();
-        assertThat(entry.getEntryAdapter().isColorized()).isEqualTo(
-                entry.getSbn().getNotification().isColorized());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getSbn() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .build();
-        assertThat(entry.getEntryAdapter().getSbn()).isEqualTo(
-                entry.getSbn());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void canDragAndDrop() {
-        PendingIntent pi = mock(PendingIntent.class);
-        when(pi.isActivity()).thenReturn(true);
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setContentIntent(pi)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .build();
-        assertThat(entry.getEntryAdapter().canDragAndDrop()).isTrue();
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isBubble() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setFlag(FLAG_BUBBLE, true)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .build();
-        assertThat(entry.getEntryAdapter().isBubbleCapable()).isEqualTo(entry.isBubble());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getStyle() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setStyle(new Notification.BigTextStyle())
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .build();
-        assertThat(entry.getEntryAdapter().getStyle()).isEqualTo(entry.getNotificationStyle());
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void getSectionBucket() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setStyle(new Notification.BigTextStyle())
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .build();
-        entry.setBucket(BUCKET_ALERTING);
-
-        assertThat(entry.getEntryAdapter().getSectionBucket()).isEqualTo(BUCKET_ALERTING);
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void isAmbient() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .setImportance(IMPORTANCE_MIN)
-                .build();
-
-        assertThat(entry.getEntryAdapter().isAmbient()).isTrue();
-    }
-
-    @Test
-    @EnableFlags(NotificationBundleUi.FLAG_NAME)
-    public void canShowFullScreen() {
-        Notification notification = new Notification.Builder(mContext, "")
-                .setSmallIcon(R.drawable.ic_person)
-                .setFullScreenIntent(mock(PendingIntent.class), true)
-                .build();
-
-        NotificationEntry entry = new NotificationEntryBuilder()
-                .setNotification(notification)
-                .setImportance(IMPORTANCE_MIN)
-                .build();
-
-        assertThat(entry.getEntryAdapter().isFullScreenCapable()).isTrue();
-    }
-
     private Notification.Action createContextualAction(String title) {
         return new Notification.Action.Builder(
                 Icon.createWithResource(getContext(), android.R.drawable.sym_def_app_icon),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
index 609885d..3098355 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinatorTest.kt
@@ -549,7 +549,7 @@
 
     @Test
     @EnableFlags(StatusBarNotifChips.FLAG_NAME)
-    fun onPromotedNotificationChipTapped_chipTappedTwice_hunHiddenOnSecondTap() =
+    fun onPromotedNotificationChipTapped_chipTappedTwice_hunHiddenOnSecondTapImmediately() =
         testScope.runTest {
             whenever(notifCollection.getEntry(entry.key)).thenReturn(entry)
 
@@ -570,8 +570,9 @@
             executor.runAllReady()
             beforeFinalizeFilterListener.onBeforeFinalizeFilter(listOf(entry))
 
-            // THEN HUN is hidden
-            verify(headsUpManager).removeNotification(eq(entry.key), eq(false), any())
+            // THEN HUN is hidden and it's hidden immediately
+            verify(headsUpManager)
+                .removeNotification(eq(entry.key), /* releaseImmediately= */ eq(true), any())
         }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
index 8e6aedca..9e27c79 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerTest.kt
@@ -16,8 +16,6 @@
 
 package com.android.systemui.statusbar.notification.collection.render
 
-import android.os.Build
-import android.os.UserHandle
 import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.SetFlagsRule
@@ -26,6 +24,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.log.assertLogsWtf
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl
 import com.android.systemui.statusbar.notification.collection.GroupEntry
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
 import com.android.systemui.statusbar.notification.collection.ListEntry
@@ -36,12 +35,13 @@
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager.OnGroupExpansionChangeListener
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper
+import com.android.systemui.statusbar.notification.row.entryAdapterFactory
 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
+import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.withArgCaptor
 import com.google.common.truth.Truth.assertThat
-import org.junit.Assume
 import org.junit.Before
 import org.junit.Rule
 import org.junit.Test
@@ -54,11 +54,11 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class GroupExpansionManagerTest : SysuiTestCase() {
-    @get:Rule
-    val setFlagsRule = SetFlagsRule()
+    @get:Rule val setFlagsRule = SetFlagsRule()
 
     private lateinit var underTest: GroupExpansionManagerImpl
 
+    private val kosmos = testKosmos()
     private lateinit var testHelper: NotificationTestHelper
     private val dumpManager: DumpManager = mock()
     private val groupMembershipManager: GroupMembershipManager = mock()
@@ -66,15 +66,14 @@
     private val pipeline: NotifPipeline = mock()
     private lateinit var beforeRenderListListener: OnBeforeRenderListListener
 
+    private val factory: EntryAdapterFactoryImpl = kosmos.entryAdapterFactory
     private lateinit var summary1: NotificationEntry
     private lateinit var summary2: NotificationEntry
     private lateinit var entries: List<ListEntry>
 
     private fun notificationEntry(pkg: String, id: Int, parent: ExpandableNotificationRow?) =
         NotificationEntryBuilder().setPkg(pkg).setId(id).build().apply {
-            row = testHelper.createRow().apply {
-                setIsChildInGroup(true, parent)
-            }
+            row = testHelper.createRow().apply { setIsChildInGroup(true, parent) }
         }
 
     @Before
@@ -91,7 +90,7 @@
                         listOf(
                             notificationEntry("foo", 2, summary1.row),
                             notificationEntry("foo", 3, summary1.row),
-                            notificationEntry("foo", 4, summary1.row)
+                            notificationEntry("foo", 4, summary1.row),
                         )
                     )
                     .build(),
@@ -101,11 +100,11 @@
                         listOf(
                             notificationEntry("bar", 2, summary2.row),
                             notificationEntry("bar", 3, summary2.row),
-                            notificationEntry("bar", 4, summary2.row)
+                            notificationEntry("bar", 4, summary2.row),
                         )
                     )
                     .build(),
-                notificationEntry("baz", 1, null)
+                notificationEntry("baz", 1, null),
             )
 
         whenever(groupMembershipManager.getGroupSummary(summary1)).thenReturn(summary1)
@@ -135,18 +134,20 @@
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun notifyOnlyOnChange_withEntryAdapter() {
+        val entryAdapter1 = factory.create(summary1)
+        val entryAdapter2 = factory.create(summary2)
         var listenerCalledCount = 0
         underTest.registerGroupExpansionChangeListener { _, _ -> listenerCalledCount++ }
 
-        underTest.setGroupExpanded(summary1.entryAdapter, false)
+        underTest.setGroupExpanded(entryAdapter1, false)
         assertThat(listenerCalledCount).isEqualTo(0)
-        underTest.setGroupExpanded(summary1.entryAdapter, true)
+        underTest.setGroupExpanded(entryAdapter1, true)
         assertThat(listenerCalledCount).isEqualTo(1)
-        underTest.setGroupExpanded(summary2.entryAdapter, true)
+        underTest.setGroupExpanded(entryAdapter2, true)
         assertThat(listenerCalledCount).isEqualTo(2)
-        underTest.setGroupExpanded(summary1.entryAdapter, true)
+        underTest.setGroupExpanded(entryAdapter1, true)
         assertThat(listenerCalledCount).isEqualTo(2)
-        underTest.setGroupExpanded(summary2.entryAdapter, false)
+        underTest.setGroupExpanded(entryAdapter2, false)
         assertThat(listenerCalledCount).isEqualTo(3)
     }
 
@@ -168,16 +169,17 @@
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun expandUnattachedEntryAdapter() {
+        val entryAdapter = factory.create(summary1)
         // First, expand the entry when it is attached.
-        underTest.setGroupExpanded(summary1.entryAdapter, true)
-        assertThat(underTest.isGroupExpanded(summary1.entryAdapter)).isTrue()
+        underTest.setGroupExpanded(entryAdapter, true)
+        assertThat(underTest.isGroupExpanded(entryAdapter)).isTrue()
 
         // Un-attach it, and un-expand it.
         NotificationEntryBuilder.setNewParent(summary1, null)
-        underTest.setGroupExpanded(summary1.entryAdapter, false)
+        underTest.setGroupExpanded(entryAdapter, false)
 
         // Expanding again should throw.
-        assertLogsWtf { underTest.setGroupExpanded(summary1.entryAdapter, true) }
+        assertLogsWtf { underTest.setGroupExpanded(entryAdapter, true) }
     }
 
     @Test
@@ -207,6 +209,7 @@
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun syncWithPipeline_withEntryAdapter() {
+        val entryAdapter = factory.create(summary1)
         underTest.attach(pipeline)
         beforeRenderListListener = withArgCaptor {
             verify(pipeline).addOnBeforeRenderListListener(capture())
@@ -219,7 +222,7 @@
         verify(listener, never()).onGroupExpansionChange(any(), any())
 
         // Expand one of the groups.
-        underTest.setGroupExpanded(summary1.entryAdapter, true)
+        underTest.setGroupExpanded(entryAdapter, true)
         verify(listener).onGroupExpansionChange(summary1.row, true)
 
         // Empty the pipeline list and verify that the group is no longer expanded.
@@ -231,11 +234,15 @@
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isGroupExpanded() {
-        underTest.setGroupExpanded(summary1.entryAdapter, true)
+        val entryAdapter = summary1.row.entryAdapter
+        underTest.setGroupExpanded(entryAdapter, true)
 
-        assertThat(underTest.isGroupExpanded(summary1.entryAdapter)).isTrue();
-        assertThat(underTest.isGroupExpanded(
-            (entries[0] as? GroupEntry)?.getChildren()?.get(0)?.entryAdapter))
-            .isTrue();
+        assertThat(underTest.isGroupExpanded(entryAdapter)).isTrue()
+        assertThat(
+                underTest.isGroupExpanded(
+                    (entries[0] as? GroupEntry)?.getChildren()?.get(0)?.row?.entryAdapter
+                )
+            )
+            .isTrue()
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
index 2bbf094..0ccf585 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerTest.kt
@@ -22,10 +22,13 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl
 import com.android.systemui.statusbar.notification.collection.GroupEntry
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.row.entryAdapterFactory
 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
+import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import org.junit.Rule
 import org.junit.Test
@@ -35,8 +38,10 @@
 @RunWith(AndroidJUnit4::class)
 class GroupMembershipManagerTest : SysuiTestCase() {
 
-    @get:Rule
-    val setFlagsRule = SetFlagsRule()
+    @get:Rule val setFlagsRule = SetFlagsRule()
+
+    private val kosmos = testKosmos()
+    private val factory: EntryAdapterFactoryImpl = kosmos.entryAdapterFactory
 
     private var underTest = GroupMembershipManagerImpl()
 
@@ -144,14 +149,14 @@
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isChildEntryAdapterInGroup_topLevel() {
         val topLevelEntry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
-        assertThat(underTest.isChildInGroup(topLevelEntry.entryAdapter)).isFalse()
+        assertThat(underTest.isChildInGroup(factory.create(topLevelEntry))).isFalse()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isChildEntryAdapterInGroup_noParent() {
         val noParentEntry = NotificationEntryBuilder().setParent(null).build()
-        assertThat(underTest.isChildInGroup(noParentEntry.entryAdapter)).isFalse()
+        assertThat(underTest.isChildInGroup(factory.create(noParentEntry))).isFalse()
     }
 
     @Test
@@ -165,7 +170,7 @@
                 .build()
         GroupEntryBuilder().setKey(groupKey).setSummary(summary).build()
 
-        assertThat(underTest.isChildInGroup(summary.entryAdapter)).isFalse()
+        assertThat(underTest.isChildInGroup(factory.create(summary))).isFalse()
     }
 
     @Test
@@ -180,14 +185,14 @@
         val entry = NotificationEntryBuilder().setGroup(mContext, groupKey).build()
         GroupEntryBuilder().setKey(groupKey).setSummary(summary).addChild(entry).build()
 
-        assertThat(underTest.isChildInGroup(entry.entryAdapter)).isTrue()
+        assertThat(underTest.isChildInGroup(factory.create(entry))).isTrue()
     }
 
     @Test
     @EnableFlags(NotificationBundleUi.FLAG_NAME)
     fun isGroupRoot_topLevelEntry() {
         val entry = NotificationEntryBuilder().setParent(GroupEntry.ROOT_ENTRY).build()
-        assertThat(underTest.isGroupRoot(entry.entryAdapter)).isFalse()
+        assertThat(underTest.isGroupRoot(factory.create(entry))).isFalse()
     }
 
     @Test
@@ -201,7 +206,7 @@
                 .build()
         GroupEntryBuilder().setKey(groupKey).setSummary(summary).build()
 
-        assertThat(underTest.isGroupRoot(summary.entryAdapter)).isTrue()
+        assertThat(underTest.isGroupRoot(factory.create(summary))).isTrue()
     }
 
     @Test
@@ -216,6 +221,6 @@
         val entry = NotificationEntryBuilder().setGroup(mContext, groupKey).build()
         GroupEntryBuilder().setKey(groupKey).setSummary(summary).addChild(entry).build()
 
-        assertThat(underTest.isGroupRoot(entry.entryAdapter)).isFalse()
+        assertThat(underTest.isGroupRoot(factory.create(entry))).isFalse()
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerTest.kt
index dc27859..a2e4a32 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/AvalancheControllerTest.kt
@@ -17,9 +17,10 @@
 
 import android.app.Notification
 import android.os.Handler
+import android.platform.test.annotations.DisableFlags
 import android.platform.test.annotations.EnableFlags
+import android.platform.test.flag.junit.FlagsParameterization
 import android.testing.TestableLooper.RunWithLooper
-import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.testing.UiEventLoggerFake
 import com.android.systemui.SysuiTestCase
@@ -28,6 +29,7 @@
 import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.plugins.statusbar.statusBarStateController
 import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.collection.provider.visualStabilityProvider
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManagerImpl
@@ -53,12 +55,18 @@
 import org.mockito.invocation.InvocationOnMock
 import org.mockito.junit.MockitoJUnit
 import org.mockito.junit.MockitoRule
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
 
 @SmallTest
 @RunWithLooper
-@RunWith(AndroidJUnit4::class)
+@RunWith(ParameterizedAndroidJunit4::class)
 @EnableFlags(NotificationThrottleHun.FLAG_NAME)
-class AvalancheControllerTest : SysuiTestCase() {
+class AvalancheControllerTest(val flags: FlagsParameterization) : SysuiTestCase() {
+    init {
+        mSetFlagsRule.setFlagsParameterization(flags)
+    }
+
     private val kosmos = testKosmos()
 
     // For creating mocks
@@ -72,10 +80,10 @@
     // For creating TestableHeadsUpManager
     @Mock private val mAccessibilityMgr: AccessibilityManagerWrapper? = null
     private val mUiEventLoggerFake = UiEventLoggerFake()
-    @Mock private lateinit var mHeadsUpManagerLogger: HeadsUpManagerLogger
+    private val headsUpManagerLogger = HeadsUpManagerLogger(logcatLogBuffer())
     @Mock private lateinit var mBgHandler: Handler
 
-    private val mLogger = Mockito.spy(HeadsUpManagerLogger(logcatLogBuffer()))
+    private val mLogger = Mockito.spy(headsUpManagerLogger)
     private val mGlobalSettings = FakeGlobalSettings()
     private val mSystemClock = FakeSystemClock()
     private val mExecutor = FakeExecutor(mSystemClock)
@@ -95,7 +103,7 @@
         // Initialize AvalancheController and TestableHeadsUpManager during setUp instead of
         // declaration, where mocks are null
         mAvalancheController =
-            AvalancheController(dumpManager, mUiEventLoggerFake, mHeadsUpManagerLogger, mBgHandler)
+            AvalancheController(dumpManager, mUiEventLoggerFake, headsUpManagerLogger, mBgHandler)
 
         testableHeadsUpManager =
             HeadsUpManagerImpl(
@@ -278,7 +286,7 @@
         // Delete
         mAvalancheController.delete(firstEntry, runnableMock, "testLabel")
 
-        // Next entry is shown
+        // Showing entry becomes previous
         assertThat(mAvalancheController.previousHunKey).isEqualTo(firstEntry.mEntry!!.key)
     }
 
@@ -296,12 +304,12 @@
         // Delete
         mAvalancheController.delete(showingEntry, runnableMock!!, "testLabel")
 
-        // Next entry is shown
+        // Previous key not filled in
         assertThat(mAvalancheController.previousHunKey).isEqualTo("")
     }
 
     @Test
-    fun testGetDurationMs_untrackedEntryEmptyAvalanche_useAutoDismissTime() {
+    fun testGetDuration_untrackedEntryEmptyAvalanche_useAutoDismissTime() {
         val givenEntry = createHeadsUpEntry(id = 0)
 
         // Nothing is showing
@@ -310,12 +318,12 @@
         // Nothing is next
         mAvalancheController.clearNext()
 
-        val durationMs = mAvalancheController.getDurationMs(givenEntry, autoDismissMs = 5000)
-        assertThat(durationMs).isEqualTo(5000)
+        val durationMs = mAvalancheController.getDuration(givenEntry, autoDismissMsValue = 5000)
+        assertThat((durationMs as RemainingDuration.UpdatedDuration).duration).isEqualTo(5000)
     }
 
     @Test
-    fun testGetDurationMs_untrackedEntryNonEmptyAvalanche_useAutoDismissTime() {
+    fun testGetDuration_untrackedEntryNonEmptyAvalanche_useAutoDismissTime() {
         val givenEntry = createHeadsUpEntry(id = 0)
 
         // Given entry not tracked
@@ -325,12 +333,12 @@
         val nextEntry = createHeadsUpEntry(id = 2)
         mAvalancheController.addToNext(nextEntry, runnableMock!!)
 
-        val durationMs = mAvalancheController.getDurationMs(givenEntry, autoDismissMs = 5000)
-        assertThat(durationMs).isEqualTo(5000)
+        val durationMs = mAvalancheController.getDuration(givenEntry, autoDismissMsValue = 5000)
+        assertThat((durationMs as RemainingDuration.UpdatedDuration).duration).isEqualTo(5000)
     }
 
     @Test
-    fun testGetDurationMs_lastEntry_useAutoDismissTime() {
+    fun testGetDuration_lastEntry_useAutoDismissTime() {
         // Entry is showing
         val showingEntry = createHeadsUpEntry(id = 0)
         mAvalancheController.headsUpEntryShowing = showingEntry
@@ -338,12 +346,12 @@
         // Nothing is next
         mAvalancheController.clearNext()
 
-        val durationMs = mAvalancheController.getDurationMs(showingEntry, autoDismissMs = 5000)
-        assertThat(durationMs).isEqualTo(5000)
+        val durationMs = mAvalancheController.getDuration(showingEntry, autoDismissMsValue = 5000)
+        assertThat((durationMs as RemainingDuration.UpdatedDuration).duration).isEqualTo(5000)
     }
 
     @Test
-    fun testGetDurationMs_nextEntryLowerPriority_5000() {
+    fun testGetDuration_nextEntryLowerPriority_5000() {
         // Entry is showing
         val showingEntry = createFsiHeadsUpEntry(id = 1)
         mAvalancheController.headsUpEntryShowing = showingEntry
@@ -355,12 +363,12 @@
         // Next entry has lower priority
         assertThat(nextEntry.compareNonTimeFields(showingEntry)).isEqualTo(1)
 
-        val durationMs = mAvalancheController.getDurationMs(showingEntry, autoDismissMs = 5000)
-        assertThat(durationMs).isEqualTo(5000)
+        val durationMs = mAvalancheController.getDuration(showingEntry, autoDismissMsValue = 5000)
+        assertThat((durationMs as RemainingDuration.UpdatedDuration).duration).isEqualTo(5000)
     }
 
     @Test
-    fun testGetDurationMs_nextEntrySamePriority_1000() {
+    fun testGetDuration_nextEntrySamePriority_1000() {
         // Entry is showing
         val showingEntry = createHeadsUpEntry(id = 0)
         mAvalancheController.headsUpEntryShowing = showingEntry
@@ -372,12 +380,12 @@
         // Same priority
         assertThat(nextEntry.compareNonTimeFields(showingEntry)).isEqualTo(0)
 
-        val durationMs = mAvalancheController.getDurationMs(showingEntry, autoDismissMs = 5000)
-        assertThat(durationMs).isEqualTo(1000)
+        val durationMs = mAvalancheController.getDuration(showingEntry, autoDismissMsValue = 5000)
+        assertThat((durationMs as RemainingDuration.UpdatedDuration).duration).isEqualTo(1000)
     }
 
     @Test
-    fun testGetDurationMs_nextEntryHigherPriority_500() {
+    fun testGetDuration_nextEntryHigherPriority_500() {
         // Entry is showing
         val showingEntry = createHeadsUpEntry(id = 0)
         mAvalancheController.headsUpEntryShowing = showingEntry
@@ -389,7 +397,51 @@
         // Next entry has higher priority
         assertThat(nextEntry.compareNonTimeFields(showingEntry)).isEqualTo(-1)
 
-        val durationMs = mAvalancheController.getDurationMs(showingEntry, autoDismissMs = 5000)
-        assertThat(durationMs).isEqualTo(500)
+        val durationMs = mAvalancheController.getDuration(showingEntry, autoDismissMsValue = 5000)
+        assertThat((durationMs as RemainingDuration.UpdatedDuration).duration).isEqualTo(500)
+    }
+
+    @Test
+    @DisableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun testGetDuration_nextEntryIsPinnedByUser_flagOff_1000() {
+        // Entry is showing
+        val showingEntry = createHeadsUpEntry(id = 0)
+        mAvalancheController.headsUpEntryShowing = showingEntry
+
+        // There's another entry waiting to show next and it's PinnedByUser
+        val nextEntry = createHeadsUpEntry(id = 1)
+        nextEntry.requestedPinnedStatus = PinnedStatus.PinnedByUser
+        mAvalancheController.addToNext(nextEntry, runnableMock!!)
+
+        val durationMs = mAvalancheController.getDuration(showingEntry, autoDismissMsValue = 5000)
+
+        // BUT PinnedByUser is ignored because flag is off, so the duration for a SAME priority next
+        // is used
+        assertThat((durationMs as RemainingDuration.UpdatedDuration).duration).isEqualTo(1000)
+    }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    fun testGetDuration_nextEntryIsPinnedByUser_flagOn_hideImmediately() {
+        // Entry is showing
+        val showingEntry = createHeadsUpEntry(id = 0)
+        mAvalancheController.headsUpEntryShowing = showingEntry
+
+        // There's another entry waiting to show next and it's PinnedByUser
+        val nextEntry = createHeadsUpEntry(id = 1)
+        nextEntry.requestedPinnedStatus = PinnedStatus.PinnedByUser
+        mAvalancheController.addToNext(nextEntry, runnableMock!!)
+
+        val duration = mAvalancheController.getDuration(showingEntry, autoDismissMsValue = 5000)
+
+        assertThat(duration).isEqualTo(RemainingDuration.HideImmediately)
+    }
+
+    companion object {
+        @JvmStatic
+        @Parameters(name = "{0}")
+        fun getParams(): List<FlagsParameterization> {
+            return FlagsParameterization.allCombinationsOf(StatusBarNotifChips.FLAG_NAME)
+        }
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimatorTest.kt
index 206eb89..706885b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimatorTest.kt
@@ -21,6 +21,8 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.ui.fakeSystemBarUtilsProxy
+import com.android.systemui.testKosmos
 import com.google.common.truth.Truth.assertThat
 import kotlin.test.Test
 import org.junit.Before
@@ -30,6 +32,8 @@
 @RunWith(AndroidJUnit4::class)
 @EnableFlags(NotificationsHunSharedAnimationValues.FLAG_NAME)
 class HeadsUpAnimatorTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
     @Before
     fun setUp() {
         context.getOrCreateTestableResources().apply {
@@ -38,34 +42,64 @@
     }
 
     @Test
-    fun getHeadsUpYTranslation_fromBottomTrue_usesBottomAndYAbove() {
-        val underTest = HeadsUpAnimator(context)
+    fun getHeadsUpYTranslation_fromBottomTrue_hasStatusBarChipFalse_usesBottomAndYAbove() {
+        val underTest = HeadsUpAnimator(context, kosmos.fakeSystemBarUtilsProxy)
         underTest.stackTopMargin = 30
         underTest.headsUpAppearHeightBottom = 300
 
-        val yTranslation = underTest.getHeadsUpYTranslation(isHeadsUpFromBottom = true)
+        val yTranslation =
+            underTest.getHeadsUpYTranslation(isHeadsUpFromBottom = true, hasStatusBarChip = false)
 
         assertThat(yTranslation).isEqualTo(TEST_Y_ABOVE_SCREEN + 300)
     }
 
     @Test
-    fun getHeadsUpYTranslation_fromBottomFalse_usesTopMarginAndYAbove() {
-        val underTest = HeadsUpAnimator(context)
+    fun getHeadsUpYTranslation_fromBottomTrue_hasStatusBarChipTrue_usesBottomAndYAbove() {
+        val underTest = HeadsUpAnimator(context, kosmos.fakeSystemBarUtilsProxy)
         underTest.stackTopMargin = 30
         underTest.headsUpAppearHeightBottom = 300
 
-        val yTranslation = underTest.getHeadsUpYTranslation(isHeadsUpFromBottom = false)
+        val yTranslation =
+            underTest.getHeadsUpYTranslation(isHeadsUpFromBottom = true, hasStatusBarChip = true)
+
+        // fromBottom takes priority
+        assertThat(yTranslation).isEqualTo(TEST_Y_ABOVE_SCREEN + 300)
+    }
+
+    @Test
+    fun getHeadsUpYTranslation_fromBottomFalse_hasStatusBarChipFalse_usesTopMarginAndYAbove() {
+        val underTest = HeadsUpAnimator(context, kosmos.fakeSystemBarUtilsProxy)
+        underTest.stackTopMargin = 30
+        underTest.headsUpAppearHeightBottom = 300
+
+        val yTranslation =
+            underTest.getHeadsUpYTranslation(isHeadsUpFromBottom = false, hasStatusBarChip = false)
 
         assertThat(yTranslation).isEqualTo(-30 - TEST_Y_ABOVE_SCREEN)
     }
 
     @Test
+    fun getHeadsUpYTranslation_fromBottomFalse_hasStatusBarChipTrue_usesTopMarginAndStatusBarHeight() {
+        val underTest = HeadsUpAnimator(context, kosmos.fakeSystemBarUtilsProxy)
+        underTest.stackTopMargin = 30
+        underTest.headsUpAppearHeightBottom = 300
+        kosmos.fakeSystemBarUtilsProxy.fakeStatusBarHeight = 75
+        underTest.updateResources(context)
+
+        val yTranslation =
+            underTest.getHeadsUpYTranslation(isHeadsUpFromBottom = false, hasStatusBarChip = true)
+
+        assertThat(yTranslation).isEqualTo(75 - 30)
+    }
+
+    @Test
     fun getHeadsUpYTranslation_resourcesUpdated() {
-        val underTest = HeadsUpAnimator(context)
+        val underTest = HeadsUpAnimator(context, kosmos.fakeSystemBarUtilsProxy)
         underTest.stackTopMargin = 30
         underTest.headsUpAppearHeightBottom = 300
 
-        val yTranslation = underTest.getHeadsUpYTranslation(isHeadsUpFromBottom = true)
+        val yTranslation =
+            underTest.getHeadsUpYTranslation(isHeadsUpFromBottom = true, hasStatusBarChip = false)
 
         assertThat(yTranslation).isEqualTo(TEST_Y_ABOVE_SCREEN + 300)
 
@@ -77,7 +111,12 @@
         underTest.updateResources(context)
 
         // THEN HeadsUpAnimator knows about it
-        assertThat(underTest.getHeadsUpYTranslation(isHeadsUpFromBottom = true))
+        assertThat(
+                underTest.getHeadsUpYTranslation(
+                    isHeadsUpFromBottom = true,
+                    hasStatusBarChip = false,
+                )
+            )
             .isEqualTo(newYAbove + 300)
     }
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt
index 216fd2d..3116143 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorImplTest.kt
@@ -57,7 +57,8 @@
 
     private val underTest = kosmos.promotedNotificationContentExtractor
     private val systemClock = kosmos.fakeSystemClock
-    private val rowImageInflater = RowImageInflater.newInstance(previousIndex = null)
+    private val rowImageInflater =
+        RowImageInflater.newInstance(previousIndex = null, reinflating = false)
     private val imageModelProvider by lazy { rowImageInflater.useForContentModel() }
 
     @Test
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt
index aa6e76d..6926677 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractorTest.kt
@@ -111,7 +111,7 @@
             )
 
             val topPromotedNotificationContent by
-                collectLastValue(underTest.topPromotedNotificationContent)
+                collectLastValue(underTest.aodPromotedNotification)
 
             // THEN the ron is first because the call has no content
             assertThat(topPromotedNotificationContent?.identity?.key)
@@ -131,7 +131,7 @@
             )
 
             val topPromotedNotificationContent by
-                collectLastValue(underTest.topPromotedNotificationContent)
+                collectLastValue(underTest.aodPromotedNotification)
 
             // THEN the call is the top notification
             assertThat(topPromotedNotificationContent?.identity?.key)
@@ -148,7 +148,7 @@
             renderNotificationListInteractor.setRenderedList(listOf(callEntry, otherEntry))
 
             val topPromotedNotificationContent by
-                collectLastValue(underTest.topPromotedNotificationContent)
+                collectLastValue(underTest.aodPromotedNotification)
 
             // THEN there is no top promoted notification
             assertThat(topPromotedNotificationContent).isNull()
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
index f060cae..bb12eff 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowControllerTest.kt
@@ -37,9 +37,12 @@
 import com.android.systemui.statusbar.SbnBuilder
 import com.android.systemui.statusbar.SmartReplyController
 import com.android.systemui.statusbar.notification.ColorUpdateLogger
+import com.android.systemui.statusbar.notification.NotificationActivityStarter
 import com.android.systemui.statusbar.notification.collection.EntryAdapter
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactory
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider
 import com.android.systemui.statusbar.notification.collection.render.FakeNodeController
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager
@@ -47,6 +50,7 @@
 import com.android.systemui.statusbar.notification.headsup.HeadsUpManager
 import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRowController.BUBBLES_SETTING_URI
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainer
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer
@@ -112,6 +116,7 @@
     private val uiEventLogger: UiEventLogger = mock()
     private val msdlPlayer: MSDLPlayer = mock()
     private val rebindingTracker: NotificationRebindingTracker = mock()
+    private val entryAdapterFactory: EntryAdapterFactory = mock()
     private lateinit var controller: ExpandableNotificationRowController
 
     @Before
@@ -154,6 +159,7 @@
                 uiEventLogger,
                 msdlPlayer,
                 rebindingTracker,
+                entryAdapterFactory,
             )
         whenever(view.childrenContainer).thenReturn(childrenContainer)
 
@@ -277,8 +283,10 @@
         whenever(view.privateLayout).thenReturn(childView)
         val entryAdapter = mock(EntryAdapter::class.java)
         val sbn =
-            SbnBuilder().setNotification(Notification.Builder(mContext).build())
-                .setUser(UserHandle.of(view.entry.sbn.userId)).build()
+            SbnBuilder()
+                .setNotification(Notification.Builder(mContext).build())
+                .setUser(UserHandle.of(view.entry.sbn.userId))
+                .build()
         whenever(entryAdapter.sbn).thenReturn(sbn)
         whenever(view.entryAdapter).thenReturn(entryAdapter)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
index ce3aee1..31413b0 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImplTest.kt
@@ -41,7 +41,6 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager.RedactionType
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor
-import com.android.systemui.statusbar.notification.collection.EntryAdapter
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.promoted.FakePromotedNotificationContentExtractor
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUi
@@ -204,7 +203,7 @@
         val result =
             NotificationRowContentBinderImpl.InflationProgress(
                 packageContext = mContext,
-                rowImageInflater = RowImageInflater.newInstance(null),
+                rowImageInflater = RowImageInflater.newInstance(null, reinflating = false),
                 remoteViews = NewRemoteViews(),
                 contentModel = NotificationContentModel(headsUpStatusBarModel),
                 promotedContent = null,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
index c376fad..8e7733b 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/row/NotificationTestHelper.java
@@ -70,10 +70,14 @@
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor;
+import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl;
 import com.android.systemui.statusbar.notification.collection.GroupEntry;
 import com.android.systemui.statusbar.notification.collection.GroupEntryBuilder;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder;
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
@@ -87,6 +91,7 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.ExpandableNotificationRowLogger;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow.OnExpandClickListener;
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag;
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
 import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
@@ -101,11 +106,6 @@
 import com.android.systemui.util.time.SystemClockImpl;
 import com.android.systemui.wmshell.BubblesTestActivity;
 
-import kotlin.coroutines.CoroutineContext;
-
-import kotlinx.coroutines.flow.StateFlowKt;
-import kotlinx.coroutines.test.TestScope;
-
 import org.mockito.ArgumentCaptor;
 
 import java.util.List;
@@ -114,6 +114,10 @@
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
 
+import kotlin.coroutines.CoroutineContext;
+import kotlinx.coroutines.flow.StateFlowKt;
+import kotlinx.coroutines.test.TestScope;
+
 /**
  * A helper class to create {@link ExpandableNotificationRow} (for both individual and group
  * notifications).
@@ -734,7 +738,16 @@
         mBindPipelineEntryListener.onEntryInit(entry);
         mBindPipeline.manageRow(entry, row);
 
+        EntryAdapter entryAdapter = new EntryAdapterFactoryImpl(
+                mock(NotificationActivityStarter.class),
+                mock(MetricsLogger.class),
+                mock(PeopleNotificationIdentifier.class),
+                mock(NotificationIconStyleProvider.class),
+                mock(VisualStabilityCoordinator.class)
+        ).create(entry);
+
         row.initialize(
+                entryAdapter,
                 entry,
                 mock(RemoteInputViewSubcomponent.Factory.class),
                 APP_NAME,
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
index 14bbd38..761ed61 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/NotificationChildrenContainerTest.java
@@ -27,6 +27,7 @@
 import android.view.View;
 import android.widget.RemoteViews;
 
+import androidx.compose.ui.platform.ComposeView;
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
 
@@ -35,7 +36,9 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationTestHelper;
 import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.BundleHeaderViewModelImpl;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper;
+import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
 
 import org.junit.Assert;
 import org.junit.Before;
@@ -273,6 +276,22 @@
         Assert.assertEquals(1f, header.getTopRoundness(), 0.001f);
     }
 
+    @Test
+    @EnableFlags(NotificationBundleUi.FLAG_NAME)
+    public void initBundleHeader_composeview_is_initialized_once() {
+        View currentView = mChildrenContainer.getChildAt(mChildrenContainer.getChildCount() - 1);
+        Assert.assertFalse(currentView instanceof ComposeView);
+
+        BundleHeaderViewModelImpl viewModel = new BundleHeaderViewModelImpl();
+        mChildrenContainer.initBundleHeader(viewModel);
+        currentView = mChildrenContainer.getChildAt(mChildrenContainer.getChildCount() - 1);
+        Assert.assertTrue(currentView instanceof ComposeView);
+
+        mChildrenContainer.initBundleHeader(viewModel);
+        View finalView = mChildrenContainer.getChildAt(mChildrenContainer.getChildCount() - 1);
+        Assert.assertEquals(currentView, finalView);
+    }
+
     private NotificationHeaderView createHeaderView(boolean lowPriority) {
         Notification notification = mNotificationTestHelper.createNotification();
         final Notification.Builder builder = Notification.Builder.recoverBuilder(getContext(),
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 9545150..08ecbac 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -2,6 +2,7 @@
 
 import android.annotation.DimenRes
 import android.content.pm.PackageManager
+import android.platform.test.annotations.EnableFlags
 import android.platform.test.flag.junit.FlagsParameterization
 import android.widget.FrameLayout
 import androidx.test.filters.SmallTest
@@ -19,6 +20,7 @@
 import com.android.systemui.shade.transition.LargeScreenShadeInterpolator
 import com.android.systemui.statusbar.NotificationShelf
 import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.notification.RoundableState
 import com.android.systemui.statusbar.notification.collection.EntryAdapter
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
@@ -32,6 +34,8 @@
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.statusbar.ui.fakeSystemBarUtilsProxy
+import com.android.systemui.testKosmos
 import com.google.common.truth.Expect
 import com.google.common.truth.Truth.assertThat
 import org.junit.Assume
@@ -53,6 +57,8 @@
 
     @JvmField @Rule var expect: Expect = Expect.create()
 
+    private val kosmos = testKosmos()
+
     private val largeScreenShadeInterpolator = mock<LargeScreenShadeInterpolator>()
     private val avalancheController = mock<AvalancheController>()
 
@@ -131,13 +137,14 @@
         hostView.addView(notificationRow)
 
         if (NotificationsHunSharedAnimationValues.isEnabled) {
-             headsUpAnimator = HeadsUpAnimator(context)
+            headsUpAnimator = HeadsUpAnimator(context, kosmos.fakeSystemBarUtilsProxy)
         }
-        stackScrollAlgorithm = StackScrollAlgorithm(
-            context,
-            hostView,
-            if (::headsUpAnimator.isInitialized) headsUpAnimator else null,
-        )
+        stackScrollAlgorithm =
+            StackScrollAlgorithm(
+                context,
+                hostView,
+                if (::headsUpAnimator.isInitialized) headsUpAnimator else null,
+            )
     }
 
     private fun isTv(): Boolean {
@@ -450,6 +457,46 @@
     }
 
     @Test
+    @EnableFlags(NotificationsHunSharedAnimationValues.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun resetViewStates_hunAnimatingAway_noStatusBarChip_hunTranslatedToTopOfScreen() {
+        val topMargin = 100f
+        ambientState.maxHeadsUpTranslation = 2000f
+        ambientState.stackTopMargin = topMargin.toInt()
+        headsUpAnimator?.stackTopMargin = topMargin.toInt()
+        whenever(notificationRow.intrinsicHeight).thenReturn(100)
+
+        val statusBarHeight = 432
+        kosmos.fakeSystemBarUtilsProxy.fakeStatusBarHeight = statusBarHeight
+        headsUpAnimator!!.updateResources(context)
+
+        whenever(notificationRow.isHeadsUpAnimatingAway).thenReturn(true)
+        whenever(notificationRow.hasStatusBarChipDuringHeadsUpAnimation()).thenReturn(false)
+
+        resetViewStates_hunYTranslationIs(
+            expected = -topMargin - stackScrollAlgorithm.mHeadsUpAppearStartAboveScreen
+        )
+    }
+
+    @Test
+    @EnableFlags(NotificationsHunSharedAnimationValues.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun resetViewStates_hunAnimatingAway_withStatusBarChip_hunTranslatedToBottomOfStatusBar() {
+        val topMargin = 100f
+        ambientState.maxHeadsUpTranslation = 2000f
+        ambientState.stackTopMargin = topMargin.toInt()
+        headsUpAnimator?.stackTopMargin = topMargin.toInt()
+        whenever(notificationRow.intrinsicHeight).thenReturn(100)
+
+        val statusBarHeight = 432
+        kosmos.fakeSystemBarUtilsProxy.fakeStatusBarHeight = statusBarHeight
+        headsUpAnimator!!.updateResources(context)
+
+        whenever(notificationRow.isHeadsUpAnimatingAway).thenReturn(true)
+        whenever(notificationRow.hasStatusBarChipDuringHeadsUpAnimation()).thenReturn(true)
+
+        resetViewStates_hunYTranslationIs(expected = statusBarHeight - topMargin)
+    }
+
+    @Test
     fun resetViewStates_hunAnimatingAway_bottomNotClipped() {
         whenever(notificationRow.isHeadsUpAnimatingAway).thenReturn(true)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
index cb4642c..f6c031f 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/StackStateAnimatorTest.kt
@@ -26,12 +26,15 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.animation.AnimatorTestRule
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.notification.headsup.HeadsUpAnimator
 import com.android.systemui.statusbar.notification.headsup.NotificationsHunSharedAnimationValues
 import com.android.systemui.statusbar.notification.row.ExpandableView
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout.AnimationEvent
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_HEADS_UP_APPEAR
 import com.android.systemui.statusbar.notification.stack.StackStateAnimator.ANIMATION_DURATION_HEADS_UP_DISAPPEAR
+import com.android.systemui.statusbar.ui.fakeSystemBarUtilsProxy
+import com.android.systemui.testKosmos
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.mock
 import com.android.systemui.util.mockito.whenever
@@ -46,7 +49,6 @@
 import org.mockito.Mockito.description
 import org.mockito.Mockito.eq
 import org.mockito.Mockito.verify
-import org.mockito.kotlin.doNothing
 
 private const val VIEW_HEIGHT = 100
 private const val FULL_SHADE_APPEAR_TRANSLATION = 300
@@ -60,6 +62,8 @@
     @get:Rule val setFlagsRule = SetFlagsRule()
     @get:Rule val animatorTestRule = AnimatorTestRule(this)
 
+    private val kosmos = testKosmos()
+
     private lateinit var stackStateAnimator: StackStateAnimator
     private lateinit var headsUpAnimator: HeadsUpAnimator
     private val stackScroller: NotificationStackScrollLayout = mock()
@@ -80,13 +84,14 @@
         whenever(view.viewState).thenReturn(viewState)
 
         if (NotificationsHunSharedAnimationValues.isEnabled) {
-            headsUpAnimator = HeadsUpAnimator(context)
+            headsUpAnimator = HeadsUpAnimator(context, kosmos.fakeSystemBarUtilsProxy)
         }
-        stackStateAnimator = StackStateAnimator(
-            mContext,
-            stackScroller,
-            if (::headsUpAnimator.isInitialized) headsUpAnimator else null,
-        )
+        stackStateAnimator =
+            StackStateAnimator(
+                mContext,
+                stackScroller,
+                if (::headsUpAnimator.isInitialized) headsUpAnimator else null,
+            )
     }
 
     @Test
@@ -134,6 +139,62 @@
     }
 
     @Test
+    @EnableFlags(NotificationsHunSharedAnimationValues.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun startAnimationForEvents_headsUpFromTop_andHasStatusBarChipFalse() {
+        val statusBarHeight = 156
+        val topMargin = 50f
+        val expectedStartY = -topMargin - HEADS_UP_ABOVE_SCREEN
+
+        headsUpAnimator.stackTopMargin = topMargin.toInt()
+        kosmos.fakeSystemBarUtilsProxy.fakeStatusBarHeight = statusBarHeight
+        headsUpAnimator.updateResources(context)
+
+        val event = AnimationEvent(view, AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR)
+        event.headsUpHasStatusBarChip = false
+
+        stackStateAnimator.startAnimationForEvents(arrayListOf(event), 0)
+
+        verify(view).setFinalActualHeight(VIEW_HEIGHT)
+        verify(view, description("should animate from the top")).translationY = expectedStartY
+        verify(view)
+            .performAddAnimation(
+                /* delay= */ 0L,
+                /* duration= */ ANIMATION_DURATION_HEADS_UP_APPEAR.toLong(),
+                /* isHeadsUpAppear= */ true,
+                /* isHeadsUpCycling= */ false,
+                /* onEndRunnable= */ null,
+            )
+    }
+
+    @Test
+    @EnableFlags(NotificationsHunSharedAnimationValues.FLAG_NAME, StatusBarNotifChips.FLAG_NAME)
+    fun startAnimationForEvents_headsUpFromTop_andHasStatusBarChipTrue() {
+        val statusBarHeight = 156
+        val topMargin = 50f
+        val expectedStartY = statusBarHeight - topMargin
+
+        headsUpAnimator!!.stackTopMargin = topMargin.toInt()
+        kosmos.fakeSystemBarUtilsProxy.fakeStatusBarHeight = statusBarHeight
+        headsUpAnimator!!.updateResources(context)
+
+        val event = AnimationEvent(view, AnimationEvent.ANIMATION_TYPE_HEADS_UP_APPEAR)
+        event.headsUpHasStatusBarChip = true
+
+        stackStateAnimator.startAnimationForEvents(arrayListOf(event), 0)
+
+        verify(view).setFinalActualHeight(VIEW_HEIGHT)
+        verify(view, description("should animate below status bar")).translationY = expectedStartY
+        verify(view)
+            .performAddAnimation(
+                /* delay= */ 0L,
+                /* duration= */ ANIMATION_DURATION_HEADS_UP_APPEAR.toLong(),
+                /* isHeadsUpAppear= */ true,
+                /* isHeadsUpCycling= */ false,
+                /* onEndRunnable= */ null,
+            )
+    }
+
+    @Test
     @DisableFlags(NotificationsHunSharedAnimationValues.FLAG_NAME)
     fun startAnimationForEvents_headsUpFromBottom_startsHeadsUpAppearAnim_flagOff() {
         val screenHeight = 2000f
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt
similarity index 87%
rename from packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt
rename to packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt
index 31f8590..46430af 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/KeyguardStatusBarViewControllerTest.kt
@@ -70,6 +70,7 @@
 import com.android.systemui.util.settings.SecureSettings
 import com.android.systemui.util.time.FakeSystemClock
 import com.google.common.truth.Truth
+import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.test.TestScope
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
@@ -83,6 +84,7 @@
 import org.mockito.Mock
 import org.mockito.Mockito
 import org.mockito.MockitoAnnotations
+import org.mockito.kotlin.whenever
 
 @SmallTest
 @RunWith(AndroidJUnit4::class)
@@ -155,7 +157,7 @@
         testScope = kosmos.testScope
         shadeViewStateProvider = TestShadeViewStateProvider()
 
-        Mockito.`when`(
+        whenever(
                 kosmos.mockStatusBarContentInsetsProvider
                     .getStatusBarContentInsetsForCurrentRotation()
             )
@@ -163,9 +165,9 @@
 
         MockitoAnnotations.initMocks(this)
 
-        Mockito.`when`(iconManagerFactory.create(ArgumentMatchers.any(), ArgumentMatchers.any()))
+        whenever(iconManagerFactory.create(ArgumentMatchers.any(), ArgumentMatchers.any()))
             .thenReturn(iconManager)
-        Mockito.`when`(statusBarContentInsetsProviderStore.forDisplay(context.displayId))
+        whenever(statusBarContentInsetsProviderStore.forDisplay(context.displayId))
             .thenReturn(kosmos.mockStatusBarContentInsetsProvider)
         allowTestableLooperAsMainThread()
         looper.runWithLooper {
@@ -174,7 +176,7 @@
                     LayoutInflater.from(mContext).inflate(R.layout.keyguard_status_bar, null)
                         as KeyguardStatusBarView
                 )
-            Mockito.`when`(keyguardStatusBarView.getDisplay()).thenReturn(mContext.display)
+            whenever(keyguardStatusBarView.display).thenReturn(mContext.display)
         }
 
         controller = createController()
@@ -404,14 +406,14 @@
     fun updateViewState_alphaAndVisibilityGiven_viewUpdated() {
         // Verify the initial values so we know the method triggers changes.
         Truth.assertThat(keyguardStatusBarView.alpha).isEqualTo(1f)
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
 
         val newAlpha = 0.5f
         val newVisibility = View.INVISIBLE
         controller.updateViewState(newAlpha, newVisibility)
 
         Truth.assertThat(keyguardStatusBarView.alpha).isEqualTo(newAlpha)
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(newVisibility)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(newVisibility)
     }
 
     @Test
@@ -423,7 +425,7 @@
         controller.updateViewState(1f, View.VISIBLE)
 
         // Since we're disabled, we stay invisible
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
     }
 
     @Test
@@ -444,15 +446,15 @@
     fun updateViewState_bypassEnabledAndShouldListenForFace_viewHidden() {
         controller.onViewAttached()
         updateStateToKeyguard()
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
 
-        Mockito.`when`(keyguardUpdateMonitor.shouldListenForFace()).thenReturn(true)
-        Mockito.`when`(keyguardBypassController.bypassEnabled).thenReturn(true)
+        whenever(keyguardUpdateMonitor.shouldListenForFace()).thenReturn(true)
+        whenever(keyguardBypassController.bypassEnabled).thenReturn(true)
         onFinishedGoingToSleep()
 
         controller.updateViewState()
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
     }
 
     @Test
@@ -461,13 +463,13 @@
         controller.onViewAttached()
         updateStateToKeyguard()
 
-        Mockito.`when`(keyguardUpdateMonitor.shouldListenForFace()).thenReturn(true)
-        Mockito.`when`(keyguardBypassController.bypassEnabled).thenReturn(false)
+        whenever(keyguardUpdateMonitor.shouldListenForFace()).thenReturn(true)
+        whenever(keyguardBypassController.bypassEnabled).thenReturn(false)
         onFinishedGoingToSleep()
 
         controller.updateViewState()
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
     }
 
     @Test
@@ -476,13 +478,13 @@
         controller.onViewAttached()
         updateStateToKeyguard()
 
-        Mockito.`when`(keyguardUpdateMonitor.shouldListenForFace()).thenReturn(false)
-        Mockito.`when`(keyguardBypassController.bypassEnabled).thenReturn(true)
+        whenever(keyguardUpdateMonitor.shouldListenForFace()).thenReturn(false)
+        whenever(keyguardBypassController.bypassEnabled).thenReturn(true)
         onFinishedGoingToSleep()
 
         controller.updateViewState()
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
     }
 
     @Test
@@ -495,7 +497,7 @@
 
         controller.updateViewState()
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
     }
 
     @Test
@@ -508,7 +510,7 @@
 
         controller.updateViewState()
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
     }
 
     @Test
@@ -520,7 +522,7 @@
 
         controller.updateViewState()
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
     }
 
     @Test
@@ -532,7 +534,7 @@
 
         controller.updateViewState()
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
     }
 
     @Test
@@ -544,7 +546,7 @@
 
         controller.updateViewState()
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
     }
 
     @Test
@@ -556,7 +558,7 @@
 
         controller.updateViewState()
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
     }
 
     @Test
@@ -568,7 +570,7 @@
 
         controller.setDozing(true)
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
     }
 
     @Test
@@ -580,7 +582,7 @@
 
         controller.setDozing(false)
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
     }
 
     @Test
@@ -595,7 +597,7 @@
 
         controller.updateViewState()
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.GONE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.GONE)
         Truth.assertThat(keyguardStatusBarView.alpha).isEqualTo(0.456f)
     }
 
@@ -611,7 +613,7 @@
 
         controller.updateViewState(0.789f, View.VISIBLE)
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.GONE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.GONE)
         Truth.assertThat(keyguardStatusBarView.alpha).isEqualTo(0.456f)
     }
 
@@ -635,13 +637,13 @@
         controller.init()
         controller.onViewAttached()
         updateStateToKeyguard()
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
 
         controller.setDozing(true)
 
         // setDozing(true) should typically cause the view to hide. But since the flag is on, we
         // should ignore these set dozing calls and stay the same visibility.
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
     }
 
     @Test
@@ -679,7 +681,7 @@
         shadeViewStateProvider.setShouldHeadsUpBeVisible(true)
         controller.updateForHeadsUp(/* animate= */ false)
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
     }
 
     @Test
@@ -695,7 +697,7 @@
         shadeViewStateProvider.setShouldHeadsUpBeVisible(false)
         controller.updateForHeadsUp(/* animate= */ false)
 
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.VISIBLE)
     }
 
     @Test
@@ -728,7 +730,7 @@
         val str = mContext.getString(com.android.internal.R.string.status_bar_volume)
 
         // GIVEN the setting is off
-        Mockito.`when`(secureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0))
+        whenever(secureSettings.getInt(Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON, 0))
             .thenReturn(0)
 
         // WHEN CollapsedStatusBarFragment builds the blocklist
@@ -744,7 +746,7 @@
         val str = mContext.getString(com.android.internal.R.string.status_bar_volume)
 
         // GIVEN the setting is ON
-        Mockito.`when`(
+        whenever(
                 secureSettings.getIntForUser(
                     Settings.Secure.STATUS_BAR_SHOW_VIBRATE_ICON,
                     0,
@@ -779,42 +781,52 @@
         controller.onViewAttached()
         updateStateToKeyguard()
         setDisableSystemInfo(true)
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
 
         controller.animateKeyguardStatusBarIn()
 
         // Since we're disabled, we don't actually animate in and stay invisible
-        Truth.assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
+        assertThat(keyguardStatusBarView.visibility).isEqualTo(View.INVISIBLE)
     }
 
     @Test
     fun animateToGlanceableHub_affectsAlpha() =
         testScope.runTest {
-            controller.init()
-            val transitionAlphaAmount = .5f
-            ViewUtils.attachView(keyguardStatusBarView)
-            looper.processAllMessages()
-            updateStateToKeyguard()
-            kosmos.fakeCommunalSceneRepository.snapToScene(CommunalScenes.Communal)
-            runCurrent()
-            controller.updateCommunalAlphaTransition(transitionAlphaAmount)
-            Truth.assertThat(keyguardStatusBarView.getAlpha()).isEqualTo(transitionAlphaAmount)
+            try {
+                controller.init()
+                val transitionAlphaAmount = .5f
+                ViewUtils.attachView(keyguardStatusBarView)
+
+                looper.processAllMessages()
+                updateStateToKeyguard()
+                kosmos.fakeCommunalSceneRepository.snapToScene(CommunalScenes.Communal)
+                runCurrent()
+                controller.updateCommunalAlphaTransition(transitionAlphaAmount)
+                assertThat(keyguardStatusBarView.getAlpha()).isEqualTo(transitionAlphaAmount)
+            } finally {
+                ViewUtils.detachView(keyguardStatusBarView)
+            }
         }
 
     @Test
     fun animateToGlanceableHub_alphaResetOnCommunalNotShowing() =
         testScope.runTest {
-            controller.init()
-            val transitionAlphaAmount = .5f
-            ViewUtils.attachView(keyguardStatusBarView)
-            looper.processAllMessages()
-            updateStateToKeyguard()
-            kosmos.fakeCommunalSceneRepository.snapToScene(CommunalScenes.Communal)
-            runCurrent()
-            controller.updateCommunalAlphaTransition(transitionAlphaAmount)
-            kosmos.fakeCommunalSceneRepository.snapToScene(CommunalScenes.Blank)
-            runCurrent()
-            Truth.assertThat(keyguardStatusBarView.getAlpha()).isNotEqualTo(transitionAlphaAmount)
+            try {
+                controller.init()
+                val transitionAlphaAmount = .5f
+                ViewUtils.attachView(keyguardStatusBarView)
+
+                looper.processAllMessages()
+                updateStateToKeyguard()
+                kosmos.fakeCommunalSceneRepository.snapToScene(CommunalScenes.Communal)
+                runCurrent()
+                controller.updateCommunalAlphaTransition(transitionAlphaAmount)
+                kosmos.fakeCommunalSceneRepository.snapToScene(CommunalScenes.Blank)
+                runCurrent()
+                assertThat(keyguardStatusBarView.getAlpha()).isNotEqualTo(transitionAlphaAmount)
+            } finally {
+                ViewUtils.detachView(keyguardStatusBarView)
+            }
         }
 
     /**
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
index d163726..b9d9a53 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/MultiDisplayAutoHideControllerStoreTest.kt
@@ -62,11 +62,11 @@
         }
 
     @Test
-    fun displayRemoved_stopsInstance() =
+    fun systemDecorationRemovedEvent_stopsInstance() =
         testScope.runTest {
             val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
-            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+            fakeDisplayRepository.triggerRemoveSystemDecorationEvent(DEFAULT_DISPLAY)
 
             verify(instance).stop()
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt
index 47967b3..670c195 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarNotificationPresenterTest.kt
@@ -43,6 +43,7 @@
 import com.android.systemui.statusbar.StatusBarState
 import com.android.systemui.statusbar.commandQueue
 import com.android.systemui.statusbar.lockscreenShadeTransitionController
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
 import com.android.systemui.statusbar.notification.domain.interactor.notificationAlertsInteractor
@@ -54,6 +55,7 @@
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionRefactor
 import com.android.systemui.statusbar.notification.interruption.VisualInterruptionType
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.entryAdapterFactory
 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi
 import com.android.systemui.statusbar.notification.stack.notificationStackScrollLayoutController
 import com.android.systemui.statusbar.notification.visualInterruptionDecisionProvider
@@ -105,10 +107,14 @@
     private val notificationAlertsInteractor = kosmos.notificationAlertsInteractor
     private val visualInterruptionDecisionProvider = kosmos.visualInterruptionDecisionProvider
 
+    private lateinit var factory: EntryAdapterFactoryImpl
+
     private lateinit var underTest: StatusBarNotificationPresenter
 
     @Before
     fun setup() {
+        factory = kosmos.entryAdapterFactory
+
         underTest = createPresenter()
         if (VisualInterruptionRefactor.isEnabled) {
             verifyAndCaptureSuppressors()
@@ -451,7 +457,7 @@
     private fun createRow(entry: NotificationEntry): ExpandableNotificationRow {
         val row: ExpandableNotificationRow = mock()
         if (NotificationBundleUi.isEnabled) {
-            whenever(row.entryAdapter).thenReturn(entry.entryAdapter)
+            whenever(row.entryAdapter).thenReturn(factory.create(entry))
         } else {
             whenever(row.entry).thenReturn(entry)
         }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
index 345ddae..c23e0e7 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/StatusBarRemoteInputCallbackTest.java
@@ -46,7 +46,7 @@
 import com.android.systemui.statusbar.NotificationLockscreenUserManager;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry.NotifEntryAdapter;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryAdapter;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.NotificationContentView;
@@ -135,7 +135,7 @@
         final ExpandableNotificationRow enr = mock(ExpandableNotificationRow.class);
         final NotificationContentView privateLayout = mock(NotificationContentView.class);
         final NotificationEntry enrEntry = mock(NotificationEntry.class);
-        final NotifEntryAdapter enrEntryAdapter = mock(NotifEntryAdapter.class);
+        final NotificationEntryAdapter enrEntryAdapter = mock(NotificationEntryAdapter.class);
 
         when(enr.getPrivateLayout()).thenReturn(privateLayout);
         when(enr.getEntry()).thenReturn(enrEntry);
@@ -178,7 +178,7 @@
 
         // THEN
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
         verify(enr).setUserExpanded(true);
         verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
     }
@@ -203,7 +203,7 @@
 
         // THEN
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
         verify(enr).setUserExpanded(true);
         verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
     }
@@ -217,7 +217,7 @@
         final ExpandableNotificationRow enr = mock(ExpandableNotificationRow.class);
         final NotificationContentView privateLayout = mock(NotificationContentView.class);
         final NotificationEntry enrEntry = mock(NotificationEntry.class);
-        final NotifEntryAdapter enrEntryAdapter = mock(NotifEntryAdapter.class);
+        final NotificationEntryAdapter enrEntryAdapter = mock(NotificationEntryAdapter.class);
 
         when(enr.getPrivateLayout()).thenReturn(privateLayout);
         when(enr.getEntry()).thenReturn(enrEntry);
@@ -260,7 +260,7 @@
 
         // THEN
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(enrEntry);
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
         verify(enr, never()).setUserExpanded(anyBoolean());
         verify(privateLayout, never()).setOnExpandedVisibleListener(any());
     }
@@ -290,7 +290,7 @@
         verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
         verify(enr, never()).setUserExpanded(anyBoolean());
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
     }
 
     @Test
@@ -318,7 +318,7 @@
         verify(privateLayout, never()).setOnExpandedVisibleListener(onExpandedVisibleRunner);
         verify(enr, never()).setUserExpanded(anyBoolean());
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
     }
 
     @Test
@@ -346,7 +346,7 @@
         verify(privateLayout).setOnExpandedVisibleListener(onExpandedVisibleRunner);
         verify(enr, never()).setUserExpanded(anyBoolean());
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
     }
 
     @Test
@@ -374,6 +374,6 @@
         verify(privateLayout, never()).setOnExpandedVisibleListener(onExpandedVisibleRunner);
         verify(enr, never()).setUserExpanded(anyBoolean());
         verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntry.class));
-        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotifEntryAdapter.class));
+        verify(mGroupExpansionManager, never()).toggleGroupExpansion(any(NotificationEntryAdapter.class));
     }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
index 58856d9..ffde34e 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/phone/SystemUIDialogTest.java
@@ -48,7 +48,6 @@
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.kosmos.KosmosJavaAdapter;
 import com.android.systemui.model.SysUiState;
-import com.android.systemui.settings.FakeDisplayTracker;
 
 import org.junit.Before;
 import org.junit.Rule;
@@ -84,8 +83,7 @@
     public void setup() {
         MockitoAnnotations.initMocks(this);
         KosmosJavaAdapter kosmos = new KosmosJavaAdapter(this);
-        FakeDisplayTracker displayTracker = new FakeDisplayTracker(mContext);
-        mSysUiState = new SysUiState(displayTracker, kosmos.getSceneContainerPlugin());
+        mSysUiState = kosmos.getSysuiState();
         mDependency.injectTestDependency(BroadcastDispatcher.class, mBroadcastDispatcher);
         when(mDelegate.getBackAnimationSpec(ArgumentMatchers.any()))
                 .thenReturn(mock(BackAnimationSpec.class));
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairosTest.kt
new file mode 100644
index 0000000..80f4b2c
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairosTest.kt
@@ -0,0 +1,173 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.demoModeController
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosTestScope
+import com.android.systemui.kairos.runKairosTest
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.validMobileEvent
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
+
+/**
+ * The switcher acts as a dispatcher to either the `prod` or `demo` versions of the repository
+ * interface it's switching on. These tests just need to verify that the entire interface properly
+ * switches over when the value of `demoMode` changes
+ */
+@OptIn(ExperimentalKairosApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MobileRepositorySwitcherKairosTest : SysuiTestCase() {
+    private val kosmos =
+        testKosmos().apply {
+            useUnconfinedTestDispatcher()
+            demoModeController.stub {
+                // Never start in demo mode
+                on { isInDemoMode } doReturn false
+            }
+            wifiDataSource.stub { on { wifiEvents } doReturn MutableStateFlow(null) }
+        }
+
+    private val Kosmos.underTest
+        get() = mobileRepositorySwitcherKairos
+
+    private val Kosmos.realRepo
+        get() = mobileConnectionsRepositoryKairosImpl
+
+    private fun runTest(block: suspend KairosTestScope.() -> Unit) =
+        kosmos.run { runKairosTest { block() } }
+
+    @Test
+    fun activeRepoMatchesDemoModeSetting() = runTest {
+        demoModeController.stub { on { isInDemoMode } doReturn false }
+
+        val latest by underTest.activeRepo.collectLastValue()
+
+        assertThat(latest).isEqualTo(realRepo)
+
+        startDemoMode()
+
+        assertThat(latest).isInstanceOf(DemoMobileConnectionsRepositoryKairos::class.java)
+
+        finishDemoMode()
+
+        assertThat(latest).isEqualTo(realRepo)
+    }
+
+    @Test
+    fun subscriptionListUpdatesWhenDemoModeChanges() = runTest {
+        demoModeController.stub { on { isInDemoMode } doReturn false }
+
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_1, SUB_2)
+        }
+
+        val latest by underTest.subscriptions.collectLastValue()
+
+        // The real subscriptions has 2 subs
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2))
+
+        // Demo mode turns on, and we should see only the demo subscriptions
+        startDemoMode()
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(validMobileEvent(subId = 3))
+
+        // Demo mobile connections repository makes arbitrarily-formed subscription info
+        // objects, so just validate the data we care about
+        assertThat(latest).hasSize(1)
+        assertThat(latest!!.first().subscriptionId).isEqualTo(3)
+
+        finishDemoMode()
+
+        assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2))
+    }
+
+    private fun KairosTestScope.startDemoMode() {
+        demoModeController.stub { on { isInDemoMode } doReturn true }
+        getDemoModeCallback().onDemoModeStarted()
+    }
+
+    private fun KairosTestScope.finishDemoMode() {
+        demoModeController.stub { on { isInDemoMode } doReturn false }
+        getDemoModeCallback().onDemoModeFinished()
+    }
+
+    private fun KairosTestScope.getSubscriptionCallback():
+        SubscriptionManager.OnSubscriptionsChangedListener =
+        argumentCaptor<SubscriptionManager.OnSubscriptionsChangedListener>()
+            .apply {
+                verify(subscriptionManager).addOnSubscriptionsChangedListener(any(), capture())
+            }
+            .lastValue
+
+    private fun KairosTestScope.getDemoModeCallback(): DemoMode =
+        argumentCaptor<DemoMode>()
+            .apply { verify(demoModeController).addCallback(capture()) }
+            .lastValue
+
+    companion object {
+        private const val SUB_1_ID = 1
+        private const val SUB_1_NAME = "Carrier $SUB_1_ID"
+        private val SUB_1: SubscriptionInfo = mock {
+            on { subscriptionId } doReturn SUB_1_ID
+            on { carrierName } doReturn SUB_1_NAME
+            on { profileClass } doReturn PROFILE_CLASS_UNSET
+        }
+        private val MODEL_1 =
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                carrierName = SUB_1_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        private const val SUB_2_ID = 2
+        private const val SUB_2_NAME = "Carrier $SUB_2_ID"
+        private val SUB_2: SubscriptionInfo = mock {
+            on { subscriptionId } doReturn SUB_2_ID
+            on { carrierName } doReturn SUB_2_NAME
+            on { profileClass } doReturn PROFILE_CLASS_UNSET
+        }
+        private val MODEL_2 =
+            SubscriptionModel(
+                subscriptionId = SUB_2_ID,
+                carrierName = SUB_2_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionKairosParameterizedTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionKairosParameterizedTest.kt
new file mode 100644
index 0000000..99cc93d
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionKairosParameterizedTest.kt
@@ -0,0 +1,285 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
+
+import android.telephony.Annotation
+import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
+import androidx.test.filters.SmallTest
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosTestScope
+import com.android.systemui.kairos.kairos
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.runKairosTest
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demoMobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demoModeMobileConnectionDataSourceKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.wifiDataSource
+import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.MutableStateFlow
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.stub
+import platform.test.runner.parameterized.ParameterizedAndroidJunit4
+import platform.test.runner.parameterized.Parameters
+
+/**
+ * Parameterized test for all of the common values of [FakeNetworkEventModel]. This test simply
+ * verifies that passing the given model to [DemoMobileConnectionsRepositoryKairos] results in the
+ * correct flows emitting from the given connection.
+ */
+@OptIn(ExperimentalKairosApi::class)
+@SmallTest
+@RunWith(ParameterizedAndroidJunit4::class)
+internal class DemoMobileConnectionKairosParameterizedTest(private val testCase: TestCase) :
+    SysuiTestCase() {
+
+    private val Kosmos.fakeWifiEventFlow by Fixture { MutableStateFlow<FakeWifiEventModel?>(null) }
+
+    private val kosmos =
+        testKosmos().apply {
+            useUnconfinedTestDispatcher()
+            wifiDataSource.stub { on { wifiEvents } doReturn fakeWifiEventFlow }
+        }
+
+    private fun runTest(block: suspend KairosTestScope.() -> Unit) =
+        kosmos.run { runKairosTest { block() } }
+
+    @Test
+    fun demoNetworkData() = runTest {
+        val underTest by
+            demoMobileConnectionsRepositoryKairos.mobileConnectionsBySubId
+                .map { it[subId] }
+                .collectLastValue()
+        val networkModel =
+            FakeNetworkEventModel.Mobile(
+                level = testCase.level,
+                dataType = testCase.dataType,
+                subId = testCase.subId,
+                carrierId = testCase.carrierId,
+                inflateStrength = testCase.inflateStrength,
+                activity = testCase.activity,
+                carrierNetworkChange = testCase.carrierNetworkChange,
+                roaming = testCase.roaming,
+                name = "demo name",
+                slice = testCase.slice,
+            )
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(networkModel)
+        assertConnection(underTest!!, networkModel)
+    }
+
+    private suspend fun KairosTestScope.assertConnection(
+        conn: DemoMobileConnectionRepositoryKairos,
+        model: FakeNetworkEventModel,
+    ) {
+        when (model) {
+            is FakeNetworkEventModel.Mobile -> {
+                kairos.transact {
+                    assertThat(conn.subId).isEqualTo(model.subId)
+                    assertThat(conn.cdmaLevel.sample()).isEqualTo(model.level)
+                    assertThat(conn.primaryLevel.sample()).isEqualTo(model.level)
+                    assertThat(conn.dataActivityDirection.sample())
+                        .isEqualTo(
+                            (model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel()
+                        )
+                    assertThat(conn.carrierNetworkChangeActive.sample())
+                        .isEqualTo(model.carrierNetworkChange)
+                    assertThat(conn.isRoaming.sample()).isEqualTo(model.roaming)
+                    assertThat(conn.networkName.sample())
+                        .isEqualTo(NetworkNameModel.IntentDerived(model.name))
+                    assertThat(conn.carrierName.sample())
+                        .isEqualTo(
+                            NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}")
+                        )
+                    assertThat(conn.hasPrioritizedNetworkCapabilities.sample())
+                        .isEqualTo(model.slice)
+                    assertThat(conn.isNonTerrestrial.sample()).isEqualTo(model.ntn)
+
+                    // TODO(b/261029387): check these once we start handling them
+                    assertThat(conn.isEmergencyOnly.sample()).isFalse()
+                    assertThat(conn.isGsm.sample()).isFalse()
+                    assertThat(conn.dataConnectionState.sample())
+                        .isEqualTo(DataConnectionState.Connected)
+                }
+            }
+            // MobileDisabled isn't combinatorial in nature, and is tested in
+            // DemoMobileConnectionsRepositoryTest.kt
+            else -> {}
+        }
+    }
+
+    /** Matches [FakeNetworkEventModel] */
+    internal data class TestCase(
+        val level: Int,
+        val dataType: SignalIcon.MobileIconGroup,
+        val subId: Int,
+        val carrierId: Int,
+        val inflateStrength: Boolean,
+        @Annotation.DataActivityType val activity: Int,
+        val carrierNetworkChange: Boolean,
+        val roaming: Boolean,
+        val name: String,
+        val slice: Boolean,
+        val ntn: Boolean,
+    ) {
+        override fun toString(): String {
+            return "INPUT(level=$level, " +
+                "dataType=${dataType.name}, " +
+                "subId=$subId, " +
+                "carrierId=$carrierId, " +
+                "inflateStrength=$inflateStrength, " +
+                "activity=$activity, " +
+                "carrierNetworkChange=$carrierNetworkChange, " +
+                "roaming=$roaming, " +
+                "name=$name," +
+                "slice=$slice" +
+                "ntn=$ntn)"
+        }
+
+        // Convenience for iterating test data and creating new cases
+        fun modifiedBy(
+            level: Int? = null,
+            dataType: SignalIcon.MobileIconGroup? = null,
+            subId: Int? = null,
+            carrierId: Int? = null,
+            inflateStrength: Boolean? = null,
+            @Annotation.DataActivityType activity: Int? = null,
+            carrierNetworkChange: Boolean? = null,
+            roaming: Boolean? = null,
+            name: String? = null,
+            slice: Boolean? = null,
+            ntn: Boolean? = null,
+        ): TestCase =
+            TestCase(
+                level = level ?: this.level,
+                dataType = dataType ?: this.dataType,
+                subId = subId ?: this.subId,
+                carrierId = carrierId ?: this.carrierId,
+                inflateStrength = inflateStrength ?: this.inflateStrength,
+                activity = activity ?: this.activity,
+                carrierNetworkChange = carrierNetworkChange ?: this.carrierNetworkChange,
+                roaming = roaming ?: this.roaming,
+                name = name ?: this.name,
+                slice = slice ?: this.slice,
+                ntn = ntn ?: this.ntn,
+            )
+    }
+
+    companion object {
+        private val subId = 1
+
+        private val booleanList = listOf(true, false)
+        private val levels = listOf(0, 1, 2, 3)
+        private val dataTypes =
+            listOf(
+                TelephonyIcons.THREE_G,
+                TelephonyIcons.LTE,
+                TelephonyIcons.FOUR_G,
+                TelephonyIcons.NR_5G,
+                TelephonyIcons.NR_5G_PLUS,
+            )
+        private val carrierIds = listOf(1, 10, 100)
+        private val inflateStrength = booleanList
+        private val activity =
+            listOf(
+                TelephonyManager.DATA_ACTIVITY_NONE,
+                TelephonyManager.DATA_ACTIVITY_IN,
+                TelephonyManager.DATA_ACTIVITY_OUT,
+                TelephonyManager.DATA_ACTIVITY_INOUT,
+            )
+        private val carrierNetworkChange = booleanList
+        // false first so the base case doesn't have roaming set (more common)
+        private val roaming = listOf(false, true)
+        private val names = listOf("name 1", "name 2")
+        private val slice = listOf(false, true)
+        private val ntn = listOf(false, true)
+
+        @Parameters(name = "{0}") @JvmStatic fun data() = testData()
+
+        /**
+         * Generate some test data. For the sake of convenience, we'll parameterize only non-null
+         * network event data. So given the lists of test data:
+         * ```
+         *    list1 = [1, 2, 3]
+         *    list2 = [false, true]
+         *    list3 = [a, b, c]
+         * ```
+         *
+         * We'll generate test cases for:
+         *
+         * Test (1, false, a) Test (2, false, a) Test (3, false, a) Test (1, true, a) Test (1,
+         * false, b) Test (1, false, c)
+         *
+         * NOTE: this is not a combinatorial product of all of the possible sets of parameters.
+         * Since this test is built to exercise demo mode, the general approach is to define a
+         * fully-formed "base case", and from there to make sure to use every valid parameter once,
+         * by defining the rest of the test cases against the base case. Specific use-cases can be
+         * added to the non-parameterized test, or manually below the generated test cases.
+         */
+        private fun testData(): List<TestCase> {
+            val testSet = mutableSetOf<TestCase>()
+
+            val baseCase =
+                TestCase(
+                    levels.first(),
+                    dataTypes.first(),
+                    subId,
+                    carrierIds.first(),
+                    inflateStrength.first(),
+                    activity.first(),
+                    carrierNetworkChange.first(),
+                    roaming.first(),
+                    names.first(),
+                    slice.first(),
+                    ntn.first(),
+                )
+
+            val tail =
+                sequenceOf(
+                        levels.map { baseCase.modifiedBy(level = it) },
+                        dataTypes.map { baseCase.modifiedBy(dataType = it) },
+                        carrierIds.map { baseCase.modifiedBy(carrierId = it) },
+                        inflateStrength.map { baseCase.modifiedBy(inflateStrength = it) },
+                        activity.map { baseCase.modifiedBy(activity = it) },
+                        carrierNetworkChange.map { baseCase.modifiedBy(carrierNetworkChange = it) },
+                        roaming.map { baseCase.modifiedBy(roaming = it) },
+                        names.map { baseCase.modifiedBy(name = it) },
+                        slice.map { baseCase.modifiedBy(slice = it) },
+                        ntn.map { baseCase.modifiedBy(ntn = it) },
+                    )
+                    .flatten()
+
+            testSet.add(baseCase)
+            tail.toCollection(testSet)
+
+            return testSet.toList()
+        }
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryKairosTest.kt
new file mode 100644
index 0000000..503d561
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryKairosTest.kt
@@ -0,0 +1,465 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
+
+import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
+import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosTestScope
+import com.android.systemui.kairos.kairos
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.runKairosTest
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demoMobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demoModeMobileConnectionDataSourceKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.wifiDataSource
+import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import junit.framework.Assert
+import kotlinx.coroutines.flow.MutableStateFlow
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.stub
+
+@OptIn(ExperimentalKairosApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class DemoMobileConnectionsRepositoryKairosTest : SysuiTestCase() {
+
+    private val Kosmos.fakeWifiEventFlow by
+        Kosmos.Fixture { MutableStateFlow<FakeWifiEventModel?>(null) }
+
+    private val Kosmos.underTest
+        get() = demoMobileConnectionsRepositoryKairos
+
+    private val kosmos =
+        testKosmos().apply {
+            useUnconfinedTestDispatcher()
+            wifiDataSource.stub { on { wifiEvents } doReturn fakeWifiEventFlow }
+        }
+
+    private fun runTest(block: suspend KairosTestScope.() -> Unit) =
+        kosmos.run { runKairosTest { block() } }
+
+    @Test
+    fun isDefault_defaultsToTrue() = runTest {
+        underTest
+        val isDefault = kairos.transact { underTest.mobileIsDefault.sample() }
+        assertThat(isDefault).isTrue()
+    }
+
+    @Test
+    fun validated_defaultsToTrue() = runTest {
+        underTest
+        val isValidated = kairos.transact { underTest.defaultConnectionIsValidated.sample() }
+        assertThat(isValidated).isTrue()
+    }
+
+    @Test
+    fun networkEvent_createNewSubscription() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        assertThat(latest).isEmpty()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(validMobileEvent(subId = 1))
+
+        assertThat(latest).hasSize(1)
+        assertThat(latest!!.first().subscriptionId).isEqualTo(1)
+    }
+
+    @Test
+    fun wifiCarrierMergedEvent_createNewSubscription() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        assertThat(latest).isEmpty()
+
+        fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5)
+
+        assertThat(latest).hasSize(1)
+        assertThat(latest!!.first().subscriptionId).isEqualTo(5)
+    }
+
+    @Test
+    fun networkEvent_reusesSubscriptionWhenSameId() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        assertThat(latest).isEmpty()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(
+            validMobileEvent(subId = 1, level = 1)
+        )
+
+        assertThat(latest).hasSize(1)
+        assertThat(latest!!.first().subscriptionId).isEqualTo(1)
+
+        // Second network event comes in with the same subId, does not create a new subscription
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(
+            validMobileEvent(subId = 1, level = 2)
+        )
+
+        assertThat(latest).hasSize(1)
+        assertThat(latest!!.first().subscriptionId).isEqualTo(1)
+    }
+
+    @Test
+    fun wifiCarrierMergedEvent_reusesSubscriptionWhenSameId() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        assertThat(latest).isEmpty()
+
+        fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5, level = 1)
+
+        assertThat(latest).hasSize(1)
+        assertThat(latest!!.first().subscriptionId).isEqualTo(5)
+
+        // Second network event comes in with the same subId, does not create a new subscription
+        fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5, level = 2)
+
+        assertThat(latest).hasSize(1)
+        assertThat(latest!!.first().subscriptionId).isEqualTo(5)
+    }
+
+    @Test
+    fun multipleSubscriptions() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(validMobileEvent(subId = 1))
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(validMobileEvent(subId = 2))
+
+        assertThat(latest).hasSize(2)
+    }
+
+    @Test
+    fun mobileSubscriptionAndCarrierMergedSubscription() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(validMobileEvent(subId = 1))
+        fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 5)
+
+        assertThat(latest).hasSize(2)
+    }
+
+    @Test
+    fun multipleMobileSubscriptionsAndCarrierMergedSubscription() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(validMobileEvent(subId = 1))
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(validMobileEvent(subId = 2))
+        fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 3)
+
+        assertThat(latest).hasSize(3)
+    }
+
+    @Test
+    fun mobileDisabledEvent_disablesConnection_subIdSpecified_singleConn() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(
+            validMobileEvent(subId = 1, level = 1)
+        )
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(MobileDisabled(subId = 1))
+
+        assertThat(latest).hasSize(0)
+    }
+
+    @Test
+    fun mobileDisabledEvent_disablesConnection_subIdNotSpecified_singleConn() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(
+            validMobileEvent(subId = 1, level = 1)
+        )
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(
+            MobileDisabled(subId = null)
+        )
+
+        assertThat(latest).hasSize(0)
+    }
+
+    @Test
+    fun mobileDisabledEvent_disablesConnection_subIdSpecified_multipleConn() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(
+            validMobileEvent(subId = 1, level = 1)
+        )
+
+        assertThat(latest).hasSize(1)
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(
+            validMobileEvent(subId = 2, level = 1)
+        )
+
+        assertThat(latest).hasSize(2)
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(MobileDisabled(subId = 2))
+
+        assertThat(latest).hasSize(1)
+    }
+
+    @Test
+    fun mobileDisabledEvent_subIdNotSpecified_multipleConn_ignoresCommand() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(
+            validMobileEvent(subId = 1, level = 1)
+        )
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(
+            validMobileEvent(subId = 2, level = 1)
+        )
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(
+            MobileDisabled(subId = null)
+        )
+
+        assertThat(latest).hasSize(2)
+    }
+
+    @Test
+    fun wifiNetworkUpdatesToDisabled_carrierMergedConnectionRemoved() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 1)
+
+        assertThat(latest).hasSize(1)
+
+        fakeWifiEventFlow.value = FakeWifiEventModel.WifiDisabled
+
+        assertThat(latest).isEmpty()
+    }
+
+    @Test
+    fun wifiNetworkUpdatesToActive_carrierMergedConnectionRemoved() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        fakeWifiEventFlow.value = validCarrierMergedEvent(subId = 1)
+
+        assertThat(latest).hasSize(1)
+
+        fakeWifiEventFlow.value =
+            FakeWifiEventModel.Wifi(level = 1, activity = 0, ssid = null, validated = true)
+
+        assertThat(latest).isEmpty()
+    }
+
+    @Test
+    fun mobileSubUpdatesToCarrierMerged_onlyOneConnection() = runTest {
+        val latestSubsList by underTest.subscriptions.collectLastValue()
+        val connections by underTest.mobileConnectionsBySubId.map { it.values }.collectLastValue()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(
+            validMobileEvent(subId = 3, level = 2)
+        )
+        assertThat(latestSubsList).hasSize(1)
+
+        val carrierMergedEvent = validCarrierMergedEvent(subId = 3, level = 1)
+        fakeWifiEventFlow.value = carrierMergedEvent
+        assertThat(latestSubsList).hasSize(1)
+        val connection = connections!!.find { it.subId == 3 }!!
+        assertCarrierMergedConnection(connection, carrierMergedEvent)
+    }
+
+    @Test
+    fun mobileSubUpdatesToCarrierMergedThenBack_hasOldMobileData() = runTest {
+        val latestSubsList by underTest.subscriptions.collectLastValue()
+        val connections by underTest.mobileConnectionsBySubId.map { it.values }.collectLastValue()
+
+        val mobileEvent = validMobileEvent(subId = 3, level = 2)
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(mobileEvent)
+        assertThat(latestSubsList).hasSize(1)
+
+        val carrierMergedEvent = validCarrierMergedEvent(subId = 3, level = 1)
+        fakeWifiEventFlow.value = carrierMergedEvent
+        assertThat(latestSubsList).hasSize(1)
+        var connection = connections!!.find { it.subId == 3 }!!
+        assertCarrierMergedConnection(connection, carrierMergedEvent)
+
+        // WHEN the carrier merged is removed
+        fakeWifiEventFlow.value =
+            FakeWifiEventModel.Wifi(level = 4, activity = 0, ssid = null, validated = true)
+
+        assertThat(latestSubsList).hasSize(1)
+        assertThat(connections).hasSize(1)
+
+        // THEN the subId=3 connection goes back to the mobile information
+        connection = connections!!.find { it.subId == 3 }!!
+        assertConnection(connection, mobileEvent)
+    }
+
+    @Test
+    fun demoConnection_singleSubscription() = runTest {
+        var currentEvent: FakeNetworkEventModel = validMobileEvent(subId = 1)
+        val connections by underTest.mobileConnectionsBySubId.map { it.values }.collectLastValue()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(currentEvent)
+
+        assertThat(connections).hasSize(1)
+        val connection1 = connections!!.first()
+
+        assertConnection(connection1, currentEvent)
+
+        // Exercise the whole api
+
+        currentEvent = validMobileEvent(subId = 1, level = 2)
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(currentEvent)
+        assertConnection(connection1, currentEvent)
+    }
+
+    @Test
+    fun demoConnection_twoConnections_updateSecond_noAffectOnFirst() = runTest {
+        var currentEvent1 = validMobileEvent(subId = 1)
+        var connection1: DemoMobileConnectionRepositoryKairos? = null
+        var currentEvent2 = validMobileEvent(subId = 2)
+        var connection2: DemoMobileConnectionRepositoryKairos? = null
+        val connections by underTest.mobileConnectionsBySubId.map { it.values }.collectLastValue()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(currentEvent1)
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(currentEvent2)
+        assertThat(connections).hasSize(2)
+        connections!!.forEach {
+            when (it.subId) {
+                1 -> connection1 = it
+                2 -> connection2 = it
+                else -> Assert.fail("Unexpected subscription")
+            }
+        }
+
+        assertConnection(connection1!!, currentEvent1)
+        assertConnection(connection2!!, currentEvent2)
+
+        // WHEN the event changes for connection 2, it updates, and connection 1 stays the same
+        currentEvent2 = validMobileEvent(subId = 2, activity = DATA_ACTIVITY_INOUT)
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(currentEvent2)
+        assertConnection(connection1!!, currentEvent1)
+        assertConnection(connection2!!, currentEvent2)
+
+        // and vice versa
+        currentEvent1 = validMobileEvent(subId = 1, inflateStrength = true)
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(currentEvent1)
+        assertConnection(connection1!!, currentEvent1)
+        assertConnection(connection2!!, currentEvent2)
+    }
+
+    @Test
+    fun demoConnection_twoConnections_updateCarrierMerged_noAffectOnFirst() = runTest {
+        var currentEvent1 = validMobileEvent(subId = 1)
+        var connection1: DemoMobileConnectionRepositoryKairos? = null
+        var currentEvent2 = validCarrierMergedEvent(subId = 2)
+        var connection2: DemoMobileConnectionRepositoryKairos? = null
+        val connections by underTest.mobileConnectionsBySubId.map { it.values }.collectLastValue()
+
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(currentEvent1)
+        fakeWifiEventFlow.value = currentEvent2
+        assertThat(connections).hasSize(2)
+        connections!!.forEach {
+            when (it.subId) {
+                1 -> connection1 = it
+                2 -> connection2 = it
+                else -> Assert.fail("Unexpected subscription")
+            }
+        }
+
+        assertConnection(connection1!!, currentEvent1)
+        assertCarrierMergedConnection(connection2!!, currentEvent2)
+
+        // WHEN the event changes for connection 2, it updates, and connection 1 stays the same
+        currentEvent2 = validCarrierMergedEvent(subId = 2, level = 4)
+        fakeWifiEventFlow.value = currentEvent2
+        assertConnection(connection1!!, currentEvent1)
+        assertCarrierMergedConnection(connection2!!, currentEvent2)
+
+        // and vice versa
+        currentEvent1 = validMobileEvent(subId = 1, inflateStrength = true)
+        demoModeMobileConnectionDataSourceKairos.fake.mobileEvents.emit(currentEvent1)
+        assertConnection(connection1!!, currentEvent1)
+        assertCarrierMergedConnection(connection2!!, currentEvent2)
+    }
+
+    @Test
+    fun demoIsNotInEcmState() = runTest {
+        underTest
+        assertThat(kairos.transact { underTest.isInEcmMode.sample() }).isFalse()
+    }
+
+    private suspend fun KairosTestScope.assertConnection(
+        conn: DemoMobileConnectionRepositoryKairos,
+        model: FakeNetworkEventModel,
+    ) {
+        when (model) {
+            is FakeNetworkEventModel.Mobile -> {
+                kairos.transact {
+                    assertThat(conn.subId).isEqualTo(model.subId)
+                    assertThat(conn.cdmaLevel.sample()).isEqualTo(model.level)
+                    assertThat(conn.primaryLevel.sample()).isEqualTo(model.level)
+                    assertThat(conn.dataActivityDirection.sample())
+                        .isEqualTo(
+                            (model.activity ?: DATA_ACTIVITY_NONE).toMobileDataActivityModel()
+                        )
+                    assertThat(conn.carrierNetworkChangeActive.sample())
+                        .isEqualTo(model.carrierNetworkChange)
+                    assertThat(conn.isRoaming.sample()).isEqualTo(model.roaming)
+                    assertThat(conn.networkName.sample())
+                        .isEqualTo(NetworkNameModel.IntentDerived(model.name))
+                    assertThat(conn.carrierName.sample())
+                        .isEqualTo(
+                            NetworkNameModel.SubscriptionDerived("${model.name} ${model.subId}")
+                        )
+                    assertThat(conn.hasPrioritizedNetworkCapabilities.sample())
+                        .isEqualTo(model.slice)
+                    assertThat(conn.isNonTerrestrial.sample()).isEqualTo(model.ntn)
+
+                    // TODO(b/261029387) check these once we start handling them
+                    assertThat(conn.isEmergencyOnly.sample()).isFalse()
+                    assertThat(conn.isGsm.sample()).isFalse()
+                    assertThat(conn.dataConnectionState.sample())
+                        .isEqualTo(DataConnectionState.Connected)
+                }
+            }
+            else -> {}
+        }
+    }
+
+    private suspend fun KairosTestScope.assertCarrierMergedConnection(
+        conn: DemoMobileConnectionRepositoryKairos,
+        model: FakeWifiEventModel.CarrierMerged,
+    ) {
+        kairos.transact {
+            assertThat(conn.subId).isEqualTo(model.subscriptionId)
+            assertThat(conn.cdmaLevel.sample()).isEqualTo(model.level)
+            assertThat(conn.primaryLevel.sample()).isEqualTo(model.level)
+            assertThat(conn.carrierNetworkChangeActive.sample()).isEqualTo(false)
+            assertThat(conn.isRoaming.sample()).isEqualTo(false)
+            assertThat(conn.isEmergencyOnly.sample()).isFalse()
+            assertThat(conn.isGsm.sample()).isFalse()
+            assertThat(conn.dataConnectionState.sample()).isEqualTo(DataConnectionState.Connected)
+            assertThat(conn.hasPrioritizedNetworkCapabilities.sample()).isFalse()
+        }
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairosTest.kt
new file mode 100644
index 0000000..1838d13
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairosTest.kt
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import android.telephony.TelephonyManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.kairos.ActivatedKairosFixture
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosTestScope
+import com.android.systemui.kairos.runKairosTest
+import com.android.systemui.kairos.stateOf
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.fakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.wifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
+
+@OptIn(ExperimentalKairosApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CarrierMergedConnectionRepositoryKairosTest : SysuiTestCase() {
+
+    private val Kosmos.underTest by ActivatedKairosFixture {
+        CarrierMergedConnectionRepositoryKairos(
+            subId = SUB_ID,
+            tableLogBuffer = logcatTableLogBuffer(this),
+            telephonyManager = telephonyManager,
+            wifiRepository = wifiRepository,
+            isInEcmMode = stateOf(false),
+        )
+    }
+
+    private val Kosmos.telephonyManager: TelephonyManager by Fixture {
+        mock {
+            on { subscriptionId } doReturn SUB_ID
+            on { simOperatorName } doReturn ""
+        }
+    }
+
+    private fun runTest(block: suspend KairosTestScope.() -> Unit) =
+        testKosmos().run {
+            useUnconfinedTestDispatcher()
+            runKairosTest { block() }
+        }
+
+    @Test
+    fun inactiveWifi_isDefault() = runTest {
+        val latestConnState by underTest.dataConnectionState.collectLastValue()
+        val latestNetType by underTest.resolvedNetworkType.collectLastValue()
+
+        fakeWifiRepository.setWifiNetwork(WifiNetworkModel.Inactive())
+
+        assertThat(latestConnState).isEqualTo(DataConnectionState.Disconnected)
+        assertThat(latestNetType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
+    }
+
+    @Test
+    fun activeWifi_isDefault() = runTest {
+        val latestConnState by underTest.dataConnectionState.collectLastValue()
+        val latestNetType by underTest.resolvedNetworkType.collectLastValue()
+
+        fakeWifiRepository.setWifiNetwork(WifiNetworkModel.Active.of(level = 1))
+
+        assertThat(latestConnState).isEqualTo(DataConnectionState.Disconnected)
+        assertThat(latestNetType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
+    }
+
+    @Test
+    fun carrierMergedWifi_isValidAndFieldsComeFromWifiNetwork() = runTest {
+        val latest by underTest.primaryLevel.collectLastValue()
+
+        fakeWifiRepository.setIsWifiEnabled(true)
+        fakeWifiRepository.setIsWifiDefault(true)
+
+        fakeWifiRepository.setWifiNetwork(
+            WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
+        )
+
+        assertThat(latest).isEqualTo(3)
+    }
+
+    @Test
+    fun activity_comesFromWifiActivity() = runTest {
+        val latest by underTest.dataActivityDirection.collectLastValue()
+
+        fakeWifiRepository.setIsWifiEnabled(true)
+        fakeWifiRepository.setIsWifiDefault(true)
+        fakeWifiRepository.setWifiNetwork(
+            WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
+        )
+        fakeWifiRepository.setWifiActivity(
+            DataActivityModel(hasActivityIn = true, hasActivityOut = false)
+        )
+
+        assertThat(latest!!.hasActivityIn).isTrue()
+        assertThat(latest!!.hasActivityOut).isFalse()
+
+        fakeWifiRepository.setWifiActivity(
+            DataActivityModel(hasActivityIn = false, hasActivityOut = true)
+        )
+
+        assertThat(latest!!.hasActivityIn).isFalse()
+        assertThat(latest!!.hasActivityOut).isTrue()
+    }
+
+    @Test
+    fun carrierMergedWifi_wrongSubId_isDefault() = runTest {
+        val latestLevel by underTest.primaryLevel.collectLastValue()
+        val latestType by underTest.resolvedNetworkType.collectLastValue()
+
+        fakeWifiRepository.setWifiNetwork(
+            WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID + 10, level = 3)
+        )
+
+        assertThat(latestLevel).isNotEqualTo(3)
+        assertThat(latestType).isNotEqualTo(ResolvedNetworkType.CarrierMergedNetworkType)
+    }
+
+    // This scenario likely isn't possible, but write a test for it anyway
+    @Test
+    fun carrierMergedButNotEnabled_isDefault() = runTest {
+        val latest by underTest.primaryLevel.collectLastValue()
+
+        fakeWifiRepository.setWifiNetwork(
+            WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
+        )
+        fakeWifiRepository.setIsWifiEnabled(false)
+
+        assertThat(latest).isNotEqualTo(3)
+    }
+
+    // This scenario likely isn't possible, but write a test for it anyway
+    @Test
+    fun carrierMergedButWifiNotDefault_isDefault() = runTest {
+        val latest by underTest.primaryLevel.collectLastValue()
+
+        fakeWifiRepository.setWifiNetwork(
+            WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
+        )
+        fakeWifiRepository.setIsWifiDefault(false)
+
+        assertThat(latest).isNotEqualTo(3)
+    }
+
+    @Test
+    fun numberOfLevels_comesFromCarrierMerged() = runTest {
+        val latest by underTest.numberOfLevels.collectLastValue()
+
+        fakeWifiRepository.setWifiNetwork(
+            WifiNetworkModel.CarrierMerged.of(
+                subscriptionId = SUB_ID,
+                level = 1,
+                numberOfLevels = 6,
+            )
+        )
+
+        assertThat(latest).isEqualTo(6)
+    }
+
+    @Test
+    fun dataEnabled_matchesWifiEnabled() = runTest {
+        val latest by underTest.dataEnabled.collectLastValue()
+
+        fakeWifiRepository.setIsWifiEnabled(true)
+        assertThat(latest).isTrue()
+
+        fakeWifiRepository.setIsWifiEnabled(false)
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun cdmaRoaming_alwaysFalse() = runTest {
+        val latest by underTest.cdmaRoaming.collectLastValue()
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun networkName_usesSimOperatorNameAsInitial() = runTest {
+        telephonyManager.stub { on { simOperatorName } doReturn "Test SIM name" }
+
+        val latest by underTest.networkName.collectLastValue()
+
+        assertThat(latest).isEqualTo(NetworkNameModel.SimDerived("Test SIM name"))
+    }
+
+    @Test
+    fun networkName_updatesOnNetworkUpdate() = runTest {
+        fakeWifiRepository.setIsWifiEnabled(true)
+        fakeWifiRepository.setIsWifiDefault(true)
+
+        telephonyManager.stub { on { simOperatorName } doReturn "Test SIM name" }
+
+        val latest by underTest.networkName.collectLastValue()
+
+        assertThat(latest).isEqualTo(NetworkNameModel.SimDerived("Test SIM name"))
+
+        telephonyManager.stub { on { simOperatorName } doReturn "New SIM name" }
+        fakeWifiRepository.setWifiNetwork(
+            WifiNetworkModel.CarrierMerged.of(subscriptionId = SUB_ID, level = 3)
+        )
+
+        assertThat(latest).isEqualTo(NetworkNameModel.SimDerived("New SIM name"))
+    }
+
+    @Test
+    fun isAllowedDuringAirplaneMode_alwaysTrue() = runTest {
+        val latest by underTest.isAllowedDuringAirplaneMode.collectLastValue()
+
+        assertThat(latest).isTrue()
+    }
+
+    private companion object {
+        const val SUB_ID = 123
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryKairosTest.kt
new file mode 100644
index 0000000..858bb09
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryKairosTest.kt
@@ -0,0 +1,544 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import android.os.PersistableBundle
+import android.telephony.ServiceState
+import android.telephony.SignalStrength
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.activated
+import com.android.systemui.flags.Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO
+import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.kairos.ActivatedKairosFixture
+import com.android.systemui.kairos.BuildSpec
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosTestScope
+import com.android.systemui.kairos.MutableState
+import com.android.systemui.kairos.buildSpec
+import com.android.systemui.kairos.kairos
+import com.android.systemui.kairos.runKairosTest
+import com.android.systemui.kairos.stateOf
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_EMERGENCY
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Companion.COL_OPERATOR
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepositoryKairos.Companion.COL_PRIMARY_LEVEL
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.fakeWifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.wifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import java.io.PrintWriter
+import java.io.StringWriter
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+
+/**
+ * This repo acts as a dispatcher to either the `typical` or `carrier merged` versions of the
+ * repository interface it's switching on. These tests just need to verify that the entire interface
+ * properly switches over when the value of `isCarrierMerged` changes.
+ */
+@OptIn(ExperimentalKairosApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class FullMobileConnectionRepositoryKairosTest : SysuiTestCase() {
+    private val Kosmos.fakeMobileRepo by Fixture {
+        FakeMobileConnectionRepositoryKairos(SUB_ID, kairos, mobileLogger)
+    }
+
+    private val Kosmos.fakeCarrierMergedRepo by Fixture {
+        FakeMobileConnectionRepositoryKairos(SUB_ID, kairos, mobileLogger).apply {
+            // Mimicks the real carrier merged repository
+            isAllowedDuringAirplaneMode.setValue(true)
+        }
+    }
+
+    private var Kosmos.mobileRepo: MobileConnectionRepositoryKairos by Fixture { fakeMobileRepo }
+    private var Kosmos.carrierMergedRepoSpec:
+        BuildSpec<MobileConnectionRepositoryKairos> by Fixture {
+        buildSpec { fakeCarrierMergedRepo }
+    }
+
+    private val Kosmos.mobileLogger by Fixture { logcatTableLogBuffer(this, "TestName") }
+
+    private val Kosmos.underTest by ActivatedKairosFixture {
+        FullMobileConnectionRepositoryKairos(
+            SUB_ID,
+            mobileLogger,
+            mobileRepo,
+            carrierMergedRepoSpec,
+            isCarrierMerged,
+        )
+    }
+
+    private val Kosmos.subscriptionModel by Fixture {
+        MutableState(
+            kairos,
+            SubscriptionModel(
+                subscriptionId = SUB_ID,
+                carrierName = DEFAULT_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            ),
+        )
+    }
+
+    private val Kosmos.isCarrierMerged by Fixture { MutableState(kairos, false) }
+
+    // Use a real config, with no overrides
+    private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_ID, PersistableBundle())
+
+    private val kosmos =
+        testKosmos().apply {
+            useUnconfinedTestDispatcher()
+            fakeFeatureFlagsClassic.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, true)
+        }
+
+    private fun runTest(block: suspend KairosTestScope.() -> Unit) =
+        kosmos.run { runKairosTest { block() } }
+
+    @Test
+    fun startingIsCarrierMerged_usesCarrierMergedInitially() = runTest {
+        val carrierMergedOperatorName = "Carrier Merged Operator"
+        val nonCarrierMergedName = "Non-carrier-merged"
+
+        fakeCarrierMergedRepo.operatorAlphaShort.setValue(carrierMergedOperatorName)
+        fakeMobileRepo.operatorAlphaShort.setValue(nonCarrierMergedName)
+
+        isCarrierMerged.setValue(true)
+
+        val activeRepo by underTest.activeRepo.collectLastValue()
+        val operatorAlphaShort by underTest.operatorAlphaShort.collectLastValue()
+
+        assertThat(activeRepo).isEqualTo(fakeCarrierMergedRepo)
+        assertThat(operatorAlphaShort).isEqualTo(carrierMergedOperatorName)
+    }
+
+    @Test
+    fun startingNotCarrierMerged_usesTypicalInitially() = runTest {
+        val carrierMergedOperatorName = "Carrier Merged Operator"
+        val nonCarrierMergedName = "Typical Operator"
+
+        fakeCarrierMergedRepo.operatorAlphaShort.setValue(carrierMergedOperatorName)
+        fakeMobileRepo.operatorAlphaShort.setValue(nonCarrierMergedName)
+        isCarrierMerged.setValue(false)
+
+        assertThat(underTest.activeRepo.collectLastValue().value).isEqualTo(fakeMobileRepo)
+        assertThat(underTest.operatorAlphaShort.collectLastValue().value)
+            .isEqualTo(nonCarrierMergedName)
+    }
+
+    @Test
+    fun activeRepo_matchesIsCarrierMerged() = runTest {
+        isCarrierMerged.setValue(false)
+
+        val latest by underTest.activeRepo.collectLastValue()
+
+        isCarrierMerged.setValue(true)
+
+        assertThat(latest).isEqualTo(fakeCarrierMergedRepo)
+
+        isCarrierMerged.setValue(false)
+
+        assertThat(latest).isEqualTo(fakeMobileRepo)
+
+        isCarrierMerged.setValue(true)
+
+        assertThat(latest).isEqualTo(fakeCarrierMergedRepo)
+    }
+
+    @Test
+    fun connectionInfo_getsUpdatesFromRepo_carrierMerged() = runTest {
+        isCarrierMerged.setValue(false)
+
+        val latestName by underTest.operatorAlphaShort.collectLastValue()
+        val latestLevel by underTest.primaryLevel.collectLastValue()
+
+        isCarrierMerged.setValue(true)
+
+        val operator1 = "Carrier Merged Operator"
+        val level1 = 1
+        fakeCarrierMergedRepo.operatorAlphaShort.setValue(operator1)
+        fakeCarrierMergedRepo.primaryLevel.setValue(level1)
+
+        assertThat(latestName).isEqualTo(operator1)
+        assertThat(latestLevel).isEqualTo(level1)
+
+        val operator2 = "Carrier Merged Operator #2"
+        val level2 = 2
+        fakeCarrierMergedRepo.operatorAlphaShort.setValue(operator2)
+        fakeCarrierMergedRepo.primaryLevel.setValue(level2)
+
+        assertThat(latestName).isEqualTo(operator2)
+        assertThat(latestLevel).isEqualTo(level2)
+
+        val operator3 = "Carrier Merged Operator #3"
+        val level3 = 3
+        fakeCarrierMergedRepo.operatorAlphaShort.setValue(operator3)
+        fakeCarrierMergedRepo.primaryLevel.setValue(level3)
+
+        assertThat(latestName).isEqualTo(operator3)
+        assertThat(latestLevel).isEqualTo(level3)
+    }
+
+    @Test
+    fun connectionInfo_getsUpdatesFromRepo_mobile() = runTest {
+        isCarrierMerged.setValue(false)
+
+        val latestName by underTest.operatorAlphaShort.collectLastValue()
+        val latestLevel by underTest.primaryLevel.collectLastValue()
+
+        isCarrierMerged.setValue(false)
+
+        val operator1 = "Typical Merged Operator"
+        val level1 = 1
+        fakeMobileRepo.operatorAlphaShort.setValue(operator1)
+        fakeMobileRepo.primaryLevel.setValue(level1)
+
+        assertThat(latestName).isEqualTo(operator1)
+        assertThat(latestLevel).isEqualTo(level1)
+
+        val operator2 = "Typical Merged Operator #2"
+        val level2 = 2
+        fakeMobileRepo.operatorAlphaShort.setValue(operator2)
+        fakeMobileRepo.primaryLevel.setValue(level2)
+
+        assertThat(latestName).isEqualTo(operator2)
+        assertThat(latestLevel).isEqualTo(level2)
+
+        val operator3 = "Typical Merged Operator #3"
+        val level3 = 3
+        fakeMobileRepo.operatorAlphaShort.setValue(operator3)
+        fakeMobileRepo.primaryLevel.setValue(level3)
+
+        assertThat(latestName).isEqualTo(operator3)
+        assertThat(latestLevel).isEqualTo(level3)
+    }
+
+    @Test
+    fun connectionInfo_updatesWhenCarrierMergedUpdates() = runTest {
+        isCarrierMerged.setValue(false)
+
+        val latestName by underTest.operatorAlphaShort.collectLastValue()
+        val latestLevel by underTest.primaryLevel.collectLastValue()
+
+        val carrierMergedOperator = "Carrier Merged Operator"
+        val carrierMergedLevel = 4
+        fakeCarrierMergedRepo.operatorAlphaShort.setValue(carrierMergedOperator)
+        fakeCarrierMergedRepo.primaryLevel.setValue(carrierMergedLevel)
+
+        val mobileName = "Typical Operator"
+        val mobileLevel = 2
+        fakeMobileRepo.operatorAlphaShort.setValue(mobileName)
+        fakeMobileRepo.primaryLevel.setValue(mobileLevel)
+
+        // Start with the mobile info
+        assertThat(latestName).isEqualTo(mobileName)
+        assertThat(latestLevel).isEqualTo(mobileLevel)
+
+        // WHEN isCarrierMerged is set to true
+        isCarrierMerged.setValue(true)
+
+        // THEN the carrier merged info is used
+        assertThat(latestName).isEqualTo(carrierMergedOperator)
+        assertThat(latestLevel).isEqualTo(carrierMergedLevel)
+
+        val newCarrierMergedName = "New CM Operator"
+        val newCarrierMergedLevel = 0
+        fakeCarrierMergedRepo.operatorAlphaShort.setValue(newCarrierMergedName)
+        fakeCarrierMergedRepo.primaryLevel.setValue(newCarrierMergedLevel)
+
+        assertThat(latestName).isEqualTo(newCarrierMergedName)
+        assertThat(latestLevel).isEqualTo(newCarrierMergedLevel)
+
+        // WHEN isCarrierMerged is set to false
+        isCarrierMerged.setValue(false)
+
+        // THEN the typical info is used
+        assertThat(latestName).isEqualTo(mobileName)
+        assertThat(latestLevel).isEqualTo(mobileLevel)
+
+        val newMobileName = "New MobileOperator"
+        val newMobileLevel = 3
+        fakeMobileRepo.operatorAlphaShort.setValue(newMobileName)
+        fakeMobileRepo.primaryLevel.setValue(newMobileLevel)
+
+        assertThat(latestName).isEqualTo(newMobileName)
+        assertThat(latestLevel).isEqualTo(newMobileLevel)
+    }
+
+    @Test
+    fun isAllowedDuringAirplaneMode_updatesWhenCarrierMergedUpdates() = runTest {
+        isCarrierMerged.setValue(false)
+
+        val latest by underTest.isAllowedDuringAirplaneMode.collectLastValue()
+
+        assertThat(latest).isFalse()
+
+        isCarrierMerged.setValue(true)
+
+        assertThat(latest).isTrue()
+
+        isCarrierMerged.setValue(false)
+
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun connectionInfo_logging_notCarrierMerged_getsUpdates() = runTest {
+        // SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
+        val telephonyManager: TelephonyManager = mock {
+            on { simOperatorName } doReturn ""
+            on { subscriptionId } doReturn SUB_ID
+        }
+        fakeWifiRepository.setIsWifiEnabled(true)
+        fakeWifiRepository.setIsWifiDefault(true)
+        mobileRepo = createRealMobileRepo(telephonyManager)
+        carrierMergedRepoSpec = realCarrierMergedRepo(telephonyManager)
+
+        isCarrierMerged.setValue(false)
+
+        // Stand-up activated repository
+        underTest
+
+        // WHEN we set up some mobile connection info
+        val serviceState = ServiceState()
+        serviceState.setOperatorName("longName", "OpTypical", "1")
+        serviceState.isEmergencyOnly = true
+        getTelephonyCallbackForType<TelephonyCallback.ServiceStateListener>(telephonyManager)
+            .onServiceStateChanged(serviceState)
+
+        // THEN it's logged to the buffer
+        assertThat(dumpBuffer()).contains("$COL_OPERATOR${BUFFER_SEPARATOR}OpTypical")
+        assertThat(dumpBuffer()).contains("$COL_EMERGENCY${BUFFER_SEPARATOR}true")
+
+        // WHEN we update mobile connection info
+        val serviceState2 = ServiceState()
+        serviceState2.setOperatorName("longName", "OpDiff", "1")
+        serviceState2.isEmergencyOnly = false
+        getTelephonyCallbackForType<TelephonyCallback.ServiceStateListener>(telephonyManager)
+            .onServiceStateChanged(serviceState2)
+
+        // THEN the updates are logged
+        assertThat(dumpBuffer()).contains("$COL_OPERATOR${BUFFER_SEPARATOR}OpDiff")
+        assertThat(dumpBuffer()).contains("$COL_EMERGENCY${BUFFER_SEPARATOR}false")
+    }
+
+    @Test
+    fun connectionInfo_logging_carrierMerged_getsUpdates() = runTest {
+        // SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
+        val telephonyManager: TelephonyManager = mock {
+            on { simOperatorName } doReturn ""
+            on { subscriptionId } doReturn SUB_ID
+        }
+        fakeWifiRepository.setIsWifiEnabled(true)
+        fakeWifiRepository.setIsWifiDefault(true)
+        mobileRepo = createRealMobileRepo(telephonyManager)
+        carrierMergedRepoSpec = realCarrierMergedRepo(telephonyManager)
+
+        isCarrierMerged.setValue(true)
+
+        // Stand-up activated repository
+        underTest
+
+        // WHEN we set up carrier merged info
+        fakeWifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged.of(SUB_ID, level = 3))
+
+        // THEN the carrier merged info is logged
+        assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}3")
+
+        // WHEN we update the info
+        fakeWifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged.of(SUB_ID, level = 1))
+
+        // THEN the updates are logged
+        assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
+    }
+
+    @Test
+    fun connectionInfo_logging_updatesWhenCarrierMergedUpdates() = runTest {
+        // SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
+        val telephonyManager: TelephonyManager = mock {
+            on { simOperatorName } doReturn ""
+            on { subscriptionId } doReturn SUB_ID
+        }
+        fakeWifiRepository.setIsWifiEnabled(true)
+        fakeWifiRepository.setIsWifiDefault(true)
+        mobileRepo = createRealMobileRepo(telephonyManager)
+        carrierMergedRepoSpec = realCarrierMergedRepo(telephonyManager)
+
+        isCarrierMerged.setValue(false)
+
+        // Stand-up activated repository
+        underTest
+
+        // WHEN we set up some mobile connection info
+        val cb =
+            getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>(telephonyManager)
+        cb.onSignalStrengthsChanged(mock(stubOnly = true) { on { level } doReturn 1 })
+
+        // THEN it's logged to the buffer
+        assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
+
+        // WHEN isCarrierMerged is set to true
+        fakeWifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged.of(SUB_ID, level = 3))
+        isCarrierMerged.setValue(true)
+
+        // THEN the carrier merged info is logged
+        assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}3")
+
+        // WHEN the carrier merge network is updated
+        fakeWifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged.of(SUB_ID, level = 4))
+
+        // THEN the new level is logged
+        assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}4")
+
+        // WHEN isCarrierMerged is set to false
+        isCarrierMerged.setValue(false)
+
+        // THEN the typical info is logged
+        // Note: Since our first logs also had the typical info, we need to search the log
+        // contents for after our carrier merged level log.
+        val fullBuffer = dumpBuffer()
+        val carrierMergedContentIndex = fullBuffer.indexOf("${BUFFER_SEPARATOR}4")
+        val bufferAfterCarrierMerged = fullBuffer.substring(carrierMergedContentIndex)
+        assertThat(bufferAfterCarrierMerged).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}1")
+
+        // WHEN the normal network is updated
+        cb.onSignalStrengthsChanged(mock(stubOnly = true) { on { level } doReturn 0 })
+
+        // THEN the new level is logged
+        assertThat(dumpBuffer()).contains("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}0")
+    }
+
+    @Test
+    fun connectionInfo_logging_doesNotLogUpdatesForNotActiveRepo() = runTest {
+        // SETUP: Use real repositories to verify the diffing still works. (See b/267501739.)
+        val telephonyManager: TelephonyManager = mock {
+            on { simOperatorName } doReturn ""
+            on { subscriptionId } doReturn SUB_ID
+        }
+        fakeWifiRepository.setIsWifiEnabled(true)
+        fakeWifiRepository.setIsWifiDefault(true)
+        mobileRepo = createRealMobileRepo(telephonyManager)
+        carrierMergedRepoSpec = realCarrierMergedRepo(telephonyManager)
+
+        // WHEN isCarrierMerged = false
+        isCarrierMerged.setValue(false)
+
+        // Stand-up activated repository
+        underTest
+
+        fun setSignalLevel(newLevel: Int) {
+            val signalStrength =
+                mock<SignalStrength>(stubOnly = true) { on { level } doReturn newLevel }
+            argumentCaptor<TelephonyCallback>()
+                .apply { verify(telephonyManager).registerTelephonyCallback(any(), capture()) }
+                .allValues
+                .asSequence()
+                .filterIsInstance<TelephonyCallback.SignalStrengthsListener>()
+                .forEach { it.onSignalStrengthsChanged(signalStrength) }
+        }
+
+        // WHEN we set up some mobile connection info
+        setSignalLevel(1)
+
+        // THEN updates to the carrier merged level aren't logged
+        fakeWifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged.of(SUB_ID, level = 4))
+        assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}4")
+
+        fakeWifiRepository.setWifiNetwork(WifiNetworkModel.CarrierMerged.of(SUB_ID, level = 3))
+        assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}3")
+
+        // WHEN isCarrierMerged is set to true
+        isCarrierMerged.setValue(true)
+
+        // THEN updates to the normal level aren't logged
+        setSignalLevel(5)
+        assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}5")
+
+        setSignalLevel(6)
+        assertThat(dumpBuffer()).doesNotContain("$COL_PRIMARY_LEVEL${BUFFER_SEPARATOR}6")
+    }
+
+    private fun KairosTestScope.createRealMobileRepo(
+        telephonyManager: TelephonyManager
+    ): MobileConnectionRepositoryKairosImpl =
+        MobileConnectionRepositoryKairosImpl(
+                subId = SUB_ID,
+                context = context,
+                subscriptionModel = subscriptionModel,
+                defaultNetworkName = DEFAULT_NAME_MODEL,
+                networkNameSeparator = SEP,
+                connectivityManager = mock(stubOnly = true),
+                telephonyManager = telephonyManager,
+                systemUiCarrierConfig = systemUiCarrierConfig,
+                broadcastDispatcher = fakeBroadcastDispatcher,
+                mobileMappingsProxy = mock(stubOnly = true),
+                bgDispatcher = testDispatcher,
+                logger = mock(stubOnly = true),
+                tableLogBuffer = mobileLogger,
+                flags = featureFlagsClassic,
+            )
+            .activated()
+
+    private fun Kosmos.realCarrierMergedRepo(
+        telephonyManager: TelephonyManager
+    ): BuildSpec<CarrierMergedConnectionRepositoryKairos> = buildSpec {
+        activated {
+            CarrierMergedConnectionRepositoryKairos(
+                subId = SUB_ID,
+                tableLogBuffer = mobileLogger,
+                telephonyManager = telephonyManager,
+                wifiRepository = wifiRepository,
+                isInEcmMode = stateOf(false),
+            )
+        }
+    }
+
+    private fun Kosmos.dumpBuffer(): String {
+        val outputWriter = StringWriter()
+        mobileLogger.dump(PrintWriter(outputWriter), arrayOf())
+        return outputWriter.toString()
+    }
+
+    private companion object {
+        const val SUB_ID = 42
+        private const val DEFAULT_NAME = "default name"
+        private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
+        private const val SEP = "-"
+        private const val BUFFER_SEPARATOR = "|"
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosTest.kt
new file mode 100644
index 0000000..32fc359
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosTest.kt
@@ -0,0 +1,1228 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.net.ConnectivityManager.NetworkCallback
+import android.net.connectivityManager
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WLAN
+import android.telephony.AccessNetworkConstants.TRANSPORT_TYPE_WWAN
+import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
+import android.telephony.CarrierConfigManager.KEY_SHOW_5G_SLICE_ICON_BOOL
+import android.telephony.NetworkRegistrationInfo
+import android.telephony.NetworkRegistrationInfo.DOMAIN_PS
+import android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_DENIED
+import android.telephony.NetworkRegistrationInfo.REGISTRATION_STATE_HOME
+import android.telephony.ServiceState
+import android.telephony.ServiceState.STATE_IN_SERVICE
+import android.telephony.ServiceState.STATE_OUT_OF_SERVICE
+import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyCallback.CarrierRoamingNtnListener
+import android.telephony.TelephonyCallback.DataActivityListener
+import android.telephony.TelephonyCallback.DisplayInfoListener
+import android.telephony.TelephonyCallback.ServiceStateListener
+import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_CA
+import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
+import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.DATA_ACTIVITY_DORMANT
+import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
+import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
+import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
+import android.telephony.TelephonyManager.DATA_ACTIVITY_OUT
+import android.telephony.TelephonyManager.DATA_CONNECTED
+import android.telephony.TelephonyManager.DATA_CONNECTING
+import android.telephony.TelephonyManager.DATA_DISCONNECTED
+import android.telephony.TelephonyManager.DATA_DISCONNECTING
+import android.telephony.TelephonyManager.DATA_HANDOVER_IN_PROGRESS
+import android.telephony.TelephonyManager.DATA_SUSPENDED
+import android.telephony.TelephonyManager.DATA_UNKNOWN
+import android.telephony.TelephonyManager.ERI_OFF
+import android.telephony.TelephonyManager.ERI_ON
+import android.telephony.TelephonyManager.EXTRA_CARRIER_ID
+import android.telephony.TelephonyManager.EXTRA_DATA_SPN
+import android.telephony.TelephonyManager.EXTRA_PLMN
+import android.telephony.TelephonyManager.EXTRA_SHOW_PLMN
+import android.telephony.TelephonyManager.EXTRA_SHOW_SPN
+import android.telephony.TelephonyManager.EXTRA_SPN
+import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
+import android.telephony.TelephonyManager.NETWORK_TYPE_LTE
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
+import android.telephony.telephonyManager
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.mobile.MobileMappings
+import com.android.systemui.Flags
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO
+import com.android.systemui.flags.fake
+import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.kairos.ActivatedKairosFixture
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosTestScope
+import com.android.systemui.kairos.MutableState
+import com.android.systemui.kairos.kairos
+import com.android.systemui.kairos.runKairosTest
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.LogcatEchoTrackerAlways
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.tableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfigWithOverride
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.telephonyDisplayInfo
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.testKosmos
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
+import org.mockito.kotlin.whenever
+
+@OptIn(ExperimentalKairosApi::class)
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MobileConnectionRepositoryKairosTest : SysuiTestCase() {
+
+    private val Kosmos.underTest by ActivatedKairosFixture {
+        MobileConnectionRepositoryKairosImpl(
+            SUB_1_ID,
+            context,
+            subscriptionModel,
+            DEFAULT_NAME_MODEL,
+            SEP,
+            connectivityManager,
+            telephonyManager,
+            systemUiCarrierConfig,
+            fakeBroadcastDispatcher,
+            mobileMappingsProxy,
+            testDispatcher,
+            logger,
+            tableLogger,
+            featureFlagsClassic,
+        )
+    }
+
+    private val Kosmos.logger: MobileInputLogger by Fixture {
+        MobileInputLogger(LogBuffer("test_buffer", 1, LogcatEchoTrackerAlways()))
+    }
+
+    private val Kosmos.tableLogger: TableLogBuffer by Fixture {
+        tableLogBufferFactory.getOrCreate("test_buffer", 1)
+    }
+
+    private val Kosmos.context: Context by Fixture { mock() }
+
+    private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, testCarrierConfig())
+
+    private val Kosmos.subscriptionModel: MutableState<SubscriptionModel?> by Fixture {
+        MutableState(
+            kairos,
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                carrierName = DEFAULT_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            ),
+        )
+    }
+
+    private val kosmos =
+        testKosmos().apply {
+            useUnconfinedTestDispatcher()
+            featureFlagsClassic.fake.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, true)
+            telephonyManager.stub { on { subscriptionId } doReturn SUB_1_ID }
+        }
+
+    private fun runTest(block: suspend KairosTestScope.() -> Unit) =
+        kosmos.run { runKairosTest { block() } }
+
+    @Test
+    fun emergencyOnly() = runTest {
+        val latest by underTest.isEmergencyOnly.collectLastValue()
+
+        val serviceState = ServiceState().apply { isEmergencyOnly = true }
+
+        getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
+
+        assertThat(latest).isEqualTo(true)
+    }
+
+    @Test
+    fun emergencyOnly_toggles() = runTest {
+        val latest by underTest.isEmergencyOnly.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<ServiceStateListener>()
+        callback.onServiceStateChanged(ServiceState().apply { isEmergencyOnly = true })
+
+        assertThat(latest).isTrue()
+
+        callback.onServiceStateChanged(ServiceState().apply { isEmergencyOnly = false })
+
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun cdmaLevelUpdates() = runTest {
+        val latest by underTest.cdmaLevel.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
+        var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+        callback.onSignalStrengthsChanged(strength)
+
+        assertThat(latest).isEqualTo(2)
+
+        // gsmLevel updates, no change to cdmaLevel
+        strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true)
+        callback.onSignalStrengthsChanged(strength)
+
+        assertThat(latest).isEqualTo(2)
+    }
+
+    @Test
+    fun gsmLevelUpdates() = runTest {
+        val latest by underTest.primaryLevel.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
+        var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+        callback.onSignalStrengthsChanged(strength)
+
+        assertThat(latest).isEqualTo(1)
+
+        strength = signalStrength(gsmLevel = 3, cdmaLevel = 2, isGsm = true)
+        callback.onSignalStrengthsChanged(strength)
+
+        assertThat(latest).isEqualTo(3)
+    }
+
+    @Test
+    fun isGsm() = runTest {
+        val latest by underTest.isGsm.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.SignalStrengthsListener>()
+        var strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = true)
+        callback.onSignalStrengthsChanged(strength)
+
+        assertThat(latest).isTrue()
+
+        strength = signalStrength(gsmLevel = 1, cdmaLevel = 2, isGsm = false)
+        callback.onSignalStrengthsChanged(strength)
+
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun dataConnectionState_connected() = runTest {
+        val latest by underTest.dataConnectionState.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+        callback.onDataConnectionStateChanged(DATA_CONNECTED, 200 /* unused */)
+
+        assertThat(latest).isEqualTo(DataConnectionState.Connected)
+    }
+
+    @Test
+    fun dataConnectionState_connecting() = runTest {
+        val latest by underTest.dataConnectionState.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+        callback.onDataConnectionStateChanged(DATA_CONNECTING, 200 /* unused */)
+
+        assertThat(latest).isEqualTo(DataConnectionState.Connecting)
+    }
+
+    @Test
+    fun dataConnectionState_disconnected() = runTest {
+        val latest by underTest.dataConnectionState.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+        callback.onDataConnectionStateChanged(DATA_DISCONNECTED, 200 /* unused */)
+
+        assertThat(latest).isEqualTo(DataConnectionState.Disconnected)
+    }
+
+    @Test
+    fun dataConnectionState_disconnecting() = runTest {
+        val latest by underTest.dataConnectionState.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+        callback.onDataConnectionStateChanged(DATA_DISCONNECTING, 200 /* unused */)
+
+        assertThat(latest).isEqualTo(DataConnectionState.Disconnecting)
+    }
+
+    @Test
+    fun dataConnectionState_suspended() = runTest {
+        val latest by underTest.dataConnectionState.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+        callback.onDataConnectionStateChanged(DATA_SUSPENDED, 200 /* unused */)
+
+        assertThat(latest).isEqualTo(DataConnectionState.Suspended)
+    }
+
+    @Test
+    fun dataConnectionState_handoverInProgress() = runTest {
+        val latest by underTest.dataConnectionState.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+        callback.onDataConnectionStateChanged(DATA_HANDOVER_IN_PROGRESS, 200 /* unused */)
+
+        assertThat(latest).isEqualTo(DataConnectionState.HandoverInProgress)
+    }
+
+    @Test
+    fun dataConnectionState_unknown() = runTest {
+        val latest by underTest.dataConnectionState.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+        callback.onDataConnectionStateChanged(DATA_UNKNOWN, 200 /* unused */)
+
+        assertThat(latest).isEqualTo(DataConnectionState.Unknown)
+    }
+
+    @Test
+    fun dataConnectionState_invalid() = runTest {
+        val latest by underTest.dataConnectionState.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DataConnectionStateListener>()
+        callback.onDataConnectionStateChanged(45, 200 /* unused */)
+
+        assertThat(latest).isEqualTo(DataConnectionState.Invalid)
+    }
+
+    @Test
+    fun dataActivity() = runTest {
+        val latest by underTest.dataActivityDirection.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<DataActivityListener>()
+        callback.onDataActivity(DATA_ACTIVITY_INOUT)
+
+        assertThat(latest).isEqualTo(DATA_ACTIVITY_INOUT.toMobileDataActivityModel())
+    }
+
+    @Test
+    fun carrierId_initialValueCaptured() = runTest {
+        whenever(telephonyManager.simCarrierId).thenReturn(1234)
+
+        val latest by underTest.carrierId.collectLastValue()
+
+        assertThat(latest).isEqualTo(1234)
+    }
+
+    @Test
+    fun carrierId_updatesOnBroadcast() = runTest {
+        whenever(telephonyManager.simCarrierId).thenReturn(1234)
+
+        val latest by underTest.carrierId.collectLastValue()
+
+        fakeBroadcastDispatcher.sendIntentToMatchingReceiversOnly(
+            context,
+            carrierIdIntent(carrierId = 4321),
+        )
+
+        assertThat(latest).isEqualTo(4321)
+    }
+
+    @Test
+    fun carrierNetworkChange() = runTest {
+        val latest by underTest.carrierNetworkChangeActive.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.CarrierNetworkListener>()
+        callback.onCarrierNetworkChange(true)
+
+        assertThat(latest).isEqualTo(true)
+    }
+
+    @Test
+    fun networkType_default() = runTest {
+        val latest by underTest.resolvedNetworkType.collectLastValue()
+
+        val expected = UnknownNetworkType
+
+        assertThat(latest).isEqualTo(expected)
+    }
+
+    @Test
+    fun networkType_unknown_hasCorrectKey() = runTest {
+        val latest by underTest.resolvedNetworkType.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+        val ti =
+            telephonyDisplayInfo(
+                networkType = NETWORK_TYPE_UNKNOWN,
+                overrideNetworkType = NETWORK_TYPE_UNKNOWN,
+            )
+
+        callback.onDisplayInfoChanged(ti)
+
+        val expected = UnknownNetworkType
+        assertThat(latest).isEqualTo(expected)
+        assertThat(latest!!.lookupKey).isEqualTo(MobileMappings.toIconKey(NETWORK_TYPE_UNKNOWN))
+    }
+
+    @Test
+    fun networkType_updatesUsingDefault() = runTest {
+        val latest by underTest.resolvedNetworkType.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+        val overrideType = OVERRIDE_NETWORK_TYPE_NONE
+        val type = NETWORK_TYPE_LTE
+        val ti = telephonyDisplayInfo(networkType = type, overrideNetworkType = overrideType)
+        callback.onDisplayInfoChanged(ti)
+
+        val expected = DefaultNetworkType(mobileMappingsProxy.toIconKey(type))
+        assertThat(latest).isEqualTo(expected)
+    }
+
+    @Test
+    fun networkType_updatesUsingOverride() = runTest {
+        val latest by underTest.resolvedNetworkType.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+        val type = OVERRIDE_NETWORK_TYPE_LTE_CA
+        val ti = telephonyDisplayInfo(networkType = type, overrideNetworkType = type)
+        callback.onDisplayInfoChanged(ti)
+
+        val expected = OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(type))
+        assertThat(latest).isEqualTo(expected)
+    }
+
+    @Test
+    fun networkType_unknownNetworkWithOverride_usesOverrideKey() = runTest {
+        val latest by underTest.resolvedNetworkType.collectLastValue()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DisplayInfoListener>()
+        val unknown = NETWORK_TYPE_UNKNOWN
+        val type = OVERRIDE_NETWORK_TYPE_LTE_CA
+        val ti = telephonyDisplayInfo(unknown, type)
+        callback.onDisplayInfoChanged(ti)
+
+        val expected = OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(type))
+        assertThat(latest).isEqualTo(expected)
+    }
+
+    @Test
+    fun dataEnabled_initial_false() = runTest {
+        whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
+
+        val latest by underTest.dataEnabled.collectLastValue()
+
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun isDataEnabled_tracksTelephonyCallback() = runTest {
+        val latest by underTest.dataEnabled.collectLastValue()
+
+        whenever(telephonyManager.isDataConnectionAllowed).thenReturn(false)
+        assertThat(latest).isFalse()
+
+        val callback = getTelephonyCallbackForType<TelephonyCallback.DataEnabledListener>()
+
+        callback.onDataEnabledChanged(true, 1)
+        assertThat(latest).isTrue()
+
+        callback.onDataEnabledChanged(false, 1)
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun numberOfLevels_isDefault() = runTest {
+        val latest by underTest.numberOfLevels.collectLastValue()
+
+        assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
+    }
+
+    @Test
+    fun roaming_cdma_queriesTelephonyManager() = runTest {
+        val latest by underTest.cdmaRoaming.collectLastValue()
+
+        val cb = getTelephonyCallbackForType<ServiceStateListener>()
+
+        // CDMA roaming is off, GSM roaming is on
+        whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
+        cb.onServiceStateChanged(ServiceState().also { it.roaming = true })
+
+        assertThat(latest).isFalse()
+
+        // CDMA roaming is on, GSM roaming is off
+        whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_ON)
+        cb.onServiceStateChanged(ServiceState().also { it.roaming = false })
+
+        assertThat(latest).isTrue()
+    }
+
+    /**
+     * [TelephonyManager.getCdmaEnhancedRoamingIndicatorDisplayNumber] returns -1 if the service is
+     * not running or if there is an error while retrieving the cdma ERI
+     */
+    @Test
+    fun cdmaRoaming_ignoresNegativeOne() = runTest {
+        val latest by underTest.cdmaRoaming.collectLastValue()
+
+        val serviceState = ServiceState()
+        serviceState.roaming = false
+
+        val cb = getTelephonyCallbackForType<ServiceStateListener>()
+
+        // CDMA roaming is unavailable (-1), GSM roaming is off
+        whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(-1)
+        cb.onServiceStateChanged(serviceState)
+
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun roaming_gsm_queriesDisplayInfo_viaDisplayInfo() = runTest {
+        // GIVEN flag is true
+        featureFlagsClassic.fake.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, true)
+
+        val latest by underTest.isRoaming.collectLastValue()
+
+        val cb = getTelephonyCallbackForType<DisplayInfoListener>()
+
+        // CDMA roaming is off, GSM roaming is off
+        whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
+        cb.onDisplayInfoChanged(TelephonyDisplayInfo(NETWORK_TYPE_LTE, NETWORK_TYPE_UNKNOWN, false))
+
+        assertThat(latest).isFalse()
+
+        // CDMA roaming is off, GSM roaming is on
+        cb.onDisplayInfoChanged(TelephonyDisplayInfo(NETWORK_TYPE_LTE, NETWORK_TYPE_UNKNOWN, true))
+
+        assertThat(latest).isTrue()
+    }
+
+    @Test
+    fun roaming_gsm_queriesDisplayInfo_viaServiceState() = runTest {
+        // GIVEN flag is false
+        featureFlagsClassic.fake.set(ROAMING_INDICATOR_VIA_DISPLAY_INFO, false)
+
+        val latest by underTest.isRoaming.collectLastValue()
+
+        val cb = getTelephonyCallbackForType<ServiceStateListener>()
+
+        // CDMA roaming is off, GSM roaming is off
+        whenever(telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber).thenReturn(ERI_OFF)
+        cb.onServiceStateChanged(ServiceState().also { it.roaming = false })
+
+        assertThat(latest).isFalse()
+
+        // CDMA roaming is off, GSM roaming is on
+        cb.onServiceStateChanged(ServiceState().also { it.roaming = true })
+
+        assertThat(latest).isTrue()
+    }
+
+    @Test
+    fun activity_updatesFromCallback() = runTest {
+        val latest by underTest.dataActivityDirection.collectLastValue()
+
+        assertThat(latest)
+            .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+
+        val cb = getTelephonyCallbackForType<DataActivityListener>()
+        cb.onDataActivity(DATA_ACTIVITY_IN)
+        assertThat(latest)
+            .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = false))
+
+        cb.onDataActivity(DATA_ACTIVITY_OUT)
+        assertThat(latest)
+            .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = true))
+
+        cb.onDataActivity(DATA_ACTIVITY_INOUT)
+        assertThat(latest).isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
+
+        cb.onDataActivity(DATA_ACTIVITY_NONE)
+        assertThat(latest)
+            .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+
+        cb.onDataActivity(DATA_ACTIVITY_DORMANT)
+        assertThat(latest)
+            .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+
+        cb.onDataActivity(1234)
+        assertThat(latest)
+            .isEqualTo(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+    }
+
+    @Test
+    fun networkNameForSubId_updates() = runTest {
+        val latest by underTest.carrierName.collectLastValue()
+
+        subscriptionModel.setValue(
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                carrierName = DEFAULT_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+        )
+
+        assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
+
+        val updatedName = "Derived Carrier"
+        subscriptionModel.setValue(
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                carrierName = updatedName,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+        )
+
+        assertThat(latest?.name).isEqualTo(updatedName)
+    }
+
+    @Test
+    fun networkNameForSubId_defaultWhenSubscriptionModelNull() = runTest {
+        val latest by underTest.carrierName.collectLastValue()
+
+        subscriptionModel.setValue(null)
+
+        assertThat(latest?.name).isEqualTo(DEFAULT_NAME)
+    }
+
+    @Test
+    fun networkName_default() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+
+        assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_usesBroadcastInfo_returnsDerived() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+
+        val intent = spnIntent()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        captor.lastValue.onReceive(context, intent)
+
+        // spnIntent() sets all values to true and test strings
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_usesBroadcastInfo_returnsDerived_flagOff() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+
+        val intent = spnIntent()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        captor.lastValue.onReceive(context, intent)
+
+        // spnIntent() sets all values to true and test strings
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_broadcastNotForThisSubId_keepsOldValue() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+
+        val intent = spnIntent()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        captor.lastValue.onReceive(context, intent)
+
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+
+        // WHEN an intent with a different subId is sent
+        val wrongSubIntent = spnIntent(subId = 101)
+
+        captor.lastValue.onReceive(context, wrongSubIntent)
+
+        // THEN the previous intent's name is still used
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_broadcastNotForThisSubId_keepsOldValue_flagOff() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+
+        val intent = spnIntent()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        captor.lastValue.onReceive(context, intent)
+
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+
+        // WHEN an intent with a different subId is sent
+        val wrongSubIntent = spnIntent(subId = 101)
+
+        captor.lastValue.onReceive(context, wrongSubIntent)
+
+        // THEN the previous intent's name is still used
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_broadcastHasNoData_updatesToDefault() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+
+        val intent = spnIntent()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        captor.lastValue.onReceive(context, intent)
+
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+
+        val intentWithoutInfo = spnIntent(showSpn = false, showPlmn = false)
+
+        captor.lastValue.onReceive(context, intentWithoutInfo)
+
+        assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_broadcastHasNoData_updatesToDefault_flagOff() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+
+        val intent = spnIntent()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        captor.lastValue.onReceive(context, intent)
+
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+
+        val intentWithoutInfo = spnIntent(showSpn = false, showPlmn = false)
+
+        captor.lastValue.onReceive(context, intentWithoutInfo)
+
+        assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_usingEagerStrategy_retainsNameBetweenSubscribers() = runTest {
+        // Use the [StateFlow.value] getter so we can prove that the collection happens
+        // even when there is no [Job]
+
+        // Starts out default
+        val latest by underTest.networkName.collectLastValue()
+        assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+
+        val intent = spnIntent()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        captor.lastValue.onReceive(context, intent)
+
+        // The value is still there despite no active subscribers
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_usingEagerStrategy_retainsNameBetweenSubscribers_flagOff() = runTest {
+        // Use the [StateFlow.value] getter so we can prove that the collection happens
+        // even when there is no [Job]
+
+        // Starts out default
+        val latest by underTest.networkName.collectLastValue()
+        assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+
+        val intent = spnIntent()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        captor.lastValue.onReceive(context, intent)
+
+        // The value is still there despite no active subscribers
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_allFieldsSet_prioritizesDataSpnOverSpn() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+
+        val intent =
+            spnIntent(
+                subId = SUB_1_ID,
+                showSpn = true,
+                spn = SPN,
+                dataSpn = DATA_SPN,
+                showPlmn = true,
+                plmn = PLMN,
+            )
+        captor.lastValue.onReceive(context, intent)
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_spnAndPlmn_fallbackToSpnWhenNullDataSpn() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+
+        val intent =
+            spnIntent(
+                subId = SUB_1_ID,
+                showSpn = true,
+                spn = SPN,
+                dataSpn = null,
+                showPlmn = true,
+                plmn = PLMN,
+            )
+        captor.lastValue.onReceive(context, intent)
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN"))
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_allFieldsSet_flagOff() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+
+        val intent =
+            spnIntent(
+                subId = SUB_1_ID,
+                showSpn = true,
+                spn = SPN,
+                dataSpn = DATA_SPN,
+                showPlmn = true,
+                plmn = PLMN,
+            )
+        captor.lastValue.onReceive(context, intent)
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNotNull_showSpn_spnNull_dataSpnNotNull() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        val intent =
+            spnIntent(
+                subId = SUB_1_ID,
+                showSpn = true,
+                spn = null,
+                dataSpn = DATA_SPN,
+                showPlmn = true,
+                plmn = PLMN,
+            )
+        captor.lastValue.onReceive(context, intent)
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNotNull_showSpn_spnNotNull_dataSpnNull() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        val intent =
+            spnIntent(
+                subId = SUB_1_ID,
+                showSpn = true,
+                spn = SPN,
+                dataSpn = null,
+                showPlmn = true,
+                plmn = PLMN,
+            )
+        captor.lastValue.onReceive(context, intent)
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$SPN"))
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNotNull_showSpn_spnNull_dataSpnNotNull_flagOff() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        val intent =
+            spnIntent(
+                subId = SUB_1_ID,
+                showSpn = true,
+                spn = null,
+                dataSpn = DATA_SPN,
+                showPlmn = true,
+                plmn = PLMN,
+            )
+        captor.lastValue.onReceive(context, intent)
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN$SEP$DATA_SPN"))
+    }
+
+    @Test
+    fun networkName_showPlmn_noShowSPN() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        val intent =
+            spnIntent(
+                subId = SUB_1_ID,
+                showSpn = false,
+                spn = SPN,
+                dataSpn = DATA_SPN,
+                showPlmn = true,
+                plmn = PLMN,
+            )
+        captor.lastValue.onReceive(context, intent)
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$PLMN"))
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNull_showSpn() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        val intent =
+            spnIntent(
+                subId = SUB_1_ID,
+                showSpn = true,
+                spn = SPN,
+                dataSpn = DATA_SPN,
+                showPlmn = true,
+                plmn = null,
+            )
+        captor.lastValue.onReceive(context, intent)
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$DATA_SPN"))
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNull_showSpn_dataSpnNull() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        val intent =
+            spnIntent(
+                subId = SUB_1_ID,
+                showSpn = true,
+                spn = SPN,
+                dataSpn = null,
+                showPlmn = true,
+                plmn = null,
+            )
+        captor.lastValue.onReceive(context, intent)
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$SPN"))
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNull_showSpn_bothSpnNull() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        val intent =
+            spnIntent(
+                subId = SUB_1_ID,
+                showSpn = true,
+                spn = null,
+                dataSpn = null,
+                showPlmn = true,
+                plmn = null,
+            )
+        captor.lastValue.onReceive(context, intent)
+        assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_STATUS_BAR_SWITCH_TO_SPN_FROM_DATA_SPN)
+    fun networkName_showPlmn_plmnNull_showSpn_flagOff() = runTest {
+        val latest by underTest.networkName.collectLastValue()
+        val captor = argumentCaptor<BroadcastReceiver>()
+        verify(context).registerReceiver(captor.capture(), any())
+        val intent =
+            spnIntent(
+                subId = SUB_1_ID,
+                showSpn = true,
+                spn = SPN,
+                dataSpn = DATA_SPN,
+                showPlmn = true,
+                plmn = null,
+            )
+        captor.lastValue.onReceive(context, intent)
+        assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived("$DATA_SPN"))
+    }
+
+    @Test
+    fun operatorAlphaShort_tracked() = runTest {
+        val latest by underTest.operatorAlphaShort.collectLastValue()
+
+        val shortName = "short name"
+        val serviceState = ServiceState()
+        serviceState.setOperatorName(
+            /* longName */ "long name",
+            /* shortName */ shortName,
+            /* numeric */ "12345",
+        )
+
+        getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
+
+        assertThat(latest).isEqualTo(shortName)
+    }
+
+    @Test
+    fun isInService_notIwlan() = runTest {
+        val latest by underTest.isInService.collectLastValue()
+
+        val nriInService =
+            NetworkRegistrationInfo.Builder()
+                .setDomain(DOMAIN_PS)
+                .setTransportType(TRANSPORT_TYPE_WWAN)
+                .setRegistrationState(REGISTRATION_STATE_HOME)
+                .build()
+
+        getTelephonyCallbackForType<ServiceStateListener>()
+            .onServiceStateChanged(
+                ServiceState().also {
+                    it.voiceRegState = STATE_IN_SERVICE
+                    it.addNetworkRegistrationInfo(nriInService)
+                }
+            )
+
+        assertThat(latest).isTrue()
+
+        getTelephonyCallbackForType<ServiceStateListener>()
+            .onServiceStateChanged(
+                ServiceState().also {
+                    it.voiceRegState = STATE_OUT_OF_SERVICE
+                    it.addNetworkRegistrationInfo(nriInService)
+                }
+            )
+        assertThat(latest).isTrue()
+
+        val nriNotInService =
+            NetworkRegistrationInfo.Builder()
+                .setDomain(DOMAIN_PS)
+                .setTransportType(TRANSPORT_TYPE_WWAN)
+                .setRegistrationState(REGISTRATION_STATE_DENIED)
+                .build()
+        getTelephonyCallbackForType<ServiceStateListener>()
+            .onServiceStateChanged(
+                ServiceState().also {
+                    it.voiceRegState = STATE_OUT_OF_SERVICE
+                    it.addNetworkRegistrationInfo(nriNotInService)
+                }
+            )
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun isInService_isIwlan_voiceOutOfService_dataInService() = runTest {
+        val latest by underTest.isInService.collectLastValue()
+
+        val iwlanData =
+            NetworkRegistrationInfo.Builder()
+                .setDomain(DOMAIN_PS)
+                .setTransportType(TRANSPORT_TYPE_WLAN)
+                .setRegistrationState(REGISTRATION_STATE_HOME)
+                .build()
+        val serviceState =
+            ServiceState().also {
+                it.voiceRegState = STATE_OUT_OF_SERVICE
+                it.addNetworkRegistrationInfo(iwlanData)
+            }
+
+        getTelephonyCallbackForType<ServiceStateListener>().onServiceStateChanged(serviceState)
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun isNonTerrestrial_updatesFromCallback0() = runTest {
+        val latest by underTest.isNonTerrestrial.collectLastValue()
+
+        // Starts out false
+        assertThat(latest).isFalse()
+
+        val callback = getTelephonyCallbackForType<CarrierRoamingNtnListener>()
+
+        callback.onCarrierRoamingNtnModeChanged(true)
+        assertThat(latest).isTrue()
+
+        callback.onCarrierRoamingNtnModeChanged(false)
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun numberOfLevels_usesCarrierConfig() = runTest {
+        val latest by underTest.numberOfLevels.collectLastValue()
+
+        assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
+
+        systemUiCarrierConfig.processNewCarrierConfig(
+            testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
+        )
+
+        assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS + 1)
+
+        systemUiCarrierConfig.processNewCarrierConfig(
+            testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
+        )
+
+        assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
+    }
+
+    @Test
+    fun inflateSignalStrength_usesCarrierConfig() = runTest {
+        val latest by underTest.inflateSignalStrength.collectLastValue()
+
+        assertThat(latest).isEqualTo(false)
+
+        systemUiCarrierConfig.processNewCarrierConfig(
+            testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
+        )
+
+        assertThat(latest).isEqualTo(true)
+
+        systemUiCarrierConfig.processNewCarrierConfig(
+            testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
+        )
+
+        assertThat(latest).isEqualTo(false)
+    }
+
+    @Test
+    fun allowNetworkSliceIndicator_exposesCarrierConfigValue() = runTest {
+        val latest by underTest.allowNetworkSliceIndicator.collectLastValue()
+
+        systemUiCarrierConfig.processNewCarrierConfig(
+            testCarrierConfigWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, true)
+        )
+
+        assertThat(latest).isTrue()
+
+        systemUiCarrierConfig.processNewCarrierConfig(
+            testCarrierConfigWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, false)
+        )
+
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun isAllowedDuringAirplaneMode_alwaysFalse() = runTest {
+        val latest by underTest.isAllowedDuringAirplaneMode.collectLastValue()
+
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun hasPrioritizedCaps_defaultFalse() = runTest {
+        // stand up under-test to kick-off activation
+        underTest
+
+        assertThat(kairos.transact { underTest.hasPrioritizedNetworkCapabilities.sample() })
+            .isFalse()
+    }
+
+    @Test
+    fun hasPrioritizedCaps_trueWhenAvailable() = runTest {
+        val latest by underTest.hasPrioritizedNetworkCapabilities.collectLastValue()
+
+        val callback: NetworkCallback =
+            argumentCaptor<NetworkCallback>()
+                .apply { verify(connectivityManager).registerNetworkCallback(any(), capture()) }
+                .lastValue
+
+        callback.onAvailable(mock())
+
+        assertThat(latest).isTrue()
+    }
+
+    @Test
+    fun hasPrioritizedCaps_becomesFalseWhenNetworkLost() = runTest {
+        val latest by underTest.hasPrioritizedNetworkCapabilities.collectLastValue()
+
+        val callback: NetworkCallback =
+            argumentCaptor<NetworkCallback>()
+                .apply { verify(connectivityManager).registerNetworkCallback(any(), capture()) }
+                .lastValue
+
+        callback.onAvailable(mock())
+
+        assertThat(latest).isTrue()
+
+        callback.onLost(mock())
+
+        assertThat(latest).isFalse()
+    }
+
+    private inline fun <reified T> Kosmos.getTelephonyCallbackForType(): T {
+        return MobileTelephonyHelpers.getTelephonyCallbackForType(telephonyManager)
+    }
+
+    private fun carrierIdIntent(subId: Int = SUB_1_ID, carrierId: Int): Intent =
+        Intent(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED).apply {
+            putExtra(EXTRA_SUBSCRIPTION_ID, subId)
+            putExtra(EXTRA_CARRIER_ID, carrierId)
+        }
+
+    private fun spnIntent(
+        subId: Int = SUB_1_ID,
+        showSpn: Boolean = true,
+        spn: String? = SPN,
+        dataSpn: String? = DATA_SPN,
+        showPlmn: Boolean = true,
+        plmn: String? = PLMN,
+    ): Intent =
+        Intent(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED).apply {
+            putExtra(EXTRA_SUBSCRIPTION_INDEX, subId)
+            putExtra(EXTRA_SHOW_SPN, showSpn)
+            putExtra(EXTRA_SPN, spn)
+            putExtra(EXTRA_DATA_SPN, dataSpn)
+            putExtra(EXTRA_SHOW_PLMN, showPlmn)
+            putExtra(EXTRA_PLMN, plmn)
+        }
+
+    companion object {
+        private const val SUB_1_ID = 1
+
+        private const val DEFAULT_NAME = "Fake Mobile Network"
+        private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
+        private const val SEP = "-"
+
+        private const val SPN = "testSpn"
+        private const val DATA_SPN = "testDataSpn"
+        private const val PLMN = "testPlmn"
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosTest.kt
new file mode 100644
index 0000000..e04a96e
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosTest.kt
@@ -0,0 +1,1350 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import android.annotation.SuppressLint
+import android.content.Intent
+import android.content.applicationContext
+import android.content.testableContext
+import android.net.ConnectivityManager
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
+import android.net.NetworkCapabilities.TRANSPORT_CELLULAR
+import android.net.NetworkCapabilities.TRANSPORT_ETHERNET
+import android.net.NetworkCapabilities.TRANSPORT_WIFI
+import android.net.connectivityManager
+import android.net.vcn.VcnTransportInfo
+import android.net.wifi.WifiInfo
+import android.net.wifi.WifiManager
+import android.os.ParcelUuid
+import android.telephony.CarrierConfigManager
+import android.telephony.ServiceState
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.SubscriptionManager.OnSubscriptionsChangedListener
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
+import android.telephony.TelephonyCallback.EmergencyCallbackModeListener
+import android.telephony.TelephonyManager
+import android.telephony.telephonyManager
+import android.testing.TestableLooper
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.internal.telephony.PhoneConstants
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.keyguard.keyguardUpdateMonitor
+import com.android.settingslib.R
+import com.android.settingslib.mobile.MobileMappings
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.broadcast.broadcastDispatcherContext
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.fakeFeatureFlagsClassic
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosTestScope
+import com.android.systemui.kairos.combine
+import com.android.systemui.kairos.kairos
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.runKairosTest
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.log.LogBuffer
+import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.statusbar.connectivity.WifiPickerTrackerFactory
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.airplaneModeRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepositoryKairosImpl
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.subscriptionManager
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.subscriptionManagerProxy
+import com.android.systemui.statusbar.pipeline.mobile.util.fake
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlots
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepositoryImpl
+import com.android.systemui.statusbar.pipeline.shared.data.repository.connectivityRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.prod.WifiRepositoryImpl
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.wifiRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.user.data.repository.userRepository
+import com.android.systemui.util.concurrency.FakeExecutor
+import com.android.systemui.util.time.FakeSystemClock
+import com.android.wifitrackerlib.MergedCarrierEntry
+import com.android.wifitrackerlib.WifiEntry
+import com.android.wifitrackerlib.WifiPickerTracker
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
+import java.util.UUID
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.runCurrent
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.Mockito
+import org.mockito.Mockito.verify
+import org.mockito.kotlin.any
+import org.mockito.kotlin.argumentCaptor
+import org.mockito.kotlin.doAnswer
+import org.mockito.kotlin.doReturn
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.stub
+import org.mockito.kotlin.whenever
+
+@OptIn(ExperimentalKairosApi::class)
+@SmallTest
+// This is required because our [SubscriptionManager.OnSubscriptionsChangedListener] uses a looper
+// to run the callback and this makes the looper place nicely with TestScope etc.
+@TestableLooper.RunWithLooper
+@RunWith(AndroidJUnit4::class)
+class MobileConnectionsRepositoryKairosTest : SysuiTestCase() {
+
+    private val Kosmos.wifiManager: WifiManager by Fixture { mock {} }
+    private val Kosmos.wifiPickerTrackerFactory: WifiPickerTrackerFactory by Fixture {
+        mock {
+            on { create(any(), any(), wifiPickerTrackerCallback.capture(), any()) } doReturn
+                wifiPickerTracker
+        }
+    }
+    private val Kosmos.wifiPickerTracker: WifiPickerTracker by Fixture { mock {} }
+    private val Kosmos.wifiTableLogBuffer by Fixture { logcatTableLogBuffer(this, "wifiTableLog") }
+
+    private val mainExecutor = FakeExecutor(FakeSystemClock())
+    private val wifiLogBuffer = LogBuffer("wifi", maxSize = 100, logcatEchoTracker = mock())
+    private val wifiPickerTrackerCallback =
+        argumentCaptor<WifiPickerTracker.WifiPickerTrackerCallback>()
+    private val vcnTransportInfo = VcnTransportInfo.Builder().build()
+
+    private val Kosmos.underTest
+        get() = mobileConnectionsRepositoryKairosImpl
+
+    private val kosmos =
+        testKosmos().apply {
+            fakeFeatureFlagsClassic.set(Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO, true)
+            broadcastDispatcherContext = testableContext
+            connectivityRepository =
+                ConnectivityRepositoryImpl(
+                    connectivityManager,
+                    ConnectivitySlots(applicationContext),
+                    applicationContext,
+                    mock(),
+                    mock(),
+                    applicationCoroutineScope,
+                    mock(),
+                )
+            wifiRepository =
+                WifiRepositoryImpl(
+                    applicationContext,
+                    userRepository,
+                    applicationCoroutineScope,
+                    mainExecutor,
+                    testDispatcher,
+                    wifiPickerTrackerFactory,
+                    wifiManager,
+                    wifiLogBuffer,
+                    wifiTableLogBuffer,
+                )
+            subscriptionManager.stub {
+                // For convenience, set up the subscription info callbacks
+                on { getActiveSubscriptionInfo(anyInt()) } doAnswer
+                    { invocation ->
+                        when (invocation.getArgument(0) as Int) {
+                            1 -> SUB_1
+                            2 -> SUB_2
+                            3 -> SUB_3
+                            4 -> SUB_4
+                            else -> null
+                        }
+                    }
+            }
+            telephonyManager.stub {
+                on { simOperatorName } doReturn ""
+                // Set up so the individual connection repositories
+                on { createForSubscriptionId(anyInt()) } doAnswer
+                    { invocation ->
+                        telephonyManager.stub {
+                            on { subscriptionId } doReturn invocation.getArgument(0)
+                        }
+                    }
+            }
+            testScope.runCurrent()
+        }
+
+    private fun runTest(block: suspend KairosTestScope.() -> Unit) =
+        kosmos.run { runKairosTest { block() } }
+
+    @Test
+    fun testSubscriptions_initiallyEmpty() = runTest {
+        assertThat(underTest.subscriptions.collectLastValue().value)
+            .isEqualTo(listOf<SubscriptionModel>())
+    }
+
+    @Test
+    fun testSubscriptions_listUpdates() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_1, SUB_2)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2))
+    }
+
+    @Test
+    fun testSubscriptions_removingSub_updatesList() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        // WHEN 2 networks show up
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_1, SUB_2)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        // WHEN one network is removed
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_2)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        // THEN the subscriptions list represents the newest change
+        assertThat(latest).isEqualTo(listOf(MODEL_2))
+    }
+
+    @Test
+    fun subscriptions_subIsOnlyNtn_modelHasExclusivelyNtnTrue() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        val onlyNtnSub =
+            mock<SubscriptionInfo> {
+                on { isOnlyNonTerrestrialNetwork } doReturn true
+                on { subscriptionId } doReturn 45
+                on { groupUuid } doReturn GROUP_1
+                on { carrierName } doReturn "NTN only"
+                on { profileClass } doReturn PROFILE_CLASS_UNSET
+            }
+
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(onlyNtnSub)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        assertThat(latest).hasSize(1)
+        assertThat(latest!![0].isExclusivelyNonTerrestrial).isTrue()
+    }
+
+    @Test
+    fun subscriptions_subIsNotOnlyNtn_modelHasExclusivelyNtnFalse() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        val notOnlyNtnSub =
+            mock<SubscriptionInfo> {
+                on { isOnlyNonTerrestrialNetwork } doReturn false
+                on { subscriptionId } doReturn 45
+                on { groupUuid } doReturn GROUP_1
+                on { carrierName } doReturn "NTN only"
+                on { profileClass } doReturn PROFILE_CLASS_UNSET
+            }
+
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(notOnlyNtnSub)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        assertThat(latest).hasSize(1)
+        assertThat(latest!![0].isExclusivelyNonTerrestrial).isFalse()
+    }
+
+    @Test
+    fun testSubscriptions_carrierMergedOnly_listHasCarrierMerged() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        setWifiState(isCarrierMerged = true)
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_CM)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        assertThat(latest).isEqualTo(listOf(MODEL_CM))
+    }
+
+    @Test
+    fun testSubscriptions_carrierMergedAndOther_listHasBothWithCarrierMergedLast() = runTest {
+        val latest by underTest.subscriptions.collectLastValue()
+
+        setWifiState(isCarrierMerged = true)
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_1, SUB_2, SUB_CM)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        assertThat(latest).isEqualTo(listOf(MODEL_1, MODEL_2, MODEL_CM))
+    }
+
+    @Test
+    fun testActiveDataSubscriptionId_initialValueIsNull() = runTest {
+        assertThat(underTest.activeMobileDataSubscriptionId.collectLastValue().value)
+            .isEqualTo(null)
+    }
+
+    @Test
+    fun testActiveDataSubscriptionId_updates() = runTest {
+        val active by underTest.activeMobileDataSubscriptionId.collectLastValue()
+        testScope.runCurrent()
+
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+        assertThat(active).isEqualTo(SUB_2_ID)
+    }
+
+    @Test
+    fun activeSubId_nullIfInvalidSubIdIsReceived() = runTest {
+        val latest by underTest.activeMobileDataSubscriptionId.collectLastValue()
+        testScope.runCurrent()
+
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+        assertThat(latest).isNotNull()
+
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID)
+
+        assertThat(latest).isNull()
+    }
+
+    @Test
+    fun activeRepo_initiallyNull() = runTest {
+        assertThat(underTest.activeMobileDataRepository.collectLastValue().value).isNull()
+    }
+
+    @Test
+    fun activeRepo_updatesWithActiveDataId() = runTest {
+        val latest by underTest.activeMobileDataRepository.collectLastValue()
+        testScope.runCurrent()
+
+        // GIVEN the subscription list is then updated which includes the active data sub id
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_2)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+        testScope.runCurrent()
+
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+
+        assertThat(latest?.subId).isEqualTo(SUB_2_ID)
+    }
+
+    @Test
+    fun activeRepo_nullIfActiveDataSubIdBecomesInvalid() = runTest {
+        val latest by underTest.activeMobileDataRepository.collectLastValue()
+        testScope.runCurrent()
+
+        // GIVEN the subscription list is then updated which includes the active data sub id
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_2)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+        testScope.runCurrent()
+
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+        testScope.runCurrent()
+
+        assertThat(latest).isNotNull()
+
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(INVALID_SUBSCRIPTION_ID)
+        testScope.runCurrent()
+
+        assertThat(latest).isNull()
+    }
+
+    @Test
+    /** Regression test for b/268146648. */
+    fun activeSubIdIsSetBeforeSubscriptionsAreUpdated_doesNotThrow() = runTest {
+        val activeRepo by underTest.activeMobileDataRepository.collectLastValue()
+        val subscriptions by underTest.subscriptions.collectLastValue()
+        testScope.runCurrent()
+
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+        testScope.runCurrent()
+
+        assertThat(subscriptions).isEmpty()
+        assertThat(activeRepo).isNull()
+    }
+
+    @Test
+    fun getRepoForSubId_activeDataSubIdIsRequestedBeforeSubscriptionsUpdate() = runTest {
+        underTest
+
+        var latestActiveRepo: MobileConnectionRepositoryKairos? = null
+        testScope.backgroundScope.launch {
+            kairos.activateSpec {
+                underTest.activeMobileDataSubscriptionId
+                    .combine(underTest.mobileConnectionsBySubId) { id, conns ->
+                        id?.let { conns[id] }
+                    }
+                    .observe {
+                        if (it != null) {
+                            latestActiveRepo = it
+                        }
+                    }
+            }
+        }
+
+        val latestSubscriptions by underTest.subscriptions.collectLastValue()
+        testScope.runCurrent()
+
+        // Active data subscription id is sent, but no subscription change has been posted yet
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+        testScope.runCurrent()
+
+        // Subscriptions list is empty
+        assertThat(latestSubscriptions).isEmpty()
+
+        // getRepoForSubId does not throw
+        assertThat(latestActiveRepo).isNull()
+    }
+
+    @Test
+    fun activeDataSentBeforeSubscriptionList_subscriptionReusesActiveDataRepo() = runTest {
+        val activeRepo by underTest.activeMobileDataRepository.collectLastValue()
+        testScope.runCurrent()
+
+        // GIVEN active repo is updated before the subscription list updates
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(SUB_2_ID)
+        testScope.runCurrent()
+
+        assertThat(activeRepo).isNull()
+
+        // GIVEN the subscription list is then updated which includes the active data sub id
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_2)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+        testScope.runCurrent()
+
+        // WHEN requesting a connection repository for the subscription
+        val newRepo =
+            kairos.transact { underTest.mobileConnectionsBySubId.map { it[SUB_2_ID] }.sample() }
+
+        // THEN the newly request repo has been cached and reused
+        assertThat(activeRepo).isSameInstanceAs(newRepo)
+    }
+
+    @Test
+    fun testConnectionRepository_validSubId_isCached() = runTest {
+        underTest
+
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_1)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        val repo1 by underTest.mobileConnectionsBySubId.map { it[SUB_1_ID] }.collectLastValue()
+        val repo2 by underTest.mobileConnectionsBySubId.map { it[SUB_1_ID] }.collectLastValue()
+
+        assertThat(repo1).isNotNull()
+        assertThat(repo1).isSameInstanceAs(repo2)
+    }
+
+    @Test
+    fun testConnectionRepository_carrierMergedSubId_isCached() = runTest {
+        underTest
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+        setWifiState(isCarrierMerged = true)
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_CM)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        val repo1 by underTest.mobileConnectionsBySubId.map { it[SUB_CM_ID] }.collectLastValue()
+        val repo2 by underTest.mobileConnectionsBySubId.map { it[SUB_CM_ID] }.collectLastValue()
+
+        assertThat(repo1).isNotNull()
+        assertThat(repo1).isSameInstanceAs(repo2)
+    }
+
+    @SuppressLint("UnspecifiedRegisterReceiverFlag")
+    @Test
+    fun testDeviceEmergencyCallState_eagerlyChecksState() = runTest {
+        val latest by underTest.isDeviceEmergencyCallCapable.collectLastValue()
+
+        // Value starts out false
+        assertThat(latest).isFalse()
+        telephonyManager.stub { on { activeModemCount } doReturn 1 }
+        whenever(telephonyManager.getServiceStateForSlot(any())).thenAnswer { _ ->
+            ServiceState().apply { isEmergencyOnly = true }
+        }
+
+        // WHEN an appropriate intent gets sent out
+        val intent = serviceStateIntent(subId = -1)
+        broadcastDispatcher.sendIntentToMatchingReceiversOnly(applicationContext, intent)
+        testScope.runCurrent()
+
+        // THEN the repo's state is updated despite no listeners
+        assertThat(latest).isEqualTo(true)
+    }
+
+    @Test
+    fun testDeviceEmergencyCallState_aggregatesAcrossSlots_oneTrue() = runTest {
+        val latest by underTest.isDeviceEmergencyCallCapable.collectLastValue()
+
+        // GIVEN there are multiple slots
+        telephonyManager.stub { on { activeModemCount } doReturn 4 }
+        // GIVEN only one of them reports ECM
+        whenever(telephonyManager.getServiceStateForSlot(any())).thenAnswer { invocation ->
+            when (invocation.getArgument(0) as Int) {
+                0 -> ServiceState().apply { isEmergencyOnly = false }
+                1 -> ServiceState().apply { isEmergencyOnly = false }
+                2 -> ServiceState().apply { isEmergencyOnly = true }
+                3 -> ServiceState().apply { isEmergencyOnly = false }
+                else -> null
+            }
+        }
+
+        // GIVEN a broadcast goes out for the appropriate subID
+        val intent = serviceStateIntent(subId = -1)
+        broadcastDispatcher.sendIntentToMatchingReceiversOnly(applicationContext, intent)
+        testScope.runCurrent()
+
+        // THEN the device is in ECM, because one of the service states is
+        assertThat(latest).isTrue()
+    }
+
+    @Test
+    fun testDeviceEmergencyCallState_aggregatesAcrossSlots_allFalse() = runTest {
+        val latest by underTest.isDeviceEmergencyCallCapable.collectLastValue()
+
+        // GIVEN there are multiple slots
+        telephonyManager.stub { on { activeModemCount } doReturn 4 }
+        // GIVEN only one of them reports ECM
+        whenever(telephonyManager.getServiceStateForSlot(any())).thenAnswer { invocation ->
+            when (invocation.getArgument(0) as Int) {
+                0 -> ServiceState().apply { isEmergencyOnly = false }
+                1 -> ServiceState().apply { isEmergencyOnly = false }
+                2 -> ServiceState().apply { isEmergencyOnly = false }
+                3 -> ServiceState().apply { isEmergencyOnly = false }
+                else -> null
+            }
+        }
+
+        // GIVEN a broadcast goes out for the appropriate subID
+        val intent = serviceStateIntent(subId = -1)
+        broadcastDispatcher.sendIntentToMatchingReceiversOnly(applicationContext, intent)
+        testScope.runCurrent()
+
+        // THEN the device is in ECM, because one of the service states is
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun testConnectionCache_clearsInvalidSubscriptions() = runTest {
+        underTest
+
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_1, SUB_2)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        val repoCache by underTest.mobileConnectionsBySubId.collectLastValue()
+
+        assertThat(repoCache?.keys).containsExactly(SUB_1_ID, SUB_2_ID)
+
+        // SUB_2 disappears
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_1)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        assertThat(repoCache?.keys).containsExactly(SUB_1_ID)
+    }
+
+    @Test
+    fun testConnectionCache_clearsInvalidSubscriptions_includingCarrierMerged() = runTest {
+        underTest
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, WIFI_NETWORK_CAPS_CM)
+        setWifiState(isCarrierMerged = true)
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_1, SUB_2, SUB_CM)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        val repoCache by underTest.mobileConnectionsBySubId.collectLastValue()
+
+        assertThat(repoCache?.keys).containsExactly(SUB_1_ID, SUB_2_ID, SUB_CM_ID)
+
+        // SUB_2 and SUB_CM disappear
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_1)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        assertThat(repoCache?.keys).containsExactly(SUB_1_ID)
+    }
+
+    /** Regression test for b/261706421 */
+    @Test
+    fun testConnectionsCache_clearMultipleSubscriptionsAtOnce_doesNotThrow() = runTest {
+        underTest
+
+        subscriptionManager.stub {
+            on { completeActiveSubscriptionInfoList } doReturn listOf(SUB_1, SUB_2)
+        }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        val repoCache by underTest.mobileConnectionsBySubId.collectLastValue()
+
+        assertThat(repoCache?.keys).containsExactly(SUB_1_ID, SUB_2_ID)
+
+        // All subscriptions disappear
+        subscriptionManager.stub { on { completeActiveSubscriptionInfoList } doReturn listOf() }
+        getSubscriptionCallback().onSubscriptionsChanged()
+
+        assertThat(repoCache).isEmpty()
+    }
+
+    @Test
+    fun testDefaultDataSubId_updatesOnBroadcast() = runTest {
+        val latest by underTest.defaultDataSubId.collectLastValue()
+
+        assertThat(latest).isEqualTo(null)
+
+        val intent2 =
+            Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+                .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_2_ID)
+        broadcastDispatcher.sendIntentToMatchingReceiversOnly(applicationContext, intent2)
+
+        assertThat(latest).isEqualTo(SUB_2_ID)
+
+        val intent1 =
+            Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+                .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_1_ID)
+        broadcastDispatcher.sendIntentToMatchingReceiversOnly(applicationContext, intent1)
+
+        assertThat(latest).isEqualTo(SUB_1_ID)
+    }
+
+    @Test
+    fun defaultDataSubId_fetchesInitialValueOnStart() = runTest {
+        subscriptionManagerProxy.fake.defaultDataSubId = 2
+        val latest by underTest.defaultDataSubId.collectLastValue()
+
+        assertThat(latest).isEqualTo(2)
+    }
+
+    @Test
+    fun mobileIsDefault_startsAsFalse() = runTest {
+        assertThat(underTest.mobileIsDefault.collectLastValue().value).isFalse()
+    }
+
+    @Test
+    fun mobileIsDefault_capsHaveCellular_isDefault() = runTest {
+        val caps =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_CELLULAR) } doReturn true
+            }
+
+        val latest by underTest.mobileIsDefault.collectLastValue()
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+        assertThat(latest).isTrue()
+    }
+
+    @Test
+    fun mobileIsDefault_capsDoNotHaveCellular_isNotDefault() = runTest {
+        val caps =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_CELLULAR) } doReturn false
+            }
+
+        val latest by underTest.mobileIsDefault.collectLastValue()
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun mobileIsDefault_carrierMergedViaMobile_isDefault() = runTest {
+        val carrierMergedInfo = mock<WifiInfo> { on { isCarrierMerged } doReturn true }
+        val caps =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_CELLULAR) } doReturn true
+                on { transportInfo } doReturn carrierMergedInfo
+            }
+
+        val latest by underTest.mobileIsDefault.collectLastValue()
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+        assertThat(latest).isTrue()
+    }
+
+    @Test
+    fun mobileIsDefault_wifiDefault_mobileNotDefault() = runTest {
+        val caps =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_WIFI) } doReturn true
+            }
+
+        val latest by underTest.mobileIsDefault.collectLastValue()
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun mobileIsDefault_ethernetDefault_mobileNotDefault() = runTest {
+        val caps =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_ETHERNET) } doReturn true
+            }
+
+        val latest by underTest.mobileIsDefault.collectLastValue()
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+        assertThat(latest).isFalse()
+    }
+
+    /** Regression test for b/272586234. */
+    @Test
+    fun hasCarrierMergedConnection_carrierMergedViaWifi_isTrue() = runTest {
+        val carrierMergedInfo =
+            mock<WifiInfo> {
+                on { isCarrierMerged } doReturn true
+                on { isPrimary } doReturn true
+            }
+        val caps =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_WIFI) } doReturn true
+                on { transportInfo } doReturn carrierMergedInfo
+            }
+
+        val latest by underTest.hasCarrierMergedConnection.collectLastValue()
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+        setWifiState(isCarrierMerged = true)
+
+        assertThat(latest).isTrue()
+    }
+
+    @Test
+    fun hasCarrierMergedConnection_carrierMergedViaMobile_isTrue() = runTest {
+        val carrierMergedInfo =
+            mock<WifiInfo> {
+                on { isCarrierMerged } doReturn true
+                on { isPrimary } doReturn true
+            }
+        val caps =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_CELLULAR) } doReturn true
+                on { transportInfo } doReturn carrierMergedInfo
+            }
+
+        val latest by underTest.hasCarrierMergedConnection.collectLastValue()
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+        setWifiState(isCarrierMerged = true)
+
+        assertThat(latest).isTrue()
+    }
+
+    private fun KairosTestScope.newWifiNetwork(wifiInfo: WifiInfo): Network {
+        val network = mock<Network>()
+        val capabilities =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_WIFI) } doReturn true
+                on { transportInfo } doReturn wifiInfo
+            }
+        connectivityManager.stub { on { getNetworkCapabilities(network) } doReturn capabilities }
+        return network
+    }
+
+    /** Regression test for b/272586234. */
+    @Test
+    fun hasCarrierMergedConnection_carrierMergedViaWifiWithVcnTransport_isTrue() = runTest {
+        val carrierMergedInfo =
+            mock<WifiInfo> {
+                on { isCarrierMerged } doReturn true
+                on { isPrimary } doReturn true
+            }
+        val underlyingWifi = newWifiNetwork(carrierMergedInfo)
+        val caps =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_WIFI) } doReturn true
+                on { transportInfo } doReturn vcnTransportInfo
+                on { underlyingNetworks } doReturn listOf(underlyingWifi)
+            }
+
+        val latest by underTest.hasCarrierMergedConnection.collectLastValue()
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+        setWifiState(isCarrierMerged = true)
+
+        assertThat(latest).isTrue()
+    }
+
+    @Test
+    fun hasCarrierMergedConnection_carrierMergedViaMobileWithVcnTransport_isTrue() = runTest {
+        val carrierMergedInfo =
+            mock<WifiInfo> {
+                on { isCarrierMerged } doReturn true
+                on { isPrimary } doReturn true
+            }
+        val underlyingWifi = newWifiNetwork(carrierMergedInfo)
+        val caps =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_CELLULAR) } doReturn true
+                on { transportInfo } doReturn vcnTransportInfo
+                on { underlyingNetworks } doReturn listOf(underlyingWifi)
+            }
+
+        val latest by underTest.hasCarrierMergedConnection.collectLastValue()
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+        setWifiState(isCarrierMerged = true)
+
+        assertThat(latest).isTrue()
+    }
+
+    @Test
+    fun hasCarrierMergedConnection_isCarrierMergedViaUnderlyingWifi_isTrue() = runTest {
+        val latest by underTest.hasCarrierMergedConnection.collectLastValue()
+
+        val underlyingNetwork = mock<Network>()
+        val carrierMergedInfo =
+            mock<WifiInfo> {
+                on { isCarrierMerged } doReturn true
+                on { isPrimary } doReturn true
+            }
+        val underlyingWifiCapabilities =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_WIFI) } doReturn true
+                on { transportInfo } doReturn carrierMergedInfo
+            }
+        connectivityManager.stub {
+            on { getNetworkCapabilities(underlyingNetwork) } doReturn underlyingWifiCapabilities
+        }
+
+        // WHEN the main capabilities have an underlying carrier merged network via WIFI
+        // transport and WifiInfo
+        val mainCapabilities =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_CELLULAR) } doReturn true
+                on { transportInfo } doReturn null
+                on { underlyingNetworks } doReturn listOf(underlyingNetwork)
+            }
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
+        setWifiState(isCarrierMerged = true)
+
+        // THEN there's a carrier merged connection
+        assertThat(latest).isTrue()
+    }
+
+    @Test
+    fun hasCarrierMergedConnection_isCarrierMergedViaUnderlyingCellular_isTrue() = runTest {
+        val latest by underTest.hasCarrierMergedConnection.collectLastValue()
+
+        val underlyingCarrierMergedNetwork = mock<Network>()
+        val carrierMergedInfo =
+            mock<WifiInfo> {
+                on { isCarrierMerged } doReturn true
+                on { isPrimary } doReturn true
+            }
+
+        // The Wifi network that is under the VCN network
+        val physicalWifiNetwork = newWifiNetwork(carrierMergedInfo)
+
+        val underlyingCapabilities =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_CELLULAR) } doReturn true
+                on { transportInfo } doReturn vcnTransportInfo
+                on { underlyingNetworks } doReturn listOf(physicalWifiNetwork)
+            }
+        connectivityManager.stub {
+            on { getNetworkCapabilities(underlyingCarrierMergedNetwork) } doReturn
+                underlyingCapabilities
+        }
+
+        // WHEN the main capabilities have an underlying carrier merged network via CELLULAR
+        // transport and VcnTransportInfo
+        val mainCapabilities =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_CELLULAR) } doReturn true
+                on { transportInfo } doReturn null
+                on { underlyingNetworks } doReturn listOf(underlyingCarrierMergedNetwork)
+            }
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, mainCapabilities)
+        setWifiState(isCarrierMerged = true)
+
+        // THEN there's a carrier merged connection
+        assertThat(latest).isTrue()
+    }
+
+    /** Regression test for b/272586234. */
+    @Test
+    fun hasCarrierMergedConnection_defaultIsWifiNotCarrierMerged_wifiRepoIsCarrierMerged_isTrue() =
+        runTest {
+            val latest by underTest.hasCarrierMergedConnection.collectLastValue()
+
+            // WHEN the default callback is TRANSPORT_WIFI but not carrier merged
+            val carrierMergedInfo = mock<WifiInfo> { on { isCarrierMerged } doReturn false }
+            val caps =
+                Mockito.mock(NetworkCapabilities::class.java).stub {
+                    on { hasTransport(TRANSPORT_WIFI) } doReturn true
+                    on { transportInfo } doReturn carrierMergedInfo
+                }
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+            // BUT the wifi repo has gotten updates that it *is* carrier merged
+            setWifiState(isCarrierMerged = true)
+
+            // THEN hasCarrierMergedConnection is true
+            assertThat(latest).isTrue()
+        }
+
+    /** Regression test for b/278618530. */
+    @Test
+    fun hasCarrierMergedConnection_defaultIsCellular_wifiRepoIsCarrierMerged_isFalse() = runTest {
+        val latest by underTest.hasCarrierMergedConnection.collectLastValue()
+
+        // WHEN the default callback is TRANSPORT_CELLULAR and not carrier merged
+        val caps =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_CELLULAR) } doReturn true
+                on { transportInfo } doReturn null
+            }
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+        // BUT the wifi repo has gotten updates that it *is* carrier merged
+        setWifiState(isCarrierMerged = true)
+
+        // THEN hasCarrierMergedConnection is **false** (The default network being CELLULAR
+        // takes precedence over the wifi network being carrier merged.)
+        assertThat(latest).isFalse()
+    }
+
+    /** Regression test for b/278618530. */
+    @Test
+    fun hasCarrierMergedConnection_defaultCellular_wifiIsCarrierMerged_airplaneMode_isTrue() =
+        runTest {
+            val latest by underTest.hasCarrierMergedConnection.collectLastValue()
+
+            // WHEN the default callback is TRANSPORT_CELLULAR and not carrier merged
+            val caps =
+                Mockito.mock(NetworkCapabilities::class.java).stub {
+                    on { hasTransport(TRANSPORT_CELLULAR) } doReturn true
+                    on { transportInfo } doReturn null
+                }
+            getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+            // BUT the wifi repo has gotten updates that it *is* carrier merged
+            setWifiState(isCarrierMerged = true)
+            // AND we're in airplane mode
+            airplaneModeRepository.setIsAirplaneMode(true)
+
+            // THEN hasCarrierMergedConnection is true.
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun defaultConnectionIsValidated_startsAsFalse() = runTest {
+        assertThat(underTest.defaultConnectionIsValidated.collectLastValue().value).isFalse()
+    }
+
+    @Test
+    fun defaultConnectionIsValidated_capsHaveValidated_isValidated() = runTest {
+        val caps =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasCapability(NET_CAPABILITY_VALIDATED) } doReturn true
+            }
+
+        val latest by underTest.defaultConnectionIsValidated.collectLastValue()
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+        assertThat(latest).isTrue()
+    }
+
+    @Test
+    fun defaultConnectionIsValidated_capsHaveNotValidated_isNotValidated() = runTest {
+        val caps =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasCapability(NET_CAPABILITY_VALIDATED) } doReturn false
+            }
+
+        val latest by underTest.defaultConnectionIsValidated.collectLastValue()
+
+        getDefaultNetworkCallback().onCapabilitiesChanged(NETWORK, caps)
+
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun config_initiallyFromContext() = runTest {
+        overrideResource(R.bool.config_showMin3G, true)
+        val configFromContext = MobileMappings.Config.readConfig(applicationContext)
+        assertThat(configFromContext.showAtLeast3G).isTrue()
+
+        val latest by underTest.defaultDataSubRatConfig.collectLastValue()
+
+        assertTrue(latest!!.areEqual(configFromContext))
+        assertTrue(latest!!.showAtLeast3G)
+    }
+
+    @Test
+    fun config_subIdChangeEvent_updated() = runTest {
+        val latest by underTest.defaultDataSubRatConfig.collectLastValue()
+
+        assertThat(latest!!.showAtLeast3G).isFalse()
+
+        overrideResource(R.bool.config_showMin3G, true)
+        val configFromContext = MobileMappings.Config.readConfig(applicationContext)
+        assertThat(configFromContext.showAtLeast3G).isTrue()
+
+        // WHEN the change event is fired
+        val intent =
+            Intent(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+                .putExtra(PhoneConstants.SUBSCRIPTION_KEY, SUB_1_ID)
+        broadcastDispatcher.sendIntentToMatchingReceiversOnly(applicationContext, intent)
+
+        // THEN the config is updated
+        assertThat(latest?.areEqual(configFromContext)).isEqualTo(true)
+        assertThat(latest?.showAtLeast3G).isEqualTo(true)
+    }
+
+    @Test
+    fun config_carrierConfigChangeEvent_updated() = runTest {
+        val latest by underTest.defaultDataSubRatConfig.collectLastValue()
+
+        assertThat(latest!!.showAtLeast3G).isFalse()
+
+        overrideResource(R.bool.config_showMin3G, true)
+        val configFromContext = MobileMappings.Config.readConfig(applicationContext)
+        assertThat(configFromContext.showAtLeast3G).isTrue()
+
+        // WHEN the change event is fired
+        broadcastDispatcher.sendIntentToMatchingReceiversOnly(
+            applicationContext,
+            Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED),
+        )
+
+        // THEN the config is updated
+        assertThat(latest?.areEqual(configFromContext)).isEqualTo(true)
+        assertThat(latest?.showAtLeast3G).isEqualTo(true)
+    }
+
+    @Test
+    fun carrierConfig_initialValueIsFetched() = runTest {
+        underTest
+        testScope.runCurrent()
+
+        // Value starts out false
+        assertThat(underTest.defaultDataSubRatConfig.sample().showAtLeast3G).isFalse()
+
+        overrideResource(R.bool.config_showMin3G, true)
+        val configFromContext = MobileMappings.Config.readConfig(applicationContext)
+        assertThat(configFromContext.showAtLeast3G).isTrue()
+
+        assertThat(broadcastDispatcher.numReceiversRegistered).isAtLeast(1)
+
+        // WHEN the change event is fired
+        broadcastDispatcher.sendIntentToMatchingReceiversOnly(
+            applicationContext,
+            Intent(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED),
+        )
+        testScope.runCurrent()
+
+        // WHEN collection starts AFTER the broadcast is sent out
+        val latest by underTest.defaultDataSubRatConfig.collectLastValue()
+
+        // THEN the config has the updated value
+        assertWithMessage("showAtLeast3G is false").that(latest!!.showAtLeast3G).isTrue()
+        assertWithMessage("not equal").that(latest!!.areEqual(configFromContext)).isTrue()
+    }
+
+    @Test
+    fun activeDataChange_inSameGroup_emitsUnit() = runTest {
+        var eventCount = 0
+        underTest
+        testScope.backgroundScope.launch {
+            kairos.activateSpec { underTest.activeSubChangedInGroupEvent.observe { eventCount++ } }
+        }
+        testScope.runCurrent()
+
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(SUB_3_ID_GROUPED)
+        testScope.runCurrent()
+
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(SUB_4_ID_GROUPED)
+        testScope.runCurrent()
+
+        assertThat(eventCount).isEqualTo(1)
+    }
+
+    @Test
+    fun activeDataChange_notInSameGroup_doesNotEmit() = runTest {
+        var eventCount = 0
+        underTest
+        testScope.backgroundScope.launch {
+            kairos.activateSpec { underTest.activeSubChangedInGroupEvent.observe { eventCount++ } }
+        }
+        testScope.runCurrent()
+
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(SUB_3_ID_GROUPED)
+        testScope.runCurrent()
+
+        getTelephonyCallbackForType<ActiveDataSubscriptionIdListener>(telephonyManager)
+            .onActiveDataSubscriptionIdChanged(SUB_1_ID)
+        testScope.runCurrent()
+
+        assertThat(eventCount).isEqualTo(0)
+    }
+
+    @Test
+    fun anySimSecure_propagatesStateFromKeyguardUpdateMonitor() = runTest {
+        val latest by underTest.isAnySimSecure.collectLastValue()
+        assertThat(latest).isFalse()
+
+        val updateMonitorCallback = argumentCaptor<KeyguardUpdateMonitorCallback>()
+        verify(keyguardUpdateMonitor).registerCallback(updateMonitorCallback.capture())
+
+        keyguardUpdateMonitor.stub { on { isSimPinSecure } doReturn true }
+        updateMonitorCallback.lastValue.onSimStateChanged(0, 0, 0)
+
+        assertThat(latest).isTrue()
+
+        keyguardUpdateMonitor.stub { on { isSimPinSecure } doReturn false }
+        updateMonitorCallback.lastValue.onSimStateChanged(0, 0, 0)
+
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun getIsAnySimSecure_delegatesCallToKeyguardUpdateMonitor() = runTest {
+        val anySimSecure by underTest.isAnySimSecure.collectLastValue()
+
+        assertThat(anySimSecure).isFalse()
+
+        keyguardUpdateMonitor.stub { on { isSimPinSecure } doReturn true }
+        argumentCaptor<KeyguardUpdateMonitorCallback>()
+            .apply { verify(keyguardUpdateMonitor).registerCallback(capture()) }
+            .lastValue
+            .onSimStateChanged(0, 0, 0)
+
+        assertThat(anySimSecure).isTrue()
+    }
+
+    @Test
+    fun noSubscriptionsInEcmMode_notInEcmMode() = runTest {
+        val latest by underTest.isInEcmMode.collectLastValue()
+        testScope.runCurrent()
+
+        assertThat(latest).isFalse()
+    }
+
+    @Test
+    fun someSubscriptionsInEcmMode_inEcmMode() = runTest {
+        val latest by underTest.isInEcmMode.collectLastValue()
+        testScope.runCurrent()
+
+        getTelephonyCallbackForType<EmergencyCallbackModeListener>(telephonyManager)
+            .onCallbackModeStarted(0, mock(), 0)
+
+        assertThat(latest).isTrue()
+    }
+
+    private fun KairosTestScope.getDefaultNetworkCallback(): ConnectivityManager.NetworkCallback {
+        testScope.runCurrent()
+        val callbackCaptor = argumentCaptor<ConnectivityManager.NetworkCallback>()
+        verify(connectivityManager).registerDefaultNetworkCallback(callbackCaptor.capture())
+        return callbackCaptor.lastValue
+    }
+
+    private fun KairosTestScope.setWifiState(isCarrierMerged: Boolean) {
+        if (isCarrierMerged) {
+            val mergedEntry =
+                mock<MergedCarrierEntry> {
+                    on { isPrimaryNetwork } doReturn true
+                    on { isDefaultNetwork } doReturn true
+                    on { subscriptionId } doReturn SUB_CM_ID
+                }
+            wifiPickerTracker.stub {
+                on { mergedCarrierEntry } doReturn mergedEntry
+                on { connectedWifiEntry } doReturn null
+            }
+        } else {
+            val wifiEntry =
+                mock<WifiEntry> {
+                    on { isPrimaryNetwork } doReturn true
+                    on { isDefaultNetwork } doReturn true
+                }
+            wifiPickerTracker.stub {
+                on { connectedWifiEntry } doReturn wifiEntry
+                on { mergedCarrierEntry } doReturn null
+            }
+        }
+        wifiPickerTrackerCallback.allValues.forEach { it.onWifiEntriesChanged() }
+    }
+
+    private fun KairosTestScope.getSubscriptionCallback(): OnSubscriptionsChangedListener {
+        testScope.runCurrent()
+        return argumentCaptor<OnSubscriptionsChangedListener>()
+            .apply {
+                verify(subscriptionManager).addOnSubscriptionsChangedListener(any(), capture())
+            }
+            .lastValue
+    }
+
+    companion object {
+        // Subscription 1
+        private const val SUB_1_ID = 1
+        private const val SUB_1_NAME = "Carrier $SUB_1_ID"
+        private val GROUP_1 = ParcelUuid(UUID.randomUUID())
+        private val SUB_1 =
+            mock<SubscriptionInfo> {
+                on { subscriptionId } doReturn SUB_1_ID
+                on { groupUuid } doReturn GROUP_1
+                on { carrierName } doReturn SUB_1_NAME
+                on { profileClass } doReturn PROFILE_CLASS_UNSET
+            }
+        private val MODEL_1 =
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                groupUuid = GROUP_1,
+                carrierName = SUB_1_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        // Subscription 2
+        private const val SUB_2_ID = 2
+        private const val SUB_2_NAME = "Carrier $SUB_2_ID"
+        private val GROUP_2 = ParcelUuid(UUID.randomUUID())
+        private val SUB_2 =
+            mock<SubscriptionInfo> {
+                on { subscriptionId } doReturn SUB_2_ID
+                on { groupUuid } doReturn GROUP_2
+                on { carrierName } doReturn SUB_2_NAME
+                on { profileClass } doReturn PROFILE_CLASS_UNSET
+            }
+        private val MODEL_2 =
+            SubscriptionModel(
+                subscriptionId = SUB_2_ID,
+                groupUuid = GROUP_2,
+                carrierName = SUB_2_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        // Subs 3 and 4 are considered to be in the same group ------------------------------------
+        private val GROUP_ID_3_4 = ParcelUuid(UUID.randomUUID())
+
+        // Subscription 3
+        private const val SUB_3_ID_GROUPED = 3
+        private val SUB_3 =
+            mock<SubscriptionInfo> {
+                on { subscriptionId } doReturn SUB_3_ID_GROUPED
+                on { groupUuid } doReturn GROUP_ID_3_4
+                on { profileClass } doReturn PROFILE_CLASS_UNSET
+            }
+
+        // Subscription 4
+        private const val SUB_4_ID_GROUPED = 4
+        private val SUB_4 =
+            mock<SubscriptionInfo> {
+                on { subscriptionId } doReturn SUB_4_ID_GROUPED
+                on { groupUuid } doReturn GROUP_ID_3_4
+                on { profileClass } doReturn PROFILE_CLASS_UNSET
+            }
+
+        // Subs 3 and 4 are considered to be in the same group ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+
+        private const val NET_ID = 123
+        private val NETWORK = mock<Network> { on { getNetId() } doReturn NET_ID }
+
+        // Carrier merged subscription
+        private const val SUB_CM_ID = 5
+        private const val SUB_CM_NAME = "Carrier $SUB_CM_ID"
+        private val SUB_CM =
+            mock<SubscriptionInfo> {
+                on { subscriptionId } doReturn SUB_CM_ID
+                on { carrierName } doReturn SUB_CM_NAME
+                on { profileClass } doReturn PROFILE_CLASS_UNSET
+            }
+        private val MODEL_CM =
+            SubscriptionModel(
+                subscriptionId = SUB_CM_ID,
+                carrierName = SUB_CM_NAME,
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        private val WIFI_INFO_CM =
+            mock<WifiInfo> {
+                on { isPrimary } doReturn true
+                on { isCarrierMerged } doReturn true
+                on { subscriptionId } doReturn SUB_CM_ID
+            }
+        private val WIFI_NETWORK_CAPS_CM =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_WIFI) } doReturn true
+                on { transportInfo } doReturn WIFI_INFO_CM
+                on { hasCapability(NET_CAPABILITY_VALIDATED) } doReturn true
+            }
+
+        private val WIFI_INFO_ACTIVE =
+            mock<WifiInfo> {
+                on { isPrimary } doReturn true
+                on { isCarrierMerged } doReturn false
+            }
+
+        private val WIFI_NETWORK_CAPS_ACTIVE =
+            Mockito.mock(NetworkCapabilities::class.java).stub {
+                on { hasTransport(TRANSPORT_WIFI) } doReturn true
+                on { transportInfo } doReturn WIFI_INFO_ACTIVE
+                on { hasCapability(NET_CAPABILITY_VALIDATED) } doReturn true
+            }
+
+        /**
+         * To properly mimic telephony manager, create a service state, and then turn it into an
+         * intent
+         */
+        private fun serviceStateIntent(subId: Int): Intent {
+            return Intent(Intent.ACTION_SERVICE_STATE).apply {
+                putExtra(SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX, subId)
+            }
+        }
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosTest.kt
new file mode 100644
index 0000000..c89dc57
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairosTest.kt
@@ -0,0 +1,868 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
+
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
+import android.telephony.CellSignalStrength
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
+import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.coroutines.collectLastValue
+import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.CarrierMergedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FIVE_G_OVERRIDE
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.FOUR_G
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.FakeMobileIconsInteractor.Companion.THREE_G
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.testKosmos
+import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.flow.launchIn
+import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.ArgumentMatchers.anyInt
+import org.mockito.ArgumentMatchers.anyString
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MobileIconInteractorKairosTest : SysuiTestCase() {
+    private val kosmos = testKosmos()
+
+    private lateinit var underTest: MobileIconInteractorKairos
+    private val mobileMappingsProxy = FakeMobileMappingsProxy()
+    private val mobileIconsInteractor = FakeMobileIconsInteractor(mobileMappingsProxy, mock())
+
+    private val connectionRepository =
+        FakeMobileConnectionRepository(
+            SUB_1_ID,
+            logcatTableLogBuffer(kosmos, "MobileIconInteractorTest"),
+        )
+
+    private val testDispatcher = UnconfinedTestDispatcher()
+    private val testScope = TestScope(testDispatcher)
+
+    @Before
+    fun setUp() {
+        underTest = createInteractor()
+
+        mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = true
+        connectionRepository.isInService.value = true
+    }
+
+    @Test
+    fun gsm_usesGsmLevel() =
+        testScope.runTest {
+            connectionRepository.isGsm.value = true
+            connectionRepository.primaryLevel.value = GSM_LEVEL
+            connectionRepository.cdmaLevel.value = CDMA_LEVEL
+
+            var latest: Int? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
+
+            assertThat(latest).isEqualTo(GSM_LEVEL)
+
+            job.cancel()
+        }
+
+    @Test
+    fun gsm_alwaysShowCdmaTrue_stillUsesGsmLevel() =
+        testScope.runTest {
+            connectionRepository.isGsm.value = true
+            connectionRepository.primaryLevel.value = GSM_LEVEL
+            connectionRepository.cdmaLevel.value = CDMA_LEVEL
+            mobileIconsInteractor.alwaysUseCdmaLevel.value = true
+
+            var latest: Int? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
+
+            assertThat(latest).isEqualTo(GSM_LEVEL)
+
+            job.cancel()
+        }
+
+    @Test
+    fun notGsm_level_default_unknown() =
+        testScope.runTest {
+            connectionRepository.isGsm.value = false
+
+            var latest: Int? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
+
+            assertThat(latest).isEqualTo(CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN)
+            job.cancel()
+        }
+
+    @Test
+    fun notGsm_alwaysShowCdmaTrue_usesCdmaLevel() =
+        testScope.runTest {
+            connectionRepository.isGsm.value = false
+            connectionRepository.primaryLevel.value = GSM_LEVEL
+            connectionRepository.cdmaLevel.value = CDMA_LEVEL
+            mobileIconsInteractor.alwaysUseCdmaLevel.value = true
+
+            var latest: Int? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
+
+            assertThat(latest).isEqualTo(CDMA_LEVEL)
+
+            job.cancel()
+        }
+
+    @Test
+    fun notGsm_alwaysShowCdmaFalse_usesPrimaryLevel() =
+        testScope.runTest {
+            connectionRepository.isGsm.value = false
+            connectionRepository.primaryLevel.value = GSM_LEVEL
+            connectionRepository.cdmaLevel.value = CDMA_LEVEL
+            mobileIconsInteractor.alwaysUseCdmaLevel.value = false
+
+            var latest: Int? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it.level }.launchIn(this)
+
+            assertThat(latest).isEqualTo(GSM_LEVEL)
+
+            job.cancel()
+        }
+
+    @Test
+    fun numberOfLevels_comesFromRepo_whenApplicable() =
+        testScope.runTest {
+            var latest: Int? = null
+            val job =
+                underTest.signalLevelIcon
+                    .onEach { latest = (it as? SignalIconModel.Cellular)?.numberOfLevels }
+                    .launchIn(this)
+
+            connectionRepository.numberOfLevels.value = 5
+            assertThat(latest).isEqualTo(5)
+
+            connectionRepository.numberOfLevels.value = 4
+            assertThat(latest).isEqualTo(4)
+
+            job.cancel()
+        }
+
+    @Test
+    fun inflateSignalStrength_arbitrarilyAddsOneToTheReportedLevel() =
+        testScope.runTest {
+            connectionRepository.inflateSignalStrength.value = false
+            val latest by collectLastValue(underTest.signalLevelIcon)
+
+            connectionRepository.primaryLevel.value = 4
+            assertThat(latest!!.level).isEqualTo(4)
+
+            connectionRepository.inflateSignalStrength.value = true
+            connectionRepository.primaryLevel.value = 4
+
+            // when INFLATE_SIGNAL_STRENGTH is true, we add 1 to the reported signal level
+            assertThat(latest!!.level).isEqualTo(5)
+        }
+
+    @Test
+    fun networkSlice_configOn_hasPrioritizedCaps_showsSlice() =
+        testScope.runTest {
+            connectionRepository.allowNetworkSliceIndicator.value = true
+            val latest by collectLastValue(underTest.showSliceAttribution)
+
+            connectionRepository.hasPrioritizedNetworkCapabilities.value = true
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun networkSlice_configOn_noPrioritizedCaps_noSlice() =
+        testScope.runTest {
+            connectionRepository.allowNetworkSliceIndicator.value = true
+            val latest by collectLastValue(underTest.showSliceAttribution)
+
+            connectionRepository.hasPrioritizedNetworkCapabilities.value = false
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun networkSlice_configOff_hasPrioritizedCaps_noSlice() =
+        testScope.runTest {
+            connectionRepository.allowNetworkSliceIndicator.value = false
+            val latest by collectLastValue(underTest.showSliceAttribution)
+
+            connectionRepository.hasPrioritizedNetworkCapabilities.value = true
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun networkSlice_configOff_noPrioritizedCaps_noSlice() =
+        testScope.runTest {
+            connectionRepository.allowNetworkSliceIndicator.value = false
+            val latest by collectLastValue(underTest.showSliceAttribution)
+
+            connectionRepository.hasPrioritizedNetworkCapabilities.value = false
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun iconGroup_three_g() =
+        testScope.runTest {
+            connectionRepository.resolvedNetworkType.value =
+                DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
+
+            var latest: NetworkTypeIconModel? = null
+            val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.THREE_G))
+
+            job.cancel()
+        }
+
+    @Test
+    fun iconGroup_updates_on_change() =
+        testScope.runTest {
+            connectionRepository.resolvedNetworkType.value =
+                DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
+
+            var latest: NetworkTypeIconModel? = null
+            val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+            connectionRepository.resolvedNetworkType.value =
+                DefaultNetworkType(mobileMappingsProxy.toIconKey(FOUR_G))
+
+            assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.FOUR_G))
+
+            job.cancel()
+        }
+
+    @Test
+    fun iconGroup_5g_override_type() =
+        testScope.runTest {
+            connectionRepository.resolvedNetworkType.value =
+                OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(FIVE_G_OVERRIDE))
+
+            var latest: NetworkTypeIconModel? = null
+            val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest).isEqualTo(NetworkTypeIconModel.DefaultIcon(TelephonyIcons.NR_5G))
+
+            job.cancel()
+        }
+
+    @Test
+    fun iconGroup_default_if_no_lookup() =
+        testScope.runTest {
+            connectionRepository.resolvedNetworkType.value =
+                DefaultNetworkType(mobileMappingsProxy.toIconKey(NETWORK_TYPE_UNKNOWN))
+
+            var latest: NetworkTypeIconModel? = null
+            val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest)
+                .isEqualTo(NetworkTypeIconModel.DefaultIcon(FakeMobileIconsInteractor.DEFAULT_ICON))
+
+            job.cancel()
+        }
+
+    @Test
+    fun iconGroup_carrierMerged_usesOverride() =
+        testScope.runTest {
+            connectionRepository.resolvedNetworkType.value = CarrierMergedNetworkType
+
+            var latest: NetworkTypeIconModel? = null
+            val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest)
+                .isEqualTo(
+                    NetworkTypeIconModel.DefaultIcon(CarrierMergedNetworkType.iconGroupOverride)
+                )
+
+            job.cancel()
+        }
+
+    @Test
+    fun overrideIcon_usesCarrierIdOverride() =
+        testScope.runTest {
+            val overrides =
+                mock<MobileIconCarrierIdOverrides>().also {
+                    whenever(it.carrierIdEntryExists(anyInt())).thenReturn(true)
+                    whenever(it.getOverrideFor(anyInt(), anyString(), any())).thenReturn(1234)
+                }
+
+            underTest = createInteractor(overrides)
+
+            connectionRepository.resolvedNetworkType.value =
+                DefaultNetworkType(mobileMappingsProxy.toIconKey(THREE_G))
+
+            var latest: NetworkTypeIconModel? = null
+            val job = underTest.networkTypeIconGroup.onEach { latest = it }.launchIn(this)
+
+            assertThat(latest)
+                .isEqualTo(NetworkTypeIconModel.OverriddenIcon(TelephonyIcons.THREE_G, 1234))
+
+            job.cancel()
+        }
+
+    @Test
+    fun alwaysShowDataRatIcon_matchesParent() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.alwaysShowDataRatIcon.onEach { latest = it }.launchIn(this)
+
+            mobileIconsInteractor.alwaysShowDataRatIcon.value = true
+            assertThat(latest).isTrue()
+
+            mobileIconsInteractor.alwaysShowDataRatIcon.value = false
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataState_connected() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this)
+
+            connectionRepository.dataConnectionState.value = DataConnectionState.Connected
+
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun dataState_notConnected() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isDataConnected.onEach { latest = it }.launchIn(this)
+
+            connectionRepository.dataConnectionState.value = DataConnectionState.Disconnected
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isInService_usesRepositoryValue() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isInService.onEach { latest = it }.launchIn(this)
+
+            connectionRepository.isInService.value = true
+
+            assertThat(latest).isTrue()
+
+            connectionRepository.isInService.value = false
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun roaming_isGsm_usesConnectionModel() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
+
+            connectionRepository.cdmaRoaming.value = true
+            connectionRepository.isGsm.value = true
+            connectionRepository.isRoaming.value = false
+
+            assertThat(latest).isFalse()
+
+            connectionRepository.isRoaming.value = true
+
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun roaming_isCdma_usesCdmaRoamingBit() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
+
+            connectionRepository.cdmaRoaming.value = false
+            connectionRepository.isGsm.value = false
+            connectionRepository.isRoaming.value = true
+
+            assertThat(latest).isFalse()
+
+            connectionRepository.cdmaRoaming.value = true
+            connectionRepository.isGsm.value = false
+            connectionRepository.isRoaming.value = false
+
+            assertThat(latest).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun roaming_falseWhileCarrierNetworkChangeActive() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isRoaming.onEach { latest = it }.launchIn(this)
+
+            connectionRepository.cdmaRoaming.value = true
+            connectionRepository.isGsm.value = false
+            connectionRepository.isRoaming.value = true
+            connectionRepository.carrierNetworkChangeActive.value = true
+
+            assertThat(latest).isFalse()
+
+            connectionRepository.cdmaRoaming.value = true
+            connectionRepository.isGsm.value = true
+
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkName_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() =
+        testScope.runTest {
+            var latest: NetworkNameModel? = null
+            val job = underTest.networkName.onEach { latest = it }.launchIn(this)
+
+            val testOperatorName = "operatorAlphaShort"
+
+            // Default network name, operator name is non-null, uses the operator name
+            connectionRepository.networkName.value = DEFAULT_NAME_MODEL
+            connectionRepository.operatorAlphaShort.value = testOperatorName
+
+            assertThat(latest).isEqualTo(NetworkNameModel.IntentDerived(testOperatorName))
+
+            // Default network name, operator name is null, uses the default
+            connectionRepository.operatorAlphaShort.value = null
+
+            assertThat(latest).isEqualTo(DEFAULT_NAME_MODEL)
+
+            // Derived network name, operator name non-null, uses the derived name
+            connectionRepository.networkName.value = DERIVED_NAME_MODEL
+            connectionRepository.operatorAlphaShort.value = testOperatorName
+
+            assertThat(latest).isEqualTo(DERIVED_NAME_MODEL)
+
+            job.cancel()
+        }
+
+    @Test
+    fun networkNameForSubId_usesOperatorAlphaShortWhenNonNullAndRepoIsDefault() =
+        testScope.runTest {
+            var latest: String? = null
+            val job = underTest.carrierName.onEach { latest = it }.launchIn(this)
+
+            val testOperatorName = "operatorAlphaShort"
+
+            // Default network name, operator name is non-null, uses the operator name
+            connectionRepository.carrierName.value = DEFAULT_NAME_MODEL
+            connectionRepository.operatorAlphaShort.value = testOperatorName
+
+            assertThat(latest).isEqualTo(testOperatorName)
+
+            // Default network name, operator name is null, uses the default
+            connectionRepository.operatorAlphaShort.value = null
+
+            assertThat(latest).isEqualTo(DEFAULT_NAME)
+
+            // Derived network name, operator name non-null, uses the derived name
+            connectionRepository.carrierName.value =
+                NetworkNameModel.SubscriptionDerived(DERIVED_NAME)
+            connectionRepository.operatorAlphaShort.value = testOperatorName
+
+            assertThat(latest).isEqualTo(DERIVED_NAME)
+
+            job.cancel()
+        }
+
+    @Test
+    fun isSingleCarrier_matchesParent() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isSingleCarrier.onEach { latest = it }.launchIn(this)
+
+            mobileIconsInteractor.isSingleCarrier.value = true
+            assertThat(latest).isTrue()
+
+            mobileIconsInteractor.isSingleCarrier.value = false
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isForceHidden_matchesParent() =
+        testScope.runTest {
+            var latest: Boolean? = null
+            val job = underTest.isForceHidden.onEach { latest = it }.launchIn(this)
+
+            mobileIconsInteractor.isForceHidden.value = true
+            assertThat(latest).isTrue()
+
+            mobileIconsInteractor.isForceHidden.value = false
+            assertThat(latest).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun isAllowedDuringAirplaneMode_matchesRepo() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.isAllowedDuringAirplaneMode)
+
+            connectionRepository.isAllowedDuringAirplaneMode.value = true
+            assertThat(latest).isTrue()
+
+            connectionRepository.isAllowedDuringAirplaneMode.value = false
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun cellBasedIconId_correctLevel_notCutout() =
+        testScope.runTest {
+            connectionRepository.isNonTerrestrial.value = false
+            connectionRepository.isInService.value = true
+            connectionRepository.primaryLevel.value = 1
+            connectionRepository.setDataEnabled(false)
+            connectionRepository.isNonTerrestrial.value = false
+
+            var latest: SignalIconModel.Cellular? = null
+            val job =
+                underTest.signalLevelIcon
+                    .onEach { latest = it as? SignalIconModel.Cellular }
+                    .launchIn(this)
+
+            assertThat(latest?.level).isEqualTo(1)
+            assertThat(latest?.showExclamationMark).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun icon_usesLevelFromInteractor() =
+        testScope.runTest {
+            connectionRepository.isNonTerrestrial.value = false
+            connectionRepository.isInService.value = true
+
+            var latest: SignalIconModel? = null
+            val job = underTest.signalLevelIcon.onEach { latest = it }.launchIn(this)
+
+            connectionRepository.primaryLevel.value = 3
+            assertThat(latest!!.level).isEqualTo(3)
+
+            connectionRepository.primaryLevel.value = 1
+            assertThat(latest!!.level).isEqualTo(1)
+
+            job.cancel()
+        }
+
+    @Test
+    fun cellBasedIcon_usesNumberOfLevelsFromInteractor() =
+        testScope.runTest {
+            connectionRepository.isNonTerrestrial.value = false
+
+            var latest: SignalIconModel.Cellular? = null
+            val job =
+                underTest.signalLevelIcon
+                    .onEach { latest = it as? SignalIconModel.Cellular }
+                    .launchIn(this)
+
+            connectionRepository.numberOfLevels.value = 5
+            assertThat(latest!!.numberOfLevels).isEqualTo(5)
+
+            connectionRepository.numberOfLevels.value = 2
+            assertThat(latest!!.numberOfLevels).isEqualTo(2)
+
+            job.cancel()
+        }
+
+    @Test
+    fun cellBasedIcon_defaultDataDisabled_showExclamationTrue() =
+        testScope.runTest {
+            connectionRepository.isNonTerrestrial.value = false
+            mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = false
+
+            var latest: SignalIconModel.Cellular? = null
+            val job =
+                underTest.signalLevelIcon
+                    .onEach { latest = it as? SignalIconModel.Cellular }
+                    .launchIn(this)
+
+            assertThat(latest!!.showExclamationMark).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun cellBasedIcon_defaultConnectionFailed_showExclamationTrue() =
+        testScope.runTest {
+            connectionRepository.isNonTerrestrial.value = false
+            mobileIconsInteractor.isDefaultConnectionFailed.value = true
+
+            var latest: SignalIconModel.Cellular? = null
+            val job =
+                underTest.signalLevelIcon
+                    .onEach { latest = it as? SignalIconModel.Cellular }
+                    .launchIn(this)
+
+            assertThat(latest!!.showExclamationMark).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun cellBasedIcon_enabledAndNotFailed_showExclamationFalse() =
+        testScope.runTest {
+            connectionRepository.isNonTerrestrial.value = false
+            connectionRepository.isInService.value = true
+            mobileIconsInteractor.activeDataConnectionHasDataEnabled.value = true
+            mobileIconsInteractor.isDefaultConnectionFailed.value = false
+
+            var latest: SignalIconModel.Cellular? = null
+            val job =
+                underTest.signalLevelIcon
+                    .onEach { latest = it as? SignalIconModel.Cellular }
+                    .launchIn(this)
+
+            assertThat(latest!!.showExclamationMark).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun cellBasedIcon_usesEmptyState_whenNotInService() =
+        testScope.runTest {
+            var latest: SignalIconModel.Cellular? = null
+            val job =
+                underTest.signalLevelIcon
+                    .onEach { latest = it as? SignalIconModel.Cellular }
+                    .launchIn(this)
+
+            connectionRepository.isNonTerrestrial.value = false
+            connectionRepository.isInService.value = false
+
+            assertThat(latest?.level).isEqualTo(0)
+            assertThat(latest?.showExclamationMark).isTrue()
+
+            // Changing the level doesn't overwrite the disabled state
+            connectionRepository.primaryLevel.value = 2
+            assertThat(latest?.level).isEqualTo(0)
+            assertThat(latest?.showExclamationMark).isTrue()
+
+            // Once back in service, the regular icon appears
+            connectionRepository.isInService.value = true
+            assertThat(latest?.level).isEqualTo(2)
+            assertThat(latest?.showExclamationMark).isFalse()
+
+            job.cancel()
+        }
+
+    @Test
+    fun cellBasedIcon_usesCarrierNetworkState_whenInCarrierNetworkChangeMode() =
+        testScope.runTest {
+            var latest: SignalIconModel.Cellular? = null
+            val job =
+                underTest.signalLevelIcon
+                    .onEach { latest = it as? SignalIconModel.Cellular? }
+                    .launchIn(this)
+
+            connectionRepository.isNonTerrestrial.value = false
+            connectionRepository.isInService.value = true
+            connectionRepository.carrierNetworkChangeActive.value = true
+            connectionRepository.primaryLevel.value = 1
+            connectionRepository.cdmaLevel.value = 1
+
+            assertThat(latest!!.level).isEqualTo(1)
+            assertThat(latest!!.carrierNetworkChange).isTrue()
+
+            // SignalIconModel respects the current level
+            connectionRepository.primaryLevel.value = 2
+
+            assertThat(latest!!.level).isEqualTo(2)
+            assertThat(latest!!.carrierNetworkChange).isTrue()
+
+            job.cancel()
+        }
+
+    @Test
+    fun satBasedIcon_isUsedWhenNonTerrestrial() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.signalLevelIcon)
+
+            // Start off using cellular
+            assertThat(latest).isInstanceOf(SignalIconModel.Cellular::class.java)
+
+            connectionRepository.isNonTerrestrial.value = true
+
+            assertThat(latest).isInstanceOf(SignalIconModel.Satellite::class.java)
+        }
+
+    @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+    @Test
+    // See b/346904529 for more context
+    fun satBasedIcon_doesNotInflateSignalStrength_flagOff() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.signalLevelIcon)
+
+            // GIVEN a satellite connection
+            connectionRepository.isNonTerrestrial.value = true
+            // GIVEN this carrier has set INFLATE_SIGNAL_STRENGTH
+            connectionRepository.inflateSignalStrength.value = true
+
+            connectionRepository.primaryLevel.value = 4
+            assertThat(latest!!.level).isEqualTo(4)
+
+            connectionRepository.inflateSignalStrength.value = true
+            connectionRepository.primaryLevel.value = 4
+
+            // Icon level is unaffected
+            assertThat(latest!!.level).isEqualTo(4)
+        }
+
+    @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+    @Test
+    // See b/346904529 for more context
+    fun satBasedIcon_doesNotInflateSignalStrength_flagOn() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.signalLevelIcon)
+
+            // GIVEN a satellite connection
+            connectionRepository.isNonTerrestrial.value = true
+            // GIVEN this carrier has set INFLATE_SIGNAL_STRENGTH
+            connectionRepository.inflateSignalStrength.value = true
+
+            connectionRepository.satelliteLevel.value = 4
+            assertThat(latest!!.level).isEqualTo(4)
+
+            connectionRepository.inflateSignalStrength.value = true
+            connectionRepository.primaryLevel.value = 4
+
+            // Icon level is unaffected
+            assertThat(latest!!.level).isEqualTo(4)
+        }
+
+    @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+    @Test
+    fun satBasedIcon_usesPrimaryLevel_flagOff() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.signalLevelIcon)
+
+            // GIVEN a satellite connection
+            connectionRepository.isNonTerrestrial.value = true
+
+            // GIVEN primary level is set
+            connectionRepository.primaryLevel.value = 4
+            connectionRepository.satelliteLevel.value = 0
+
+            // THEN icon uses the primary level because the flag is off
+            assertThat(latest!!.level).isEqualTo(4)
+        }
+
+    @EnableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+    @Test
+    fun satBasedIcon_usesSatelliteLevel_flagOn() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.signalLevelIcon)
+
+            // GIVEN a satellite connection
+            connectionRepository.isNonTerrestrial.value = true
+
+            // GIVEN satellite level is set
+            connectionRepository.satelliteLevel.value = 4
+            connectionRepository.primaryLevel.value = 0
+
+            // THEN icon uses the satellite level because the flag is on
+            assertThat(latest!!.level).isEqualTo(4)
+        }
+
+    /**
+     * Context (b/377518113), this test will not be needed after FLAG_CARRIER_ROAMING_NB_IOT_NTN is
+     * rolled out. The new API should report 0 automatically if not in service.
+     */
+    @DisableFlags(com.android.internal.telephony.flags.Flags.FLAG_CARRIER_ROAMING_NB_IOT_NTN)
+    @Test
+    fun satBasedIcon_reportsLevelZeroWhenOutOfService() =
+        testScope.runTest {
+            val latest by collectLastValue(underTest.signalLevelIcon)
+
+            // GIVEN a satellite connection
+            connectionRepository.isNonTerrestrial.value = true
+            // GIVEN this carrier has set INFLATE_SIGNAL_STRENGTH
+            connectionRepository.inflateSignalStrength.value = true
+
+            connectionRepository.primaryLevel.value = 4
+            assertThat(latest!!.level).isEqualTo(4)
+
+            connectionRepository.isInService.value = false
+            connectionRepository.primaryLevel.value = 4
+
+            // THEN level reports 0, by policy
+            assertThat(latest!!.level).isEqualTo(0)
+        }
+
+    private fun createInteractor(
+        overrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl()
+    ) =
+        MobileIconInteractorKairosImpl(
+            testScope.backgroundScope,
+            mobileIconsInteractor.activeDataConnectionHasDataEnabled,
+            mobileIconsInteractor.alwaysShowDataRatIcon,
+            mobileIconsInteractor.alwaysUseCdmaLevel,
+            mobileIconsInteractor.isSingleCarrier,
+            mobileIconsInteractor.mobileIsDefault,
+            mobileIconsInteractor.defaultMobileIconMapping,
+            mobileIconsInteractor.defaultMobileIconGroup,
+            mobileIconsInteractor.isDefaultConnectionFailed,
+            mobileIconsInteractor.isForceHidden,
+            connectionRepository,
+            context,
+            overrides,
+        )
+
+    companion object {
+        private const val GSM_LEVEL = 1
+        private const val CDMA_LEVEL = 2
+
+        private const val SUB_1_ID = 1
+
+        private const val DEFAULT_NAME = "test default name"
+        private val DEFAULT_NAME_MODEL = NetworkNameModel.Default(DEFAULT_NAME)
+        private const val DERIVED_NAME = "test derived name"
+        private val DERIVED_NAME_MODEL = NetworkNameModel.IntentDerived(DERIVED_NAME)
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosTest.kt
new file mode 100644
index 0000000..a9360d1
--- /dev/null
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairosTest.kt
@@ -0,0 +1,1046 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
+
+import android.os.ParcelUuid
+import android.platform.test.annotations.EnableFlags
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.android.settingslib.mobile.MobileMappings
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.flags.Flags
+import com.android.systemui.flags.fake
+import com.android.systemui.flags.featureFlagsClassic
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.collectLastValue
+import com.android.systemui.kosmos.runCurrent
+import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.testScope
+import com.android.systemui.statusbar.core.NewStatusBarIcons
+import com.android.systemui.statusbar.core.StatusBarRootModernization
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fake
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.fakeMobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.mobileConnectionsRepositoryLogbufferName
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.repository.connectivityRepository
+import com.android.systemui.statusbar.pipeline.shared.data.repository.fake
+import com.android.systemui.statusbar.policy.data.repository.FakeUserSetupRepository
+import com.android.systemui.testKosmos
+import com.android.systemui.util.CarrierConfigTracker
+import com.google.common.truth.Truth.assertThat
+import java.util.UUID
+import kotlinx.coroutines.test.advanceTimeBy
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class MobileIconsInteractorKairosTest : SysuiTestCase() {
+    private val kosmos by lazy {
+        testKosmos().apply {
+            mobileConnectionsRepositoryLogbufferName = "MobileIconsInteractorTest"
+            mobileConnectionsRepository.fake.run {
+                setMobileConnectionRepositoryMap(
+                    mapOf(
+                        SUB_1_ID to FakeMobileConnectionRepository(SUB_1_ID, mock()),
+                        SUB_2_ID to FakeMobileConnectionRepository(SUB_2_ID, mock()),
+                        SUB_3_ID to FakeMobileConnectionRepository(SUB_3_ID, mock()),
+                        SUB_4_ID to FakeMobileConnectionRepository(SUB_4_ID, mock()),
+                    )
+                )
+                setActiveMobileDataSubscriptionId(SUB_1_ID)
+            }
+            featureFlagsClassic.fake.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, true)
+        }
+    }
+
+    // shortcut rename
+    private val Kosmos.connectionsRepository by Fixture { mobileConnectionsRepository.fake }
+
+    private val Kosmos.carrierConfigTracker by Fixture { mock<CarrierConfigTracker>() }
+
+    private val Kosmos.underTest by Fixture {
+        MobileIconsInteractorKairosImpl(
+            mobileConnectionsRepository,
+            carrierConfigTracker,
+            tableLogger = mock(),
+            connectivityRepository,
+            FakeUserSetupRepository(),
+            testScope.backgroundScope,
+            context,
+            featureFlagsClassic,
+        )
+    }
+
+    @Test
+    fun filteredSubscriptions_default() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf<SubscriptionModel>())
+        }
+
+    // Based on the logic from the old pipeline, we'll never filter subs when there are more than 2
+    @Test
+    fun filteredSubscriptions_moreThanTwo_doesNotFilter() =
+        kosmos.runTest {
+            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(SUB_1, SUB_3_OPP, SUB_4_OPP))
+        }
+
+    @Test
+    fun filteredSubscriptions_nonOpportunistic_updatesWithMultipleSubs() =
+        kosmos.runTest {
+            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(SUB_1, SUB_2))
+        }
+
+    @Test
+    fun filteredSubscriptions_opportunistic_differentGroups_doesNotFilter() =
+        kosmos.runTest {
+            connectionsRepository.setSubscriptions(listOf(SUB_3_OPP, SUB_4_OPP))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(SUB_3_OPP, SUB_4_OPP))
+        }
+
+    @Test
+    fun filteredSubscriptions_opportunistic_nonGrouped_doesNotFilter() =
+        kosmos.runTest {
+            val (sub1, sub2) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_1_ID, SUB_2_ID),
+                    opportunistic = Pair(true, true),
+                    grouped = false,
+                )
+            connectionsRepository.setSubscriptions(listOf(sub1, sub2))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(sub1, sub2))
+        }
+
+    @Test
+    fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_3() =
+        kosmos.runTest {
+            val (sub3, sub4) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
+                    opportunistic = Pair(true, true),
+                    grouped = true,
+                )
+            connectionsRepository.setSubscriptions(listOf(sub3, sub4))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+                .thenReturn(false)
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            // Filtered subscriptions should show the active one when the config is false
+            assertThat(latest).isEqualTo(listOf(sub3))
+        }
+
+    @Test
+    fun filteredSubscriptions_opportunistic_grouped_configFalse_showsActive_4() =
+        kosmos.runTest {
+            val (sub3, sub4) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
+                    opportunistic = Pair(true, true),
+                    grouped = true,
+                )
+            connectionsRepository.setSubscriptions(listOf(sub3, sub4))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_4_ID)
+            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+                .thenReturn(false)
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            // Filtered subscriptions should show the active one when the config is false
+            assertThat(latest).isEqualTo(listOf(sub4))
+        }
+
+    @Test
+    fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_active_1() =
+        kosmos.runTest {
+            val (sub1, sub3) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+                    opportunistic = Pair(false, true),
+                    grouped = true,
+                )
+            connectionsRepository.setSubscriptions(listOf(sub1, sub3))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_1_ID)
+            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+                .thenReturn(true)
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            // Filtered subscriptions should show the primary (non-opportunistic) if the config is
+            // true
+            assertThat(latest).isEqualTo(listOf(sub1))
+        }
+
+    @Test
+    fun filteredSubscriptions_oneOpportunistic_grouped_configTrue_showsPrimary_nonActive_1() =
+        kosmos.runTest {
+            val (sub1, sub3) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+                    opportunistic = Pair(false, true),
+                    grouped = true,
+                )
+            connectionsRepository.setSubscriptions(listOf(sub1, sub3))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+                .thenReturn(true)
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            // Filtered subscriptions should show the primary (non-opportunistic) if the config is
+            // true
+            assertThat(latest).isEqualTo(listOf(sub1))
+        }
+
+    @Test
+    fun filteredSubscriptions_vcnSubId_agreesWithActiveSubId_usesActiveAkaVcnSub() =
+        kosmos.runTest {
+            val (sub1, sub3) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+                    opportunistic = Pair(true, true),
+                    grouped = true,
+                )
+            connectionsRepository.setSubscriptions(listOf(sub1, sub3))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+            kosmos.connectivityRepository.fake.vcnSubId.value = SUB_3_ID
+            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+                .thenReturn(false)
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(sub3))
+        }
+
+    @Test
+    fun filteredSubscriptions_vcnSubId_disagreesWithActiveSubId_usesVcnSub() =
+        kosmos.runTest {
+            val (sub1, sub3) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+                    opportunistic = Pair(true, true),
+                    grouped = true,
+                )
+            connectionsRepository.setSubscriptions(listOf(sub1, sub3))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+            kosmos.connectivityRepository.fake.vcnSubId.value = SUB_1_ID
+            whenever(carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault)
+                .thenReturn(false)
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(sub1))
+        }
+
+    @Test
+    fun filteredSubscriptions_doesNotFilterProvisioningWhenFlagIsFalse() =
+        kosmos.runTest {
+            // GIVEN the flag is false
+            featureFlagsClassic.fake.set(Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS, false)
+
+            // GIVEN 1 sub that is in PROFILE_CLASS_PROVISIONING
+            val sub1 =
+                SubscriptionModel(
+                    subscriptionId = SUB_1_ID,
+                    isOpportunistic = false,
+                    carrierName = "Carrier 1",
+                    profileClass = PROFILE_CLASS_PROVISIONING,
+                )
+
+            connectionsRepository.setSubscriptions(listOf(sub1))
+
+            // WHEN filtering is applied
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            // THEN the provisioning sub is still present (unfiltered)
+            assertThat(latest).isEqualTo(listOf(sub1))
+        }
+
+    @Test
+    fun filteredSubscriptions_filtersOutProvisioningSubs() =
+        kosmos.runTest {
+            val sub1 =
+                SubscriptionModel(
+                    subscriptionId = SUB_1_ID,
+                    isOpportunistic = false,
+                    carrierName = "Carrier 1",
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+            val sub2 =
+                SubscriptionModel(
+                    subscriptionId = SUB_2_ID,
+                    isOpportunistic = false,
+                    carrierName = "Carrier 2",
+                    profileClass = PROFILE_CLASS_PROVISIONING,
+                )
+
+            connectionsRepository.setSubscriptions(listOf(sub1, sub2))
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(sub1))
+        }
+
+    /** Note: I'm not sure if this will ever be the case, but we can test it at least */
+    @Test
+    fun filteredSubscriptions_filtersOutProvisioningSubsBeforeOpportunistic() =
+        kosmos.runTest {
+            // This is a contrived test case, where the active subId is the one that would
+            // also be filtered by opportunistic filtering.
+
+            // GIVEN grouped, opportunistic subscriptions
+            val groupUuid = ParcelUuid(UUID.randomUUID())
+            val sub1 =
+                SubscriptionModel(
+                    subscriptionId = 1,
+                    isOpportunistic = true,
+                    groupUuid = groupUuid,
+                    carrierName = "Carrier 1",
+                    profileClass = PROFILE_CLASS_PROVISIONING,
+                )
+
+            val sub2 =
+                SubscriptionModel(
+                    subscriptionId = 2,
+                    isOpportunistic = true,
+                    groupUuid = groupUuid,
+                    carrierName = "Carrier 2",
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+
+            // GIVEN active subId is 1
+            connectionsRepository.setSubscriptions(listOf(sub1, sub2))
+            connectionsRepository.setActiveMobileDataSubscriptionId(1)
+
+            // THEN filtering of provisioning subs takes place first, and we result in sub2
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(sub2))
+        }
+
+    @Test
+    fun filteredSubscriptions_groupedPairAndNonProvisioned_groupedFilteringStillHappens() =
+        kosmos.runTest {
+            // Grouped filtering only happens when the list of subs is length 2. In this case
+            // we'll show that filtering of provisioning subs happens before, and thus grouped
+            // filtering happens even though the unfiltered list is length 3
+            val (sub1, sub3) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_1_ID, SUB_3_ID),
+                    opportunistic = Pair(true, true),
+                    grouped = true,
+                )
+
+            val sub2 =
+                SubscriptionModel(
+                    subscriptionId = 2,
+                    isOpportunistic = true,
+                    groupUuid = null,
+                    carrierName = "Carrier 2",
+                    profileClass = PROFILE_CLASS_PROVISIONING,
+                )
+
+            connectionsRepository.setSubscriptions(listOf(sub1, sub2, sub3))
+            connectionsRepository.setActiveMobileDataSubscriptionId(1)
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(sub1))
+        }
+
+    @Test
+    fun filteredSubscriptions_subNotExclusivelyNonTerrestrial_hasSub() =
+        kosmos.runTest {
+            val notExclusivelyNonTerrestrialSub =
+                SubscriptionModel(
+                    isExclusivelyNonTerrestrial = false,
+                    subscriptionId = 5,
+                    carrierName = "Carrier 5",
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+
+            connectionsRepository.setSubscriptions(listOf(notExclusivelyNonTerrestrialSub))
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(notExclusivelyNonTerrestrialSub))
+        }
+
+    @Test
+    fun filteredSubscriptions_subExclusivelyNonTerrestrial_doesNotHaveSub() =
+        kosmos.runTest {
+            val exclusivelyNonTerrestrialSub =
+                SubscriptionModel(
+                    isExclusivelyNonTerrestrial = true,
+                    subscriptionId = 5,
+                    carrierName = "Carrier 5",
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+
+            connectionsRepository.setSubscriptions(listOf(exclusivelyNonTerrestrialSub))
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEmpty()
+        }
+
+    @Test
+    fun filteredSubscription_mixOfExclusivelyNonTerrestrialAndOther_hasOtherSubsOnly() =
+        kosmos.runTest {
+            val exclusivelyNonTerrestrialSub =
+                SubscriptionModel(
+                    isExclusivelyNonTerrestrial = true,
+                    subscriptionId = 5,
+                    carrierName = "Carrier 5",
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+            val otherSub1 =
+                SubscriptionModel(
+                    isExclusivelyNonTerrestrial = false,
+                    subscriptionId = 1,
+                    carrierName = "Carrier 1",
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+            val otherSub2 =
+                SubscriptionModel(
+                    isExclusivelyNonTerrestrial = false,
+                    subscriptionId = 2,
+                    carrierName = "Carrier 2",
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+
+            connectionsRepository.setSubscriptions(
+                listOf(otherSub1, exclusivelyNonTerrestrialSub, otherSub2)
+            )
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            assertThat(latest).isEqualTo(listOf(otherSub1, otherSub2))
+        }
+
+    @Test
+    fun filteredSubscriptions_exclusivelyNonTerrestrialSub_andOpportunistic_bothFiltersHappen() =
+        kosmos.runTest {
+            // Exclusively non-terrestrial sub
+            val exclusivelyNonTerrestrialSub =
+                SubscriptionModel(
+                    isExclusivelyNonTerrestrial = true,
+                    subscriptionId = 5,
+                    carrierName = "Carrier 5",
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+
+            // Opportunistic subs
+            val (sub3, sub4) =
+                createSubscriptionPair(
+                    subscriptionIds = Pair(SUB_3_ID, SUB_4_ID),
+                    opportunistic = Pair(true, true),
+                    grouped = true,
+                )
+
+            // WHEN both an exclusively non-terrestrial sub and opportunistic sub pair is included
+            connectionsRepository.setSubscriptions(listOf(sub3, sub4, exclusivelyNonTerrestrialSub))
+            connectionsRepository.setActiveMobileDataSubscriptionId(SUB_3_ID)
+
+            val latest by collectLastValue(underTest.filteredSubscriptions)
+
+            // THEN both the only-non-terrestrial sub and the non-active sub are filtered out,
+            // leaving only sub3.
+            assertThat(latest).isEqualTo(listOf(sub3))
+        }
+
+    @Test
+    fun activeDataConnection_turnedOn() =
+        kosmos.runTest {
+            (fakeMobileConnectionsRepository.getRepoForSubId(SUB_1_ID)
+                    as FakeMobileConnectionRepository)
+                .dataEnabled
+                .value = true
+
+            val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled)
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun activeDataConnection_turnedOff() =
+        kosmos.runTest {
+            (fakeMobileConnectionsRepository.getRepoForSubId(SUB_1_ID)
+                    as FakeMobileConnectionRepository)
+                .dataEnabled
+                .value = true
+
+            val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled)
+
+            (fakeMobileConnectionsRepository.getRepoForSubId(SUB_1_ID)
+                    as FakeMobileConnectionRepository)
+                .dataEnabled
+                .value = false
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun activeDataConnection_invalidSubId() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.activeDataConnectionHasDataEnabled)
+
+            connectionsRepository.setActiveMobileDataSubscriptionId(INVALID_SUBSCRIPTION_ID)
+
+            // An invalid active subId should tell us that data is off
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun failedConnection_default_validated_notFailed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+
+            connectionsRepository.mobileIsDefault.value = true
+            connectionsRepository.defaultConnectionIsValidated.value = true
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun failedConnection_notDefault_notValidated_notFailed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+
+            connectionsRepository.mobileIsDefault.value = false
+            connectionsRepository.defaultConnectionIsValidated.value = false
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun failedConnection_default_notValidated_failed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+
+            connectionsRepository.mobileIsDefault.value = true
+            connectionsRepository.defaultConnectionIsValidated.value = false
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun failedConnection_carrierMergedDefault_notValidated_failed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+
+            connectionsRepository.hasCarrierMergedConnection.value = true
+            connectionsRepository.defaultConnectionIsValidated.value = false
+
+            assertThat(latest).isTrue()
+        }
+
+    /** Regression test for b/275076959. */
+    @Test
+    fun failedConnection_dataSwitchInSameGroup_notFailed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+
+            connectionsRepository.mobileIsDefault.value = true
+            connectionsRepository.defaultConnectionIsValidated.value = true
+            runCurrent()
+
+            // WHEN there's a data change in the same subscription group
+            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+            connectionsRepository.defaultConnectionIsValidated.value = false
+            runCurrent()
+
+            // THEN the default connection is *not* marked as failed because of forced validation
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun failedConnection_dataSwitchNotInSameGroup_isFailed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+
+            connectionsRepository.mobileIsDefault.value = true
+            connectionsRepository.defaultConnectionIsValidated.value = true
+            runCurrent()
+
+            // WHEN the connection is invalidated without a activeSubChangedInGroupEvent
+            connectionsRepository.defaultConnectionIsValidated.value = false
+
+            // THEN the connection is immediately marked as failed
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun alwaysShowDataRatIcon_configHasTrue() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.alwaysShowDataRatIcon)
+
+            val config = MobileMappings.Config()
+            config.alwaysShowDataRatIcon = true
+            connectionsRepository.defaultDataSubRatConfig.value = config
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun alwaysShowDataRatIcon_configHasFalse() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.alwaysShowDataRatIcon)
+
+            val config = MobileMappings.Config()
+            config.alwaysShowDataRatIcon = false
+            connectionsRepository.defaultDataSubRatConfig.value = config
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun alwaysUseCdmaLevel_configHasTrue() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.alwaysUseCdmaLevel)
+
+            val config = MobileMappings.Config()
+            config.alwaysShowCdmaRssi = true
+            connectionsRepository.defaultDataSubRatConfig.value = config
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun alwaysUseCdmaLevel_configHasFalse() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.alwaysUseCdmaLevel)
+
+            val config = MobileMappings.Config()
+            config.alwaysShowCdmaRssi = false
+            connectionsRepository.defaultDataSubRatConfig.value = config
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun isSingleCarrier_zeroSubscriptions_false() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isSingleCarrier)
+
+            connectionsRepository.setSubscriptions(emptyList())
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun isSingleCarrier_oneSubscription_true() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isSingleCarrier)
+
+            connectionsRepository.setSubscriptions(listOf(SUB_1))
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun isSingleCarrier_twoSubscriptions_false() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isSingleCarrier)
+
+            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun isSingleCarrier_updates() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isSingleCarrier)
+
+            connectionsRepository.setSubscriptions(listOf(SUB_1))
+            assertThat(latest).isTrue()
+
+            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun mobileIsDefault_mobileFalseAndCarrierMergedFalse_false() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.mobileIsDefault)
+
+            connectionsRepository.mobileIsDefault.value = false
+            connectionsRepository.hasCarrierMergedConnection.value = false
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun mobileIsDefault_mobileTrueAndCarrierMergedFalse_true() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.mobileIsDefault)
+
+            connectionsRepository.mobileIsDefault.value = true
+            connectionsRepository.hasCarrierMergedConnection.value = false
+
+            assertThat(latest).isTrue()
+        }
+
+    /** Regression test for b/272586234. */
+    @Test
+    fun mobileIsDefault_mobileFalseAndCarrierMergedTrue_true() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.mobileIsDefault)
+
+            connectionsRepository.mobileIsDefault.value = false
+            connectionsRepository.hasCarrierMergedConnection.value = true
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun mobileIsDefault_updatesWhenRepoUpdates() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.mobileIsDefault)
+
+            connectionsRepository.mobileIsDefault.value = true
+            assertThat(latest).isTrue()
+
+            connectionsRepository.mobileIsDefault.value = false
+            assertThat(latest).isFalse()
+
+            connectionsRepository.hasCarrierMergedConnection.value = true
+            assertThat(latest).isTrue()
+        }
+
+    // The data switch tests are mostly testing the [forcingCellularValidation] flow, but that flow
+    // is private and can only be tested by looking at [isDefaultConnectionFailed].
+
+    @Test
+    fun dataSwitch_inSameGroup_validatedMatchesPreviousValue_expiresAfter2s() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+
+            connectionsRepository.mobileIsDefault.value = true
+            connectionsRepository.defaultConnectionIsValidated.value = true
+            runCurrent()
+
+            // Trigger a data change in the same subscription group that's not yet validated
+            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+            connectionsRepository.defaultConnectionIsValidated.value = false
+            runCurrent()
+
+            // After 1s, the force validation bit is still present, so the connection is not marked
+            // as failed
+            testScope.advanceTimeBy(1000)
+            assertThat(latest).isFalse()
+
+            // After 2s, the force validation expires so the connection updates to failed
+            testScope.advanceTimeBy(1001)
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun dataSwitch_inSameGroup_notValidated_immediatelyMarkedAsFailed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+
+            connectionsRepository.mobileIsDefault.value = true
+            connectionsRepository.defaultConnectionIsValidated.value = false
+            runCurrent()
+
+            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun dataSwitch_loseValidation_thenSwitchHappens_clearsForcedBit() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+
+            // GIVEN the network starts validated
+            connectionsRepository.mobileIsDefault.value = true
+            connectionsRepository.defaultConnectionIsValidated.value = true
+            runCurrent()
+
+            // WHEN a data change happens in the same group
+            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+
+            // WHEN the validation bit is lost
+            connectionsRepository.defaultConnectionIsValidated.value = false
+            runCurrent()
+
+            // WHEN another data change happens in the same group
+            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+
+            // THEN the forced validation bit is still used...
+            assertThat(latest).isFalse()
+
+            testScope.advanceTimeBy(1000)
+            assertThat(latest).isFalse()
+
+            // ... but expires after 2s
+            testScope.advanceTimeBy(1001)
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun dataSwitch_whileAlreadyForcingValidation_resetsClock() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isDefaultConnectionFailed)
+            connectionsRepository.mobileIsDefault.value = true
+            connectionsRepository.defaultConnectionIsValidated.value = true
+            runCurrent()
+
+            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+
+            testScope.advanceTimeBy(1000)
+
+            // WHEN another change in same group event happens
+            connectionsRepository.activeSubChangedInGroupEvent.emit(Unit)
+            connectionsRepository.defaultConnectionIsValidated.value = false
+            runCurrent()
+
+            // THEN the forced validation remains for exactly 2 more seconds from now
+
+            // 1.500s from second event
+            testScope.advanceTimeBy(1500)
+            assertThat(latest).isFalse()
+
+            // 2.001s from the second event
+            testScope.advanceTimeBy(501)
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun isForceHidden_repoHasMobileHidden_true() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isForceHidden)
+
+            kosmos.connectivityRepository.fake.setForceHiddenIcons(setOf(ConnectivitySlot.MOBILE))
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    fun isForceHidden_repoDoesNotHaveMobileHidden_false() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isForceHidden)
+
+            kosmos.connectivityRepository.fake.setForceHiddenIcons(setOf(ConnectivitySlot.WIFI))
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun iconInteractor_cachedPerSubId() =
+        kosmos.runTest {
+            val interactor1 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
+            val interactor2 = underTest.getMobileConnectionInteractorForSubId(SUB_1_ID)
+
+            assertThat(interactor1).isNotNull()
+            assertThat(interactor1).isSameInstanceAs(interactor2)
+        }
+
+    @Test
+    fun deviceBasedEmergencyMode_emergencyCallsOnly_followsDeviceServiceStateFromRepo() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isDeviceInEmergencyCallsOnlyMode)
+
+            connectionsRepository.isDeviceEmergencyCallCapable.value = true
+
+            assertThat(latest).isTrue()
+
+            connectionsRepository.isDeviceEmergencyCallCapable.value = false
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    fun defaultDataSubId_tracksRepo() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.defaultDataSubId)
+
+            connectionsRepository.defaultDataSubId.value = 1
+
+            assertThat(latest).isEqualTo(1)
+
+            connectionsRepository.defaultDataSubId.value = 2
+
+            assertThat(latest).isEqualTo(2)
+        }
+
+    @Test
+    @EnableFlags(NewStatusBarIcons.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+    fun isStackable_tracksNumberOfSubscriptions() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isStackable)
+
+            connectionsRepository.setSubscriptions(listOf(SUB_1))
+            assertThat(latest).isFalse()
+
+            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+            assertThat(latest).isTrue()
+
+            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2, SUB_3_OPP))
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @EnableFlags(NewStatusBarIcons.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+    fun isStackable_checksForTerrestrialConnections() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isStackable)
+
+            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+            setNumberOfLevelsForSubId(SUB_1_ID, 5)
+            setNumberOfLevelsForSubId(SUB_2_ID, 5)
+            assertThat(latest).isTrue()
+
+            (fakeMobileConnectionsRepository.getRepoForSubId(SUB_1_ID)
+                    as FakeMobileConnectionRepository)
+                .isNonTerrestrial
+                .value = true
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @EnableFlags(NewStatusBarIcons.FLAG_NAME, StatusBarRootModernization.FLAG_NAME)
+    fun isStackable_checksForNumberOfBars() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isStackable)
+
+            // Number of levels is the same for both
+            connectionsRepository.setSubscriptions(listOf(SUB_1, SUB_2))
+            setNumberOfLevelsForSubId(SUB_1_ID, 5)
+            setNumberOfLevelsForSubId(SUB_2_ID, 5)
+
+            assertThat(latest).isTrue()
+
+            // Change the number of levels to be different than SUB_2
+            setNumberOfLevelsForSubId(SUB_1_ID, 6)
+
+            assertThat(latest).isFalse()
+        }
+
+    private fun setNumberOfLevelsForSubId(subId: Int, numberOfLevels: Int) {
+        with(kosmos) {
+            (fakeMobileConnectionsRepository.getRepoForSubId(subId)
+                    as FakeMobileConnectionRepository)
+                .numberOfLevels
+                .value = numberOfLevels
+        }
+    }
+
+    /**
+     * Convenience method for creating a pair of subscriptions to test the filteredSubscriptions
+     * flow.
+     */
+    private fun createSubscriptionPair(
+        subscriptionIds: Pair<Int, Int>,
+        opportunistic: Pair<Boolean, Boolean> = Pair(false, false),
+        grouped: Boolean = false,
+    ): Pair<SubscriptionModel, SubscriptionModel> {
+        val groupUuid = if (grouped) ParcelUuid(UUID.randomUUID()) else null
+        val sub1 =
+            SubscriptionModel(
+                subscriptionId = subscriptionIds.first,
+                isOpportunistic = opportunistic.first,
+                groupUuid = groupUuid,
+                carrierName = "Carrier ${subscriptionIds.first}",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        val sub2 =
+            SubscriptionModel(
+                subscriptionId = subscriptionIds.second,
+                isOpportunistic = opportunistic.second,
+                groupUuid = groupUuid,
+                carrierName = "Carrier ${opportunistic.second}",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        return Pair(sub1, sub2)
+    }
+
+    companion object {
+
+        private const val SUB_1_ID = 1
+        private val SUB_1 =
+            SubscriptionModel(
+                subscriptionId = SUB_1_ID,
+                carrierName = "Carrier $SUB_1_ID",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        private const val SUB_2_ID = 2
+        private val SUB_2 =
+            SubscriptionModel(
+                subscriptionId = SUB_2_ID,
+                carrierName = "Carrier $SUB_2_ID",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        private const val SUB_3_ID = 3
+        private val SUB_3_OPP =
+            SubscriptionModel(
+                subscriptionId = SUB_3_ID,
+                isOpportunistic = true,
+                groupUuid = ParcelUuid(UUID.randomUUID()),
+                carrierName = "Carrier $SUB_3_ID",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+
+        private const val SUB_4_ID = 4
+        private val SUB_4_OPP =
+            SubscriptionModel(
+                subscriptionId = SUB_4_ID,
+                isOpportunistic = true,
+                groupUuid = ParcelUuid(UUID.randomUUID()),
+                carrierName = "Carrier $SUB_4_ID",
+                profileClass = PROFILE_CLASS_UNSET,
+            )
+    }
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
index f91e3a6..91b3896 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/FakeHomeStatusBarViewModel.kt
@@ -31,6 +31,7 @@
 import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel
 import com.android.systemui.statusbar.phone.domain.interactor.IsAreaDark
 import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel
+import com.android.systemui.statusbar.pipeline.shared.ui.model.ChipsVisibilityModel
 import com.android.systemui.statusbar.pipeline.shared.ui.model.SystemInfoCombinedVisibilityModel
 import com.android.systemui.statusbar.pipeline.shared.ui.model.VisibilityModel
 import kotlinx.coroutines.flow.Flow
@@ -52,7 +53,10 @@
     override val primaryOngoingActivityChip: MutableStateFlow<OngoingActivityChipModel> =
         MutableStateFlow(OngoingActivityChipModel.Inactive())
 
-    override val ongoingActivityChips = MutableStateFlow(MultipleOngoingActivityChipsModel())
+    override val ongoingActivityChips =
+        MutableStateFlow(
+            ChipsVisibilityModel(MultipleOngoingActivityChipsModel(), areChipsAllowed = false)
+        )
 
     override val ongoingActivityChipsLegacy =
         MutableStateFlow(MultipleOngoingActivityChipsModelLegacy())
@@ -62,7 +66,7 @@
     override val mediaProjectionStopDialogDueToCallEndedState =
         MutableStateFlow(MediaProjectionStopDialogModel.Hidden)
 
-    override val isHomeStatusBarAllowedByScene = MutableStateFlow(false)
+    override val isHomeStatusBarAllowed = MutableStateFlow(false)
 
     override val canShowOngoingActivityChips: Flow<Boolean> = MutableStateFlow(false)
 
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
index 7e8ee1b..12cf3b6 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelImplTest.kt
@@ -30,6 +30,7 @@
 import android.view.View
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.display.data.repository.displayRepository
 import com.android.systemui.display.data.repository.fake
@@ -57,6 +58,7 @@
 import com.android.systemui.scene.shared.model.Scenes
 import com.android.systemui.screenrecord.data.model.ScreenRecordModel
 import com.android.systemui.screenrecord.data.repository.screenRecordRepository
+import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository
 import com.android.systemui.shade.shadeTestUtil
 import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.NORMAL_PACKAGE
 import com.android.systemui.statusbar.chips.mediaprojection.domain.interactor.MediaProjectionChipInteractorTest.Companion.setUpPackageManagerForMediaProjection
@@ -64,6 +66,7 @@
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.shareToAppChipViewModel
 import com.android.systemui.statusbar.chips.ui.model.OngoingActivityChipModel
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsCallChip
 import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsScreenRecordChip
 import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModelTest.Companion.assertIsShareToAppChip
 import com.android.systemui.statusbar.core.StatusBarRootModernization
@@ -88,6 +91,7 @@
 import com.android.systemui.statusbar.phone.data.repository.fakeDarkIconRepository
 import com.android.systemui.statusbar.phone.ongoingcall.EnableChipsModernization
 import com.android.systemui.statusbar.phone.ongoingcall.StatusBarChipsModernization
+import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallTestHelper.addOngoingCallState
 import com.android.systemui.statusbar.pipeline.shared.domain.interactor.setHomeStatusBarIconBlockList
 import com.android.systemui.statusbar.pipeline.shared.domain.interactor.setHomeStatusBarInteractorShowOperatorName
 import com.android.systemui.statusbar.pipeline.shared.ui.model.VisibilityModel
@@ -95,7 +99,6 @@
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.runBlocking
-import kotlinx.coroutines.test.runCurrent
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -500,9 +503,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneLockscreen_notOccluded_false() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_sceneLockscreen_notOccluded_false() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
             kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(false, taskInfo = null)
@@ -511,9 +515,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneLockscreen_occluded_true() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_sceneLockscreen_occluded_true() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
             kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(true, taskInfo = null)
@@ -522,9 +527,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_overlayBouncer_false() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_overlayBouncer_false() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
             kosmos.sceneContainerRepository.showOverlay(Overlays.Bouncer)
@@ -533,9 +539,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneCommunal_false() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_sceneCommunal_false() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Communal)
 
@@ -543,9 +550,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneShade_false() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_sceneShade_false() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Shade)
 
@@ -553,9 +561,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneGone_true() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_sceneGone_true() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
 
@@ -563,9 +572,10 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneGoneWithNotificationsShadeOverlay_false() =
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_sceneGoneWithNotificationsShadeOverlay_false() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
             kosmos.sceneContainerRepository.showOverlay(Overlays.NotificationsShade)
@@ -575,12 +585,102 @@
         }
 
     @Test
-    fun isHomeStatusBarAllowedByScene_sceneGoneWithQuickSettingsShadeOverlay_false() =
+    @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_QsVisibleButInExternalDisplay_defaultStatusBarVisible() =
         kosmos.runTest {
-            val latest by collectLastValue(underTest.isHomeStatusBarAllowedByScene)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
 
             kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
             kosmos.sceneContainerRepository.showOverlay(Overlays.QuickSettingsShade)
+            kosmos.fakeShadeDisplaysRepository.setDisplayId(EXTERNAL_DISPLAY)
+            runCurrent()
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    @DisableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_QsVisibleButInExternalDisplay_withFlagOff_defaultStatusBarInvisible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
+
+            kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
+            kosmos.sceneContainerRepository.showOverlay(Overlays.QuickSettingsShade)
+            kosmos.fakeShadeDisplaysRepository.setDisplayId(EXTERNAL_DISPLAY)
+            runCurrent()
+
+            // Shade position is ignored.
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_qsVisibleInThisDisplay_thisStatusBarInvisible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
+
+            kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
+            kosmos.sceneContainerRepository.showOverlay(Overlays.QuickSettingsShade)
+            kosmos.fakeShadeDisplaysRepository.setDisplayId(DEFAULT_DISPLAY)
+            runCurrent()
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_qsExpandedOnDefaultDisplay_statusBarInAnotherDisplay_visible() =
+        kosmos.runTest {
+            val underTest = homeStatusBarViewModelFactory(EXTERNAL_DISPLAY)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
+
+            kosmos.sceneContainerRepository.snapToScene(Scenes.Gone)
+            kosmos.sceneContainerRepository.showOverlay(Overlays.QuickSettingsShade)
+            runCurrent()
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    @EnableSceneContainer
+    fun isHomeStatusBarAllowed_onDefaultDisplayLockscreen_invisible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
+
+            kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
+            runCurrent()
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @EnableSceneContainer
+    @EnableFlags(Flags.FLAG_SHADE_WINDOW_GOES_AROUND)
+    fun isHomeStatusBarAllowed_onExternalDispalyWithLocksceren_invisible() =
+        kosmos.runTest {
+            val underTest = homeStatusBarViewModelFactory(EXTERNAL_DISPLAY)
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
+
+            kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
+            runCurrent()
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @DisableSceneContainer
+    fun isHomeStatusBarAllowed_legacy_onDefaultDisplayLockscreen_invisible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isHomeStatusBarAllowed)
+
+            kosmos.fakeKeyguardTransitionRepository.transitionTo(
+                KeyguardState.GONE,
+                KeyguardState.LOCKSCREEN,
+            )
+
             runCurrent()
 
             assertThat(latest).isFalse()
@@ -716,7 +816,26 @@
         }
 
     @Test
-    fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_hun_false() =
+    @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+    fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_hunBySystem_noHunFlagOff_false() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.canShowOngoingActivityChips)
+
+            transitionKeyguardToGone()
+
+            headsUpNotificationRepository.setNotifications(
+                UnconfinedFakeHeadsUpRowRepository(
+                    key = "key",
+                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem),
+                )
+            )
+
+            assertThat(latest).isFalse()
+        }
+
+    @Test
+    @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+    fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_hunByUser_noHunFlagOff_true() =
         kosmos.runTest {
             val latest by collectLastValue(underTest.canShowOngoingActivityChips)
 
@@ -729,7 +848,177 @@
                 )
             )
 
-            assertThat(latest).isFalse()
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+    fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_hunBySystem_noHunFlagOn_true() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.canShowOngoingActivityChips)
+
+            transitionKeyguardToGone()
+
+            headsUpNotificationRepository.setNotifications(
+                UnconfinedFakeHeadsUpRowRepository(
+                    key = "key",
+                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem),
+                )
+            )
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+    fun canShowOngoingActivityChips_statusBarNotHidden_noSecureCamera_hunByUser_noHunFlagOn_true() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.canShowOngoingActivityChips)
+
+            transitionKeyguardToGone()
+
+            headsUpNotificationRepository.setNotifications(
+                UnconfinedFakeHeadsUpRowRepository(
+                    key = "key",
+                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser),
+                )
+            )
+
+            assertThat(latest).isTrue()
+        }
+
+    @Test
+    @EnableChipsModernization
+    fun ongoingActivityChips_statusBarHidden_noSecureCamera_noHun_notAllowed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.ongoingActivityChips)
+
+            // home status bar not allowed
+            kosmos.sceneContainerRepository.snapToScene(Scenes.Lockscreen)
+            kosmos.keyguardOcclusionRepository.setShowWhenLockedActivityInfo(false, taskInfo = null)
+
+            assertThat(latest!!.areChipsAllowed).isFalse()
+        }
+
+    @Test
+    @EnableChipsModernization
+    fun ongoingActivityChips_statusBarNotHidden_noSecureCamera_noHun_isAllowed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.ongoingActivityChips)
+
+            transitionKeyguardToGone()
+
+            assertThat(latest!!.areChipsAllowed).isTrue()
+        }
+
+    @Test
+    @EnableChipsModernization
+    fun ongoingActivityChips_statusBarNotHidden_secureCamera_noHun_notAllowed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.ongoingActivityChips)
+
+            fakeKeyguardTransitionRepository.sendTransitionSteps(
+                from = KeyguardState.LOCKSCREEN,
+                to = KeyguardState.OCCLUDED,
+                testScope = testScope,
+            )
+            kosmos.keyguardInteractor.onCameraLaunchDetected(CAMERA_LAUNCH_SOURCE_POWER_DOUBLE_TAP)
+
+            assertThat(latest!!.areChipsAllowed).isFalse()
+        }
+
+    @Test
+    @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+    @EnableChipsModernization
+    fun ongoingActivityChips_statusBarNotHidden_noSecureCamera_hunBySystem_noHunFlagOff_notAllowed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.ongoingActivityChips)
+
+            transitionKeyguardToGone()
+
+            headsUpNotificationRepository.setNotifications(
+                UnconfinedFakeHeadsUpRowRepository(
+                    key = "key",
+                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem),
+                )
+            )
+
+            assertThat(latest!!.areChipsAllowed).isFalse()
+        }
+
+    @Test
+    @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+    @EnableChipsModernization
+    fun ongoingActivityChips_statusBarNotHidden_noSecureCamera_hunByUser_noHunFlagOff_isAllowed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.ongoingActivityChips)
+
+            transitionKeyguardToGone()
+
+            headsUpNotificationRepository.setNotifications(
+                UnconfinedFakeHeadsUpRowRepository(
+                    key = "key",
+                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser),
+                )
+            )
+
+            assertThat(latest!!.areChipsAllowed).isTrue()
+        }
+
+    @Test
+    @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+    @EnableChipsModernization
+    fun ongoingActivityChips_tatusBarNotHidden_noSecureCamera_hunBySystem_noHunFlagOn_isAllowed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.ongoingActivityChips)
+
+            transitionKeyguardToGone()
+
+            headsUpNotificationRepository.setNotifications(
+                UnconfinedFakeHeadsUpRowRepository(
+                    key = "key",
+                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem),
+                )
+            )
+
+            assertThat(latest!!.areChipsAllowed).isTrue()
+        }
+
+    @Test
+    @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+    @EnableChipsModernization
+    fun ongoingActivityChips_statusBarNotHidden_noSecureCamera_hunByUser_noHunFlagOn_isAllowed() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.ongoingActivityChips)
+
+            transitionKeyguardToGone()
+
+            headsUpNotificationRepository.setNotifications(
+                UnconfinedFakeHeadsUpRowRepository(
+                    key = "key",
+                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser),
+                )
+            )
+
+            assertThat(latest!!.areChipsAllowed).isTrue()
+        }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    @EnableChipsModernization
+    fun ongoingActivityChips_followsChipsViewModel() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.ongoingActivityChips)
+            transitionKeyguardToGone()
+
+            screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+
+            assertIsScreenRecordChip(latest!!.chips.active[0])
+
+            addOngoingCallState(key = "call")
+
+            assertIsScreenRecordChip(latest!!.chips.active[0])
+            assertIsCallChip(latest!!.chips.active[1], "call", context)
         }
 
     @Test
@@ -892,7 +1181,7 @@
 
     @Test
     @EnableChipsModernization
-    fun isNotificationIconContainerVisible_anyChipShowing_ChipsModernizationOn() =
+    fun isNotificationIconContainerVisible_anyChipShowing_chipsModernizationOn() =
         kosmos.runTest {
             val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
             transitionKeyguardToGone()
@@ -909,7 +1198,7 @@
     @Test
     @DisableFlags(StatusBarRootModernization.FLAG_NAME, StatusBarChipsModernization.FLAG_NAME)
     @EnableFlags(StatusBarNotifChips.FLAG_NAME)
-    fun isNotificationIconContainerVisible_anyChipShowing_PromotedNotifsOn() =
+    fun isNotificationIconContainerVisible_anyChipShowing_promotedNotifsOn() =
         kosmos.runTest {
             val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
             transitionKeyguardToGone()
@@ -929,7 +1218,7 @@
         StatusBarRootModernization.FLAG_NAME,
         StatusBarChipsModernization.FLAG_NAME,
     )
-    fun isNotificationIconContainerVisible_anyChipShowing_ChipsModernizationAndPromotedNotifsOff() =
+    fun isNotificationIconContainerVisible_anyChipShowing_chipsModernizationAndPromotedNotifsOff() =
         kosmos.runTest {
             val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
             transitionKeyguardToGone()
@@ -943,6 +1232,86 @@
             assertThat(latest!!.visibility).isEqualTo(View.VISIBLE)
         }
 
+    @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+    fun isNotificationIconContainerVisible_hasChipButAlsoHun_hunBySystem_noHunFlagOff_visible() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
+            transitionKeyguardToGone()
+
+            // Chip
+            kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+
+            // HUN, PinnedBySystem
+            headsUpNotificationRepository.setNotifications(
+                UnconfinedFakeHeadsUpRowRepository(
+                    key = "key",
+                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem),
+                )
+            )
+
+            assertThat(latest!!.visibility).isEqualTo(View.VISIBLE)
+        }
+
+    @DisableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+    fun isNotificationIconContainerVisible_hasChipButAlsoHun_hunByUser_noHunFlagOff_gone() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
+            transitionKeyguardToGone()
+
+            // Chip
+            kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+
+            // HUN, PinnedByUser
+            headsUpNotificationRepository.setNotifications(
+                UnconfinedFakeHeadsUpRowRepository(
+                    key = "key",
+                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser),
+                )
+            )
+
+            assertThat(latest!!.visibility).isEqualTo(View.GONE)
+        }
+
+    @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+    fun isNotificationIconContainerVisible_hasChipButAlsoHun_hunBySystem_noHunFlagOn_gone() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
+            transitionKeyguardToGone()
+
+            // Chip
+            kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+
+            // HUN, PinnedBySystem
+            headsUpNotificationRepository.setNotifications(
+                UnconfinedFakeHeadsUpRowRepository(
+                    key = "key",
+                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedBySystem),
+                )
+            )
+
+            assertThat(latest!!.visibility).isEqualTo(View.GONE)
+        }
+
+    @EnableFlags(StatusBarNoHunBehavior.FLAG_NAME)
+    fun isNotificationIconContainerVisible_hasChipButAlsoHun_hunByUser_noHunFlagOn_gone() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.isNotificationIconContainerVisible)
+            transitionKeyguardToGone()
+
+            // Chip
+            kosmos.screenRecordRepository.screenRecordState.value = ScreenRecordModel.Recording
+
+            // HUN, PinnedByUser
+            headsUpNotificationRepository.setNotifications(
+                UnconfinedFakeHeadsUpRowRepository(
+                    key = "key",
+                    pinnedStatus = MutableStateFlow(PinnedStatus.PinnedByUser),
+                )
+            )
+
+            assertThat(latest!!.visibility).isEqualTo(View.GONE)
+        }
+
     @Test
     fun isSystemInfoVisible_allowedByDisableFlags_visible() =
         kosmos.runTest {
@@ -1289,4 +1658,8 @@
             testScope = testScope,
         )
     }
+
+    private companion object {
+        const val EXTERNAL_DISPLAY = 1
+    }
 }
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
index 769f012..8722a48 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/window/MultiDisplayStatusBarWindowControllerStoreTest.kt
@@ -23,6 +23,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.display.data.repository.displayRepository
 import com.android.systemui.kosmos.testScope
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.testKosmos
 import kotlinx.coroutines.runBlocking
@@ -37,7 +38,7 @@
 @RunWith(AndroidJUnit4::class)
 @EnableFlags(StatusBarConnectedDisplays.FLAG_NAME)
 class MultiDisplayStatusBarWindowControllerStoreTest : SysuiTestCase() {
-    private val kosmos = testKosmos()
+    private val kosmos = testKosmos().useUnconfinedTestDispatcher()
     private val fakeDisplayRepository = kosmos.displayRepository
     private val testScope = kosmos.testScope
 
@@ -59,11 +60,11 @@
         }
 
     @Test
-    fun displayRemoved_stopsInstance() =
+    fun systemDecorationRemovedEvent_stopsInstance() =
         testScope.runTest {
             val instance = underTest.forDisplay(DEFAULT_DISPLAY)!!
 
-            fakeDisplayRepository.removeDisplay(DEFAULT_DISPLAY)
+            fakeDisplayRepository.triggerRemoveSystemDecorationEvent(DEFAULT_DISPLAY)
 
             verify(instance).stop()
         }
diff --git a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt
index 4c1f645..b52db83 100644
--- a/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt
+++ b/packages/SystemUI/plugin/src/com/android/systemui/plugins/clocks/ClockController.kt
@@ -42,9 +42,13 @@
         isDarkTheme: Boolean,
         dozeFraction: Float,
         foldFraction: Float,
-        onBoundsChanged: (RectF) -> Unit,
+        clockListener: ClockEventListener?,
     )
 
     /** Optional method for dumping debug information */
     fun dump(pw: PrintWriter)
 }
+
+interface ClockEventListener {
+    fun onBoundsChanged(bounds: RectF)
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt
similarity index 87%
rename from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt
rename to packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt
index 3e39ae9..0c46e07 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt
+++ b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/DisplaySpecific.kt
@@ -18,4 +18,7 @@
 import javax.inject.Qualifier
 
 /** Annotates a class that is display specific. */
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class DisplaySpecific
+@Qualifier
+@MustBeDocumented
+@Retention(AnnotationRetention.RUNTIME)
+public annotation class DisplaySpecific
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Main.java b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Main.java
similarity index 100%
rename from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Main.java
rename to packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/Main.java
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/UiBackground.java b/packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/UiBackground.java
similarity index 100%
rename from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/UiBackground.java
rename to packages/SystemUI/pods/com/android/systemui/dagger/qualifiers/UiBackground.java
diff --git a/packages/SystemUI/res-keyguard/drawable/qs_media_recommendation_bg_gradient.xml b/packages/SystemUI/res-keyguard/drawable/qs_media_recommendation_bg_gradient.xml
deleted file mode 100644
index 495fbb8..0000000
--- a/packages/SystemUI/res-keyguard/drawable/qs_media_recommendation_bg_gradient.xml
+++ /dev/null
@@ -1,26 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!-- Copyright (C) 2021 The Android Open Source Project
-
-     Licensed under the Apache License, Version 2.0 (the "License");
-     you may not use this file except in compliance with the License.
-     You may obtain a copy of the License at
-
-          http://www.apache.org/licenses/LICENSE-2.0
-
-     Unless required by applicable law or agreed to in writing, software
-     distributed under the License is distributed on an "AS IS" BASIS,
-     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
-     See the License for the specific language governing permissions and
-     limitations under the License.
--->
-
-<shape
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <corners android:radius="24dp"/>
-    <gradient
-        android:angle="0"
-        android:startColor="#00000000"
-        android:endColor="#ff000000"
-        android:type="linear" />
-</shape>
diff --git a/packages/SystemUI/res/drawable/media_output_dialog_seekbar_background.xml b/packages/SystemUI/res/drawable/media_output_dialog_seekbar_background.xml
index adeb81f..592217b 100644
--- a/packages/SystemUI/res/drawable/media_output_dialog_seekbar_background.xml
+++ b/packages/SystemUI/res/drawable/media_output_dialog_seekbar_background.xml
@@ -23,16 +23,24 @@
             />
             <solid android:color="@android:color/transparent" />
             <size
-                android:height="64dp"/>
+                android:height="@dimen/media_output_dialog_item_height"/>
+        </shape>
+    </item>
+    <item android:id="@+id/contrast_dot" android:right="8dp" android:gravity="center_vertical|end">
+        <shape android:shape="oval">
+            <solid android:color="@color/media_dialog_seekbar_progress" />
+            <size
+                android:width="4dp"
+                android:height="4dp" />
         </shape>
     </item>
     <item android:id="@android:id/progress">
         <clip>
             <shape>
                 <corners
-                    android:radius="16dp"/>
+                    android:radius="@dimen/media_output_dialog_background_radius"/>
                 <size
-                    android:height="64dp"/>
+                    android:height="@dimen/media_output_dialog_item_height"/>
                 <solid android:color="@color/material_dynamic_primary80" />
             </shape>
         </clip>
diff --git a/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml b/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml
deleted file mode 100644
index de0a620..0000000
--- a/packages/SystemUI/res/drawable/qs_media_rec_scrim.xml
+++ /dev/null
@@ -1,25 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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
-  -->
-<shape xmlns:android="http://schemas.android.com/apk/res/android"
-    android:shape="rectangle">
-    <!-- gradient from 25% in the center to 100% at edges -->
-    <gradient
-        android:type="radial"
-        android:gradientRadius="40%p"
-        android:startColor="#AE000000"
-        android:endColor="#00000000" />
-</shape>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/settingslib_track_off_background.xml b/packages/SystemUI/res/drawable/settingslib_track_off_background.xml
index 3a09284..284953a 100644
--- a/packages/SystemUI/res/drawable/settingslib_track_off_background.xml
+++ b/packages/SystemUI/res/drawable/settingslib_track_off_background.xml
@@ -23,4 +23,5 @@
              android:right="@dimen/settingslib_switch_thumb_margin"/>
     <solid android:color="@color/settingslib_track_off_color"/>
     <corners android:radius="@dimen/settingslib_switch_track_radius"/>
+    <stroke android:width="2dp" android:color="@color/settingslib_track_online_color"/>
 </shape>
diff --git a/packages/SystemUI/res/layout/magic_action_button.xml b/packages/SystemUI/res/layout/magic_action_button.xml
index 381d6b1..63fc1e4 100644
--- a/packages/SystemUI/res/layout/magic_action_button.xml
+++ b/packages/SystemUI/res/layout/magic_action_button.xml
@@ -6,7 +6,7 @@
     android:background="@drawable/magic_action_button_background"
     android:drawablePadding="@dimen/magic_action_button_drawable_padding"
     android:ellipsize="none"
-    android:fontFamily="google-sans-flex"
+    android:fontFamily="google-sans-flex-medium"
     android:gravity="center"
     android:minWidth="0dp"
     android:paddingHorizontal="@dimen/magic_action_button_padding_horizontal"
diff --git a/packages/SystemUI/res/layout/media_output_list_item_advanced.xml b/packages/SystemUI/res/layout/media_output_list_item_advanced.xml
index 6b868b3..ec80cf0 100644
--- a/packages/SystemUI/res/layout/media_output_list_item_advanced.xml
+++ b/packages/SystemUI/res/layout/media_output_list_item_advanced.xml
@@ -151,6 +151,8 @@
         <ImageButton
             android:id="@+id/end_area_image_button"
             android:background="@android:color/transparent"
+            android:padding="20dp"
+            android:scaleType="fitCenter"
             android:layout_width="match_parent"
             android:layout_height="match_parent"
             android:contentDescription="@null"
diff --git a/packages/SystemUI/res/layout/media_recommendation_view.xml b/packages/SystemUI/res/layout/media_recommendation_view.xml
deleted file mode 100644
index e63aa21..0000000
--- a/packages/SystemUI/res/layout/media_recommendation_view.xml
+++ /dev/null
@@ -1,90 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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
-  -->
-<!-- Layout for media recommendation item inside QSPanel carousel -->
-<merge xmlns:android="http://schemas.android.com/apk/res/android">
-    <!-- Album cover -->
-    <ImageView
-        android:id="@+id/media_cover"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        android:translationZ="0dp"
-        android:scaleType="matrix"
-        android:adjustViewBounds="true"
-        android:clipToOutline="true"
-        android:layerType="hardware"
-        android:background="@drawable/bg_smartspace_media_item"/>
-
-    <!-- App icon -->
-    <com.android.internal.widget.CachingIconView
-        android:id="@+id/media_rec_app_icon"
-        android:layout_width="@dimen/qs_media_rec_album_icon_size"
-        android:layout_height="@dimen/qs_media_rec_album_icon_size"
-        android:minWidth="@dimen/qs_media_rec_album_icon_size"
-        android:minHeight="@dimen/qs_media_rec_album_icon_size"
-        android:layout_marginStart="@dimen/qs_media_info_spacing"
-        android:layout_marginTop="@dimen/qs_media_info_spacing"/>
-
-    <!-- Artist name -->
-    <TextView
-        android:id="@+id/media_title"
-        android:layout_width="match_parent"
-        android:layout_height="wrap_content"
-        android:layout_marginStart="@dimen/qs_media_info_spacing"
-        android:layout_marginEnd="@dimen/qs_media_info_spacing"
-        android:layout_marginBottom="@dimen/qs_media_rec_album_title_bottom_margin"
-        android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-        android:singleLine="true"
-        android:textSize="12sp"
-        android:gravity="top"
-        android:layout_gravity="bottom"
-        android:importantForAccessibility="no"/>
-
-    <!-- Album name -->
-    <TextView
-        android:id="@+id/media_subtitle"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/qs_media_rec_album_subtitle_height"
-        android:layout_marginEnd="@dimen/qs_media_info_spacing"
-        android:layout_marginStart="@dimen/qs_media_info_spacing"
-        android:layout_marginBottom="@dimen/qs_media_info_spacing"
-        android:fontFamily="@*android:string/config_headlineFontFamily"
-        android:singleLine="true"
-        android:textSize="11sp"
-        android:gravity="center_vertical"
-        android:layout_gravity="bottom"
-        android:importantForAccessibility="no"/>
-
-    <!-- Seek Bar -->
-    <SeekBar
-        android:id="@+id/media_progress_bar"
-        android:layout_width="match_parent"
-        android:layout_height="12dp"
-        android:layout_gravity="bottom"
-        android:maxHeight="@dimen/qs_media_enabled_seekbar_height"
-        android:thumb="@android:color/transparent"
-        android:splitTrack="false"
-        android:clickable="false"
-        android:progressTint="?android:attr/textColorPrimary"
-        android:progressBackgroundTint="?android:attr/textColorTertiary"
-        android:paddingTop="5dp"
-        android:paddingBottom="5dp"
-        android:paddingStart="0dp"
-        android:paddingEnd="0dp"
-        android:layout_marginEnd="@dimen/qs_media_info_spacing"
-        android:layout_marginStart="@dimen/qs_media_info_spacing"
-        android:layout_marginBottom="@dimen/qs_media_info_spacing"/>
-</merge>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/media_recommendations.xml b/packages/SystemUI/res/layout/media_recommendations.xml
deleted file mode 100644
index 65fc19c..0000000
--- a/packages/SystemUI/res/layout/media_recommendations.xml
+++ /dev/null
@@ -1,75 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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
-  -->
-
-<!-- Layout for media recommendations inside QSPanel carousel -->
-<com.android.systemui.util.animation.TransitionLayout
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    android:id="@+id/media_recommendations_updated"
-    android:layout_width="match_parent"
-    android:layout_height="wrap_content"
-    android:clipChildren="false"
-    android:clipToPadding="false"
-    android:forceHasOverlappingRendering="false"
-    android:background="@drawable/qs_media_background"
-    android:theme="@style/MediaPlayer">
-
-    <!-- This view just ensures the full media player is a certain height. -->
-    <View
-        android:id="@+id/sizing_view"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/qs_media_session_height_expanded" />
-
-    <TextView
-        android:id="@+id/media_rec_title"
-        style="@style/MediaPlayer.Recommendation.Header"
-        android:text="@string/controls_media_smartspace_rec_header"/>
-
-    <FrameLayout
-        android:id="@+id/media_cover1_container"
-        style="@style/MediaPlayer.Recommendation.AlbumContainer.Updated"
-        >
-
-        <include
-            layout="@layout/media_recommendation_view"/>
-
-    </FrameLayout>
-
-
-    <FrameLayout
-        android:id="@+id/media_cover2_container"
-        style="@style/MediaPlayer.Recommendation.AlbumContainer.Updated"
-        >
-
-        <include
-            layout="@layout/media_recommendation_view"/>
-
-    </FrameLayout>
-
-    <FrameLayout
-        android:id="@+id/media_cover3_container"
-        style="@style/MediaPlayer.Recommendation.AlbumContainer.Updated"
-        >
-
-        <include
-            layout="@layout/media_recommendation_view"/>
-
-    </FrameLayout>
-
-    <include
-        layout="@layout/media_long_press_menu" />
-
-</com.android.systemui.util.animation.TransitionLayout>
diff --git a/packages/SystemUI/res/layout/volume_dialog.xml b/packages/SystemUI/res/layout/volume_dialog.xml
index f41eaec..a1fa54c 100644
--- a/packages/SystemUI/res/layout/volume_dialog.xml
+++ b/packages/SystemUI/res/layout/volume_dialog.xml
@@ -40,7 +40,7 @@
         android:layout_marginBottom="@dimen/volume_dialog_components_spacing"
         android:clipChildren="false"
         app:layout_constraintBottom_toTopOf="@id/volume_dialog_main_slider_container"
-        app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintEnd_toEndOf="@id/volume_dialog_background"
         app:layout_constraintHeight_default="spread"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
@@ -70,9 +70,9 @@
         android:layout_marginTop="@dimen/volume_dialog_components_spacing"
         android:clipChildren="false"
         app:layout_constraintBottom_toBottomOf="parent"
-        app:layout_constraintEnd_toEndOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintEnd_toEndOf="@id/volume_dialog_background"
         app:layout_constraintHeight_default="wrap"
-        app:layout_constraintStart_toStartOf="@id/volume_dialog_main_slider_container"
+        app:layout_constraintStart_toStartOf="@id/volume_dialog_background"
         app:layout_constraintTop_toBottomOf="@id/volume_dialog_main_slider_container"
         app:layout_constraintVertical_bias="0"
         app:layout_constraintWidth_default="wrap">
diff --git a/packages/SystemUI/res/layout/volume_dialog_top_section.xml b/packages/SystemUI/res/layout/volume_dialog_top_section.xml
index 29f5248..b745547 100644
--- a/packages/SystemUI/res/layout/volume_dialog_top_section.xml
+++ b/packages/SystemUI/res/layout/volume_dialog_top_section.xml
@@ -22,7 +22,7 @@
     android:clipChildren="false"
     android:clipToPadding="false"
     android:gravity="center"
-    android:paddingEnd="@dimen/volume_dialog_ringer_drawer_diff_end_margin"
+    android:paddingEnd="@dimen/volume_dialog_buttons_margin"
     app:layoutDescription="@xml/volume_dialog_ringer_drawer_motion_scene">
 
     <View
diff --git a/packages/SystemUI/res/values-af/strings.xml b/packages/SystemUI/res/values-af/strings.xml
index d8e08fc..cbec8c2 100644
--- a/packages/SystemUI/res/values-af/strings.xml
+++ b/packages/SystemUI/res/values-af/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Gekoppel aan <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Gekoppel aan <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Vou groep uit."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Voeg toestel by groep."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Verwyder toestel uit groep."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Maak app oop."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nie gekoppel nie."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Swerwing"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Gehoortoestelle"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Skakel tans aan …"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Kan nie helderheid verstel nie omdat dit deur die boonste app beheer word"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Outodraai"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Outodraai skerm"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ligging"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Omgewing"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Links"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Regs"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Vou uit na links- en regsgeskeide kontroles"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Vou in na verenigde kontrole"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Demp omgewing"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Wys laeprioriteit-kennisgewingikone"</string>
     <string name="other" msgid="429768510980739978">"Ander"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"wissel die teël se grootte"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"verwyder teël"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"voeg teël by die laaste posisie"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Skuif teël"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Voeg by posisie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posisie is ongeldig."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Teël is bygevoeg"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Teël is verwyder"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Kitsinstellingswysiger."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Swiep op en hou met drie vingers op die raakpaneel om onlangse apps te bekyk"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Druk die handelingsleutel op jou sleutelbord om al jou apps te bekyk"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Gewysig"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Ontsluit om te kyk"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Ontsluit om kode te kyk"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstuele opvoeding"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Gebruik jou raakpaneel om terug te gaan"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swiep links of regs met drie vingers. Tik om meer gebare te leer."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Onbekend"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Stel alle teëls terug?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle Kitsinstellingsteëls sal na die toestel se oorspronklike instellings teruggestel word"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-am/strings.xml b/packages/SystemUI/res/values-am/strings.xml
index ea51f00..655f060 100644
--- a/packages/SystemUI/res/values-am/strings.xml
+++ b/packages/SystemUI/res/values-am/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ከ<xliff:g id="BLUETOOTH">%s</xliff:g> ጋር ተገናኝቷል።"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"ከ<xliff:g id="CAST">%s</xliff:g> ጋር ተገናኝቷል።"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ቡድንን ዘርጋ።"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"መሣሪያን ወደ ቡድን አክል።"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"መሣሪያን ከቡድን ላይ አስወግድ።"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"መተግበሪያ ክፈት።"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"አልተገናኘም።"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"በማዛወር ላይ"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ግቤት"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"መስሚያ አጋዥ መሣሪያዎች"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"በማብራት ላይ..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ከላይ ባለው መተግበሪያ ቁጥጥር እየተደረገበት ስለሆነ ብሩህነትን ማስተካከል አልተቻለም"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"በራስ ሰር አሽከርክር"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ማያ ገጽን በራስ-አሽከርክር"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"አካባቢ"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"በዙሪያ ያሉ"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ግራ"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ቀኝ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ወደ ግራ እና ቀኝ የተለያዩ ቁጥጥሮች ዘርጋ"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ወደ የተዋሃደ ቁጥጥር ሰብስብ"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"በዙሪያ ያሉትን ድምፀ-ከል አድርግ"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"አነስተኛ ቅድሚያ ያላቸው የማሳወቂያ አዶዎችን አሳይ"</string>
     <string name="other" msgid="429768510980739978">"ሌላ"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"የርዕሱን መጠን ይቀያይሩ"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ሰቅ አስወግድ"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"በመጨረሻው ቦታ ላይ ሰቅ ያክሉ"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ሰቁን ውሰድ"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ወደ <xliff:g id="POSITION">%1$d</xliff:g> ቦታ አክል"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"አቀማመጡ ተቀባይነት የለውም።"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"የ<xliff:g id="POSITION">%1$d</xliff:g> አቀማመጥ"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ሰቅ ታክሏል"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ሰቅ ተወግዷል"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"የፈጣን ቅንብሮች አርታዒ።"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"የቅርብ ጊዜ መተግበሪያዎችን ለማየት የመዳሰሻ ሰሌዳው ላይ በሦስት ጣቶች ወደላይ ያንሸራትቱ እና ይያዙ"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"ሁሉንም መተግበሪያዎችዎን ለማየት በቁልፍ ሰሌዳዎ ላይ ያለውን የተግባር ቁልፍ ይጫኑ"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"ጽሁፍ ተቀይሯል"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"ለመመልከት ይክፈቱ"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"ኮድን ለመመልከት ይክፈቱ"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"የዓውድ ትምህርት"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ለመመለስ የመዳሰሻ ሰሌዳዎን ይጠቀሙ"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ሦስት ጣቶችን በመጠቀም ወደ ግራ ወይም ወደ ቀኝ ያንሸራትቱ። ምልክቶችን የበለጠ ለማወቅ መታ ያድርጉ።"</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ያልታወቀ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ሁሉም ሰቆች ዳግም ይጀምሩ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ሁሉም የፈጣን ቅንብሮች ሰቆች ወደ የመሣሪያው የመጀመሪያ ቅንብሮች ዳግም ይጀምራሉ"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>፣ <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ar/strings.xml b/packages/SystemUI/res/values-ar/strings.xml
index 99c156b..b2d71da 100644
--- a/packages/SystemUI/res/values-ar/strings.xml
+++ b/packages/SystemUI/res/values-ar/strings.xml
@@ -245,20 +245,15 @@
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"تم توصيل البلوتوث."</string>
     <string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"رمز الجهاز الذي يتضمّن بلوتوث"</string>
     <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"انقر هنا لضبط إعدادات الجهاز."</string>
-    <!-- no translation found for accessibility_bluetooth_device_settings_gear_with_name (114373701123165491) -->
-    <skip />
-    <!-- no translation found for accessibility_bluetooth_device_settings_see_all (5260390270128256620) -->
-    <skip />
-    <!-- no translation found for accessibility_bluetooth_device_settings_pair_new_device (7988547106800504256) -->
-    <skip />
+    <string name="accessibility_bluetooth_device_settings_gear_with_name" msgid="114373701123165491">"‫<xliff:g id="DEVICE_NAME">%s</xliff:g>. ضبط تفاصيل الجهاز"</string>
+    <string name="accessibility_bluetooth_device_settings_see_all" msgid="5260390270128256620">"عرض جميع الأجهزة"</string>
+    <string name="accessibility_bluetooth_device_settings_pair_new_device" msgid="7988547106800504256">"إقران جهاز جديد"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"نسبة شحن البطارية غير معروفة."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"متصل بـ <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"تم الاتصال بـ <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"سيتم توسيع المجموعة."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"إضافة الجهاز إلى المجموعة"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"إزالة الجهاز من المجموعة"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"سيتم فتح التطبيق."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"غير متصل."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"التجوال"</string>
@@ -336,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"الإدخال"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"سماعات الأذن الطبية"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"جارٍ التفعيل…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"لا يمكن ضبط مستوى السطوع لأنّ التطبيق العلوي يتحكّم فيه"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"التدوير التلقائي"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"التدوير التلقائي للشاشة"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"الموقع الجغرافي"</string>
@@ -427,8 +421,14 @@
     <string name="hearing_devices_preset_label" msgid="7878267405046232358">"الإعدادات المسبقة"</string>
     <string name="hearing_devices_spinner_item_selected" msgid="3137083889662762383">"تمّ اختياره"</string>
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"الأصوات المحيطة"</string>
-    <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"الجهاز الأيسر"</string>
-    <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"الجهاز الأيمن"</string>
+    <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"اليسرى"</string>
+    <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"اليمنى"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"توسيع لوحة التحكّم الموحّدة إلى عناصر تحكُّم منفصلة على اليسار واليمين"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"تصغير عناصر التحكّم في الصوت إلى لوحة تحكُّم موحّدة"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"كتم الأصوات المحيطة"</string>
@@ -906,10 +906,8 @@
     <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"تعدُّد المهام"</string>
     <string name="system_multitasking_rhs" msgid="8779289852395243004">"استخدام \"وضع تقسيم الشاشة\" مع تثبيت التطبيق على اليمين"</string>
     <string name="system_multitasking_lhs" msgid="7348595296208696452">"استخدام \"وضع تقسيم الشاشة\" مع تثبيت التطبيق على اليسار"</string>
-    <!-- no translation found for system_multitasking_full_screen (4221409316059910349) -->
-    <skip />
-    <!-- no translation found for system_multitasking_desktop_view (8829838918507805921) -->
-    <skip />
+    <string name="system_multitasking_full_screen" msgid="4221409316059910349">"استخدام وضع ملء الشاشة"</string>
+    <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"استخدام وضع العرض المخصّص للكمبيوتر المكتبي"</string>
     <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"التبديل إلى التطبيق على اليسار أو الأسفل أثناء استخدام \"تقسيم الشاشة\""</string>
     <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"التبديل إلى التطبيق على اليمين أو الأعلى أثناء استخدام \"تقسيم الشاشة\""</string>
     <string name="system_multitasking_replace" msgid="7410071959803642125">"استبدال تطبيق بآخر في وضع \"تقسيم الشاشة\""</string>
@@ -1005,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"الإضافة إلى الموضع <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"الموضِع غير صالح."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"الموضع: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"تمت إضافة البطاقة."</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"تمت إزالة البطاقة."</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"برنامج تعديل الإعدادات السريعة."</string>
@@ -1511,8 +1511,7 @@
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"عرض التطبيقات المستخدَمة مؤخرًا"</string>
     <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"التبديل بين التطبيقات"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"تم"</string>
-    <!-- no translation found for touchpad_tutorial_next_button (9169718126626806688) -->
-    <skip />
+    <string name="touchpad_tutorial_next_button" msgid="9169718126626806688">"التالي"</string>
     <string name="gesture_error_title" msgid="469064941635578511">"يُرجى إعادة المحاولة"</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"رجوع"</string>
     <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"مرِّر سريعًا لليمين أو لليسار باستخدام 3 أصابع على لوحة اللمس"</string>
@@ -1574,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"غير معروفة"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"هل تريد إعادة ضبط كل المربّعات؟"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ستتم إعادة ضبط جميع مربّعات \"الإعدادات السريعة\" إلى الإعدادات الأصلية للجهاز"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"\"<xliff:g id="STREAM_NAME">%1$s</xliff:g>\"، <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-as/strings.xml b/packages/SystemUI/res/values-as/strings.xml
index 17d24da..6aa9d66 100644
--- a/packages/SystemUI/res/values-as/strings.xml
+++ b/packages/SystemUI/res/values-as/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>ৰ লগত সংযোগ কৰা হ’ল।"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>ত সংযোগ হ’ল।"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"গোট বিস্তাৰ কৰক।"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"গোটত ডিভাইচ যোগ দিয়ক।"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"গোটৰ পৰা ডিভাইচ আঁতৰাওক।"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"এপ্লিকেশ্বনটো খোলক।"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"সংযোগ হৈ থকা নাই।"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ৰ\'মিং"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ইনপুট"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"শ্ৰৱণ যন্ত্ৰ"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"অন কৰি থকা হৈছে…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"উজ্জ্বলতা মিলাব নোৱাৰি কাৰণ সেয়া শীৰ্ষৰ এপটোৱে নিয়ন্ত্ৰণ কৰি আছে"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"স্বয়ং-ঘূৰ্ণন"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"স্বয়ং-ঘূৰ্ণন স্ক্ৰীন"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"অৱস্থান"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"আশ-পাশ"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"বাওঁফাল"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"সোঁফাল"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"বাওঁ আৰু সোঁফালৰ পৃথক কৰা নিয়ন্ত্ৰণলৈ সংকোচন কৰক"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"একত্ৰিত নিয়ন্ত্ৰণলৈ সংকোচন কৰক"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"আশ-পাশৰ ধ্বনি মিউট কৰক"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"কম গুৰুত্বপূৰ্ণ জাননীৰ আইকনসমূহ দেখুৱাওক"</string>
     <string name="other" msgid="429768510980739978">"অন্যান্য"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"টাইলৰ আকাৰ ট’গল কৰক"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"টাইল আঁতৰাবলৈ"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"অন্তিম স্থানত টাইল যোগ দিয়ক"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"টাইল স্থানান্তৰ কৰক"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> নম্বৰ স্থানত যোগ দিয়ক"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"স্থান অমান্য।"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> নম্বৰ স্থান"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"টাইল যোগ দিয়া হৈছে"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"টাইল আঁতৰোৱা হৈছে"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ক্ষিপ্ৰ ছেটিঙৰ সম্পাদক।"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"শেহতীয়া এপ্‌সমূহ চাবলৈ টাচ্চপেডখনত তিনিটা আঙুলিৰে ওপৰলৈ ছোৱাইপ কৰি ধৰি ৰাখক"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"আপোনাৰ আটাইবোৰ এপ্‌ চাবলৈ আপোনাৰ কীব’ৰ্ডৰ কাৰ্য কীটোত টিপক"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"সম্পাদনা কৰা হৈছে"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"চাবলৈ আনলক কৰক"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"ক’ড চাবলৈ আনলক কৰক"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"প্ৰাসংগিক শিক্ষা"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"উভতি যাবলৈ আপোনাৰ টাচ্চপেড ব্যৱহাৰ কৰক"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"তিনিটা আঙুলি ব্যৱহাৰ কৰি বাওঁফাললৈ বা সোঁফাললৈ ছোৱাইপ কৰক। অধিক নিৰ্দেশ শিকিবলৈ টিপক।"</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"অজ্ঞাত"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"আটাইবোৰ টাইল ৰিছেট কৰিবনে?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"আটাইবোৰ ক্ষিপ্ৰ ছেটিঙৰ টাইল ডিভাইচৰ মূল ছেটিংছলৈ ৰিছেট হ’ব"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-az/strings.xml b/packages/SystemUI/res/values-az/strings.xml
index a0eecd1..b87432f 100644
--- a/packages/SystemUI/res/values-az/strings.xml
+++ b/packages/SystemUI/res/values-az/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> üzərindən qoşuldu."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> cihazına qoşulub."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Qrupu genişləndirin."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Qrupa cihaz əlavə edin."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Cihazı qrupdan silin."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Tətbiqi açın."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Qoşulu deyil."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Rouminq"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Giriş"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Eşitmə aparatları"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiv edilir..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Yuxarıdakı tətbiq tərəfindən idarə olunduğu üçün parlaqlığı tənzimləmək mümkün deyil"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avtodönüş"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranın avtomatik dönməsi"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Məkan"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ətraf mühit"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Sol"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Sağ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Sola və sağa ayrılmış idarəetmələr üçün genişləndirin"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Vahid nəzarət üçün yığcamlaşdırın"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Ətraf mühiti səssiz edin"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Aşağı prioritet bildiriş işarələrini göstərin"</string>
     <string name="other" msgid="429768510980739978">"Digər"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"mozaik ölçüsünü aktiv/deaktiv edin"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"lövhəni silin"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"son mövqeyə mozaik əlavə edin"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Lövhəni köçürün"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyinə əlavə edin"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Mövqe yanlışdır."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> mövqeyi"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Mozaik əlavə edilib"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Mozaik silinib"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Sürətli ayarlar redaktoru."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Son tətbiqlərə baxmaq üçün taçpeddə üç barmağınızla yuxarı çəkib saxlayın"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Bütün tətbiqlərə baxmaq üçün klaviaturada fəaliyyət açarını basın"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Çıxarılıb"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Baxmaq üçün kiliddən çıxarın"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Koda baxmaq üçün kiliddən çıxarın"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstual təhsil"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Geri qayıtmaq üçün taçped istifadə edin"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Üç barmaqla sola və ya sağa çəkin. Daha çox jest öyrənmək üçün toxunun."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Naməlum"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Bütün mozaiklər sıfırlansın?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Bütün Sürətli Ayarlar mozaiki cihazın orijinal ayarlarına sıfırlanacaq"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-b+sr+Latn/strings.xml b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
index 8921eff..a875e73 100644
--- a/packages/SystemUI/res/values-b+sr+Latn/strings.xml
+++ b/packages/SystemUI/res/values-b+sr+Latn/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezani ste sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Povezani smo sa uređajem <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Proširite grupu."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Dodajte uređaj u grupu."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Uklonite uređaj iz grupe."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Otvorite aplikaciju."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nije povezano."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Unos"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušni aparati"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključuje se..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Ne možete da prilagodite osvetljenost jer je kontroliše aplikacija u prvom planu"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatska rotacija"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okruženje"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Levo"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Desno"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Proširi na kontrole razdvojene na levu i desnu stranu"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Skupi u jedinstvenu kontrolu"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Isključi zvuk okruženja"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodajte na <xliff:g id="POSITION">%1$d</xliff:g>. poziciju"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozicija je nevažeća."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. pozicija"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Pločica je dodata"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Pločica je uklonjena"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Uređivač za Brza podešavanja."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nepoznato"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Želite da resetujete sve pločice?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Sve pločice Brzih podešavanja će se resetovati na prvobitna podešavanja uređaja"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-be/strings.xml b/packages/SystemUI/res/values-be/strings.xml
index 3568586..75d0a44 100644
--- a/packages/SystemUI/res/values-be/strings.xml
+++ b/packages/SystemUI/res/values-be/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Падлучаны да <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Ёсць падключэнне да <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Разгарнуць групу."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Дадаць прыладу ў групу."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Выдаліць прыладу з групы."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Адкрыць праграму."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Няма падключэння."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роўмінг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Увод"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слыхавыя апараты"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Уключэнне…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Не ўдаецца адрэгуляваць яркасць, бо яна кантралюецца верхняй праграмай"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Аўтапаварот"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Аўтаматычны паварот экрана"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Месцазнаходжанне"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Навакольныя гукі"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Левы бок"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Правы бок"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Зрабіць левую і правую панэлі кіравання"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Зрабіць адну панэль кіравання"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Выключыць навакольныя гукі"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Паказваць значкі апавяшчэнняў з нізкім прыярытэтам"</string>
     <string name="other" msgid="429768510980739978">"Іншае"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"змяніць памер пліткі"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"выдаліць плітку"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"дадаць плітку ў апошнюю пазіцыю"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Перамясціць плітку"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Дадаць на пазіцыю <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Няправільнае месца."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Пазіцыя <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Плітка дададзена"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Плітка выдалена"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Рэдактар хуткіх налад."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Для прагляду нядаўніх праграм правядзіце па сэнсарнай панэлі трыма пальцамі ўверх і затрымайцеся"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Каб праглядзець усе праграмы, націсніце на клавішу дзеяння на клавіятуры"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Схавана"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Разблакіруйце экран, каб праглядзець"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Разблакіруйце экран, каб праглядзець код"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Кантэкстнае навучанне"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Выкарыстайце сэнсарную панэль для вяртання"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Правядзіце ўлева ці ўправа трыма пальцамі. Націсніце, каб азнаёміцца з іншымі жэстамі."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Невядома"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Скінуць усе пліткі?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Усе пліткі хуткіх налад будуць скінуты да першапачатковых налад прылады"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bg/strings.xml b/packages/SystemUI/res/values-bg/strings.xml
index 9d6be13..4f3d641 100644
--- a/packages/SystemUI/res/values-bg/strings.xml
+++ b/packages/SystemUI/res/values-bg/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Има връзка с <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Установена е връзка с/ъс <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Разгъване на групата."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Добавяне на устройството към групата."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Премахване на устройството от групата."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Отваряне на приложението."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Няма връзка."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Вход"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слухови апарати"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Включва се..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Яркостта не може да се коригира, защото се контролира от приложението на екрана"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Авт. ориентация"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично завъртане на екрана"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Местоположение"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Околни звуци"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Ляво"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Дясно"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Разгъване до отделни контроли за ляво и дясно"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Свиване до обединена контрола"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Спиране на околните звуци"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Добавяне към позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Невалидна позиция."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Панелът е добавен"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Панелът е премахнат"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор за бързи настройки."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Неизвестно"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Да се нулират ли всички панели?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Всички панели с бързи настройки ще бъдат нулирани до първоначалните настройки на устройството"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g> – <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bn/strings.xml b/packages/SystemUI/res/values-bn/strings.xml
index 636d4f2..3fd699db 100644
--- a/packages/SystemUI/res/values-bn/strings.xml
+++ b/packages/SystemUI/res/values-bn/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>এ সংযুক্ত হয়ে আছে।"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> এর সাথে সংযুক্ত৷"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"গ্রুপ বড় করুন।"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"গ্রুপে ডিভাইস যোগ করুন।"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"গ্রুপ থেকে ডিভাইস সরিয়ে দিন।"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"অ্যাপ্লিকেশন খুলুন।"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"সংযুক্ত নয়৷"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"রোমিং"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ইনপুট"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"হিয়ারিং এড"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"চালু করা হচ্ছে…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"উজ্জ্বলতা অ্যাডজাস্ট করা যাচ্ছে না কারণ এটি সেরা অ্যাপের মাধ্যমে কন্ট্রোল করা হচ্ছে"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"নিজে থেকে ঘুরবে"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"অটো-রোটেট স্ক্রিন"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"লোকেশন"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"সারাউন্ডিং"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"বাঁদিক"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ডানদিক"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"বাঁদিক ও ডানদিকের আলাদা করা কন্ট্রোল বড় করুন"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ইউনিফায়েড কন্ট্রোল আড়াল করুন"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"সারাউন্ডিং মিউট করুন"</string>
@@ -582,7 +585,7 @@
     <string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"স্ক্রিন শেয়ার করুন"</string>
     <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> এই বিকল্পটি বন্ধ করে দিয়েছে"</string>
     <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"শেয়ার করার জন্য অ্যাপ বেছে নিন"</string>
-    <string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"আপনার স্ক্রিন কাস্ট করুন?"</string>
+    <string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"আপনার স্ক্রিন কাস্ট করতে চান?"</string>
     <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"একটি অ্যাপ কাস্ট করুন"</string>
     <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"সম্পূর্ণ স্ক্রিন কাস্ট করুন"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"আপনি সম্পূর্ণ স্ক্রিন কাস্ট করলে, আপনার স্ক্রিনে থাকা সব কিছুই দেখা যাবে। তাই পাসওয়ার্ড, পেমেন্টের বিবরণ, মেসেজ, ফটো এবং অডিও ও ভিডিওর মতো বিষয়ে সতর্ক থাকুন।"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"কম-গুরুত্বপূর্ণ বিজ্ঞপ্তির আইকন দেখুন"</string>
     <string name="other" msgid="429768510980739978">"অন্যান্য"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"টাইলের সাইজ টগল করুন"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"টাইল সরান"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"শেষ জায়গাতে টাইল যোগ করুন"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"টাইল সরান"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"অবস্থান <xliff:g id="POSITION">%1$d</xliff:g>-এ যোগ করুন"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"পজিশন সঠিক নয়।"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"অবস্থান <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"টাইল যোগ করা হয়েছে"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"টাইল সরানো হয়েছে"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"দ্রুত সেটিংস সম্পাদক৷"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"সম্প্রতি ব্যবহার করা অ্যাপ দেখতে, টাচপ্যাডে তিনটি আঙুল ব্যবহার করে উপরের দিকে সোয়াইপ করে ধরে রাখুন"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"আপনার সব অ্যাপ দেখতে, কীবোর্ডে অ্যাকশন কী প্রেস করুন"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"রিড্যাক্ট করা হয়েছে"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"দেখার জন্য আনলক করুন"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"কোড দেখার জন্য আনলক করুন"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"প্রাসঙ্গিক শিক্ষা"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ফিরে যেতে টাচপ্যাড ব্যবহার করুন"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"তিনটি আঙুলের ব্যবহার করে ডান বা বাঁদিকে সোয়াইপ করুন। আরও জেসচার সম্পর্কে জানতে ট্যাপ করুন।"</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"অজানা"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"সব টাইল রিসেট করবেন?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"সব কুইক সেটিংস টাইল, ডিভাইসের আসল সেটিংসে রিসেট হয়ে যাবে"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-bs/strings.xml b/packages/SystemUI/res/values-bs/strings.xml
index 331bac2..0b5af17 100644
--- a/packages/SystemUI/res/values-bs/strings.xml
+++ b/packages/SystemUI/res/values-bs/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezan na <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Povezan na <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Proširivanje grupe."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Dodavanje uređaja u grupu."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Uklanjanje uređaja iz grupe."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Otvaranje aplikacije."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nije povezano."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ulaz"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušni aparati"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključivanje…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Nije moguće podesiti osvijetljenost jer njome upravlja gornja aplikacija"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatsko rotiranje"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko rotiranje ekrana"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okruženje"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Lijevo"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Desno"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Proširivanje u zasebne kontrole ulijevo i udesno"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Sužavanje u objedinjenu kontrolu"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Isključivanje zvuka okruženja"</string>
@@ -991,7 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Prikaži ikone obavještenja niskog prioriteta"</string>
     <string name="other" msgid="429768510980739978">"Ostalo"</string>
-    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"promjenu veličine pločice"</string>
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"uključivanje/isključivanje veličine kartice"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"uklanjanje kartice"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"dodavanje kartice na posljednji položaj"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Pomjeranje kartice"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodavanje u položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Nevažeći položaj."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kartica je dodana"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kartica je uklonjena"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Uređivanje brzih postavki"</string>
@@ -1544,8 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Da pregledate nedavne aplikacije, prevucite nagore i zadržite s tri prsta na dodirnoj podlozi"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Da pregledate sve aplikacije, pritisnite tipku radnji na tastaturi"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redigovano"</string>
-    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Otključajte za prikaz"</string>
-    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Otključajte za prikaz koda"</string>
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Otključajte da pogledate"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Otključajte da pogledate kôd"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstualno obrazovanje"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Koristite dodirnu podlogu da se vratite"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Prevucite ulijevo ili udesno s tri prsta. Dodirnite da naučite više pokreta."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nepoznato"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vratiti sve kartice na zadano?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Sve kartice Brze postavke će se vratiti na originalne postavke uređaja"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ca/strings.xml b/packages/SystemUI/res/values-ca/strings.xml
index 01d7692..0225d2b 100644
--- a/packages/SystemUI/res/values-ca/strings.xml
+++ b/packages/SystemUI/res/values-ca/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"S\'ha connectat a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Està connectat amb <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Desplega el grup."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Afegeix el dispositiu al grup."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Suprimeix el dispositiu del grup."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Obre l\'aplicació."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Sense connexió."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Itinerància"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audiòfons"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"S\'està activant…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"No es pot ajustar la brillantor perquè està controlada per l\'aplicació superior"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Gira automàticament"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Gira la pantalla automàticament"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicació"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Entorn"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Esquerra"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Dreta"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Desplega els controls separats d\'esquerra i dreta"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Replega per unificar el control"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Silencia l\'entorn"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Afegeix a la posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"La posició no és vàlida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posició <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"El mosaic s\'ha afegit"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"El mosaic s\'ha suprimit"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configuració ràpida."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconegut"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vols restablir totes les icones?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Totes les icones de configuració ràpida es restabliran a les opcions originals del dispositiu"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-cs/strings.xml b/packages/SystemUI/res/values-cs/strings.xml
index 15e4703c..8a6980e 100644
--- a/packages/SystemUI/res/values-cs/strings.xml
+++ b/packages/SystemUI/res/values-cs/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Připojeno k zařízení <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Jste připojeni k zařízení <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Rozbalit skupinu."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Přidat zařízení do skupiny."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Odstranit zařízení ze skupiny."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Otevřít aplikaci."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nepřipojeno."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vstup"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Naslouchátka"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Zapínání…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Jas nelze upravit, protože ho řídí hlavní aplikace"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. otáčení"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčení obrazovky"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okolí"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vlevo"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Vpravo"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Rozbalit na samostatné ovládání levé a pravé strany"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Sbalit na sjednocené ovládání"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Ztlumit okolí"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Zobrazit ikony oznámení s nízkou prioritou"</string>
     <string name="other" msgid="429768510980739978">"Jiné"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"přepnout velikost dlaždice"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"odstranit dlaždici"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"přidat dlaždici na poslední pozici"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Přesunout dlaždici"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Přidat dlaždici na pozici <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozice není platná."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozice <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Dlaždice byla přidána"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Dlaždice byla odstraněna"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor rychlého nastavení"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Pokud chcete zobrazit poslední aplikace, přejeďte na touchpadu třemi prsty nahoru a podržte je"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Pokud chcete zobrazit všechny aplikace, stiskněte na klávesnici akční klávesu"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Odstraněno"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"K zobrazení je potřeba zařízení odemknout"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Pokud chcete zobrazit kód, odemkněte zařízení"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontextová výuka"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Návrat zpět pomocí touchpadu"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Přejeďte třemi prsty doleva nebo doprava. Další gesta zjistíte klepnutím."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Neznámé"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Resetovat všechny dlaždice?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Všechny dlaždice Rychlého nastavení se resetují do původní konfigurace zařízení"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-da/strings.xml b/packages/SystemUI/res/values-da/strings.xml
index ab87c46..60c5c1c 100644
--- a/packages/SystemUI/res/values-da/strings.xml
+++ b/packages/SystemUI/res/values-da/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Forbundet med <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Forbundet til <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Udvid gruppe."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Føj enhed til gruppe."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Fjern enhed fra gruppe."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Åbn app."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Ikke tilsluttet."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Høreapparater"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiverer…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Lysstyrken kan ikke justeres, fordi den styres af den øverste app"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Roter automatisk"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Roter skærmen automatisk"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokation"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Omgivelser"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Venstre"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Højre"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Udvid til adskilte styringselementer til venstre og højre"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Minimer til samlet styringselement"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Ignorer omgivelser"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Vis ikoner for notifikationer med lav prioritet"</string>
     <string name="other" msgid="429768510980739978">"Andet"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ændre feltets størrelse"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjern felt"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"føj handlingsfeltet til den sidste position"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flyt felt"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Føj til lokation <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Positionen er ugyldig."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Lokation <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Feltet blev tilføjet"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Feltet blev fjernet"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigeringsværktøj til Kvikmenu."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Du kan se nyligt brugte apps ved at stryge opad og holde tre fingre nede på touchpladen"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Du kan se alle dine apps ved at trykke på handlingstasten på dit tastatur"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Skjult"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Lås op for at se"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Lås op for at se koden"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstbaseret uddannelse"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Brug din touchplade til at gå tilbage"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Stryg til venstre eller højre med tre fingre. Tryk for at lære flere bevægelser."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ukendt"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vil du nulstille alle handlingsfelter?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle handlingsfelter i kvikmenuen nulstilles til enhedens oprindelige indstillinger"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-de/strings.xml b/packages/SystemUI/res/values-de/strings.xml
index 99e32ec..66b60b1 100644
--- a/packages/SystemUI/res/values-de/strings.xml
+++ b/packages/SystemUI/res/values-de/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Mit <xliff:g id="BLUETOOTH">%s</xliff:g> verbunden"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Verbunden mit <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Gruppe erweitern."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Gerät zu Gruppe hinzufügen."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Gerät aus Gruppe entfernen."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Anwendung öffnen."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nicht verbunden"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Eingabe"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hörgerät"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Wird aktiviert…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Die Helligkeit kann nicht angepasst werden, weil sie von der obersten App gesteuert wird"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. drehen"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Bildschirm automatisch drehen"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Standort"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Umgebungsgeräusche"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Links"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Rechts"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"In ein linkes und ein rechtes Steuerfeld maximieren"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Zu einem einzigen Steuerfeld minimieren"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Umgebungsgeräusche stummschalten"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Symbole für Benachrichtigungen mit einer niedrigen Priorität anzeigen"</string>
     <string name="other" msgid="429768510980739978">"Sonstiges"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"Größe der Kachel umschalten"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"Entfernen der Kachel"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"Kachel an letzter Position hinzufügen"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Kachel verschieben"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Zur Position <xliff:g id="POSITION">%1$d</xliff:g> hinzufügen"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position ist ungültig."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Ansicht hinzugefügt"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Ansicht entfernt"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor für Schnelleinstellungen."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Um zuletzt verwendete Apps aufzurufen, wische mit 3 Fingern nach oben und halte das Touchpad gedrückt"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Wenn du alle deine Apps aufrufen möchtest, drücke auf der Tastatur die Aktionstaste"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Entfernt"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Zum Ansehen entsperren"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Zum Ansehen des Codes entsperren"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontextbezogene Informationen"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Zum Zurückgehen Touchpad verwenden"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Wische mit drei Fingern nach links oder rechts. Tippe für mehr Infos zu Touch-Gesten."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unbekannt"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Alle Kacheln zurücksetzen?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle Schnelleinstellungen-Kacheln werden auf die Standardeinstellungen des Geräts zurückgesetzt"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-el/strings.xml b/packages/SystemUI/res/values-el/strings.xml
index d3bfc99..639aee2 100644
--- a/packages/SystemUI/res/values-el/strings.xml
+++ b/packages/SystemUI/res/values-el/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Συνδέθηκε στο <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Συνδέθηκε σε <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Αναπτύξτε την ομάδα."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Προσθήκη συσκευής στην ομάδα."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Κατάργηση συσκευής από την ομάδα."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Ανοίξτε την εφαρμογή."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Μη συνδεδεμένο"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Περιαγωγή"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Είσοδος"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Βοηθήματα ακοής"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ενεργοποίηση…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Δεν είναι δυνατή η προσαρμογή της φωτεινότητας, επειδή ελέγχεται από την εφαρμογή στην κορυφή"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Αυτόματη περιστροφή"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Αυτόματη περιστροφή οθόνης"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Τοποθεσία"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ήχοι περιβάλλοντος"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Αριστερά"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Δεξιά"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Ανάπτυξη σε ξεχωριστά στοιχεία ελέγχου αριστερά και δεξιά"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Σύμπτυξη σε ενοποιημένο στοιχείο ελέγχου"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Σίγαση ήχων περιβάλλοντος"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Προσθήκη στη θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Μη έγκυρη θέση."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Θέση <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Το πλακίδιο προστέθηκε"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Το πλακίδιο καταργήθηκε"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Επεξεργασία γρήγορων ρυθμίσεων."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Άγνωστο"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Επαναφορά σε όλα τα πλακάκια;"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Σε όλα τα πλακάκια Γρήγορων ρυθμίσεων θα γίνει επαναφορά στις αρχικές ρυθμίσεις της συσκευής"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rAU/strings.xml b/packages/SystemUI/res/values-en-rAU/strings.xml
index c253711..62441c8 100644
--- a/packages/SystemUI/res/values-en-rAU/strings.xml
+++ b/packages/SystemUI/res/values-en-rAU/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expand group."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Add device to group."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Remove device from group."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Open application."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Not connected."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Can\'t adjust brightness because it\'s being controlled by the top app"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Surroundings"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Left"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Right"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expand to left and right separated controls"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Collapse to unified control"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Mute surroundings"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Show low-priority notification icons"</string>
     <string name="other" msgid="429768510980739978">"Other"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"toggle the tile\'s size"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remove tile"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"add tile to the last position"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Move tile"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Quick settings editor."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"To view recent apps, swipe up and hold with three fingers on the touchpad"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"To view all your apps, press the action key on your keyboard"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redacted"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Unlock to view"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Unlock to view code"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Contextual education"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Use your touchpad to go back"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swipe left or right using three fingers. Tap to learn more gestures."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset all tiles?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"All Quick Settings tiles will reset to the device\'s original settings"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rCA/strings.xml b/packages/SystemUI/res/values-en-rCA/strings.xml
index 92e9d8d..69aca1f 100644
--- a/packages/SystemUI/res/values-en-rCA/strings.xml
+++ b/packages/SystemUI/res/values-en-rCA/strings.xml
@@ -423,6 +423,9 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Surroundings"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Left"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Right"</string>
+    <string name="hearing_devices_ambient_control_description" msgid="3663947879732939509">"Surroundings"</string>
+    <string name="hearing_devices_ambient_control_left_description" msgid="4440988622896213511">"Left surroundings"</string>
+    <string name="hearing_devices_ambient_control_right_description" msgid="2230461103493378003">"Right surroundings"</string>
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expand to left and right separated controls"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Collapse to unified control"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Mute surroundings"</string>
@@ -997,6 +1000,7 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <string name="accessibility_qs_edit_tile_already_added" msgid="5900071201690226752">"Tile already added"</string>
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Quick settings editor."</string>
@@ -1565,4 +1569,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset all tiles?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"All Quick Settings tiles will reset to the device’s original settings"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rGB/strings.xml b/packages/SystemUI/res/values-en-rGB/strings.xml
index c253711..62441c8 100644
--- a/packages/SystemUI/res/values-en-rGB/strings.xml
+++ b/packages/SystemUI/res/values-en-rGB/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expand group."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Add device to group."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Remove device from group."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Open application."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Not connected."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Can\'t adjust brightness because it\'s being controlled by the top app"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Surroundings"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Left"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Right"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expand to left and right separated controls"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Collapse to unified control"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Mute surroundings"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Show low-priority notification icons"</string>
     <string name="other" msgid="429768510980739978">"Other"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"toggle the tile\'s size"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remove tile"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"add tile to the last position"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Move tile"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Quick settings editor."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"To view recent apps, swipe up and hold with three fingers on the touchpad"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"To view all your apps, press the action key on your keyboard"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redacted"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Unlock to view"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Unlock to view code"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Contextual education"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Use your touchpad to go back"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swipe left or right using three fingers. Tap to learn more gestures."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset all tiles?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"All Quick Settings tiles will reset to the device\'s original settings"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-en-rIN/strings.xml b/packages/SystemUI/res/values-en-rIN/strings.xml
index c253711..62441c8 100644
--- a/packages/SystemUI/res/values-en-rIN/strings.xml
+++ b/packages/SystemUI/res/values-en-rIN/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connected to <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Connected to <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expand group."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Add device to group."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Remove device from group."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Open application."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Not connected."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hearing aids"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Turning on…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Can\'t adjust brightness because it\'s being controlled by the top app"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Auto-rotate"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Auto-rotate screen"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Location"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Surroundings"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Left"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Right"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expand to left and right separated controls"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Collapse to unified control"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Mute surroundings"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Show low-priority notification icons"</string>
     <string name="other" msgid="429768510980739978">"Other"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"toggle the tile\'s size"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remove tile"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"add tile to the last position"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Move tile"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Add to position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position invalid."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tile added"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tile removed"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Quick settings editor."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"To view recent apps, swipe up and hold with three fingers on the touchpad"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"To view all your apps, press the action key on your keyboard"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redacted"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Unlock to view"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Unlock to view code"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Contextual education"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Use your touchpad to go back"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swipe left or right using three fingers. Tap to learn more gestures."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Unknown"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset all tiles?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"All Quick Settings tiles will reset to the device\'s original settings"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es-rUS/strings.xml b/packages/SystemUI/res/values-es-rUS/strings.xml
index 7f09671..840afd4 100644
--- a/packages/SystemUI/res/values-es-rUS/strings.xml
+++ b/packages/SystemUI/res/values-es-rUS/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expandir grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Agregar el dispositivo al grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Quitar el dispositivo del grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Abrir aplicación."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"No conectado"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audífonos"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"La app superior controla el brillo, por lo que no se puede ajustar"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar la pantalla automáticamente"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Sonido envolvente"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Izquierda"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Derecha"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expandir los controles separados a la izquierda y a la derecha"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Contraer al control unificado"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Silenciar el sonido envolvente"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Agregar a la posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posición no válida"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Se agregó la tarjeta"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Se quitó la tarjeta"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de Configuración rápida"</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconocido"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"¿Quieres restablecer todas las tarjetas?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Se restablecerán todas las tarjeta de Configuración rápida a la configuración original del dispositivo"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-es/strings.xml b/packages/SystemUI/res/values-es/strings.xml
index 531d1df..177f298 100644
--- a/packages/SystemUI/res/values-es/strings.xml
+++ b/packages/SystemUI/res/values-es/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Mostrar grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Añade un dispositivo al grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Quita un dispositivo del grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Abrir aplicación."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"No conectado."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audífonos"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"No se puede ajustar el brillo porque la aplicación superior lo está controlando"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Girar pantalla automáticamente"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Ubicación"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Alrededores"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Izquierda"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Derecha"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expandir a los controles separados de izquierda y derecha"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Contraer al control unificado"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Silenciar alrededores"</string>
@@ -588,7 +591,7 @@
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"Cuando envías toda tu pantalla, se ve todo lo que hay en ella. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Cuando envías una aplicación, se ve todo lo que se muestre o reproduzca en ella. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string>
     <string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"Enviar pantalla"</string>
-    <string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"Elegir una aplicación para enviar"</string>
+    <string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"Elige una aplicación para enviar"</string>
     <string name="media_projection_entry_generic_permission_dialog_title" msgid="4519802931547483628">"¿Empezar a compartir?"</string>
     <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Cuando compartes, grabas o envías contenido, Android puede acceder a todo lo que se muestre en la pantalla o se reproduzca en tu dispositivo. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string>
     <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Cuando compartes, grabas o envías una aplicación, Android puede acceder a todo lo que se muestre o se reproduzca en ella. Debes tener cuidado con elementos como contraseñas, detalles de pagos, mensajes, fotos, audio y vídeo."</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar iconos de notificaciones con prioridad baja"</string>
     <string name="other" msgid="429768510980739978">"Otros"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"mostrar el tamaño del recuadro"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"quitar recuadro"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"añadir el recuadro a la última posición"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover recuadro"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Añadir a la posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posición no válida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Recuadro añadido"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Recuadro quitado"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de ajustes rápidos."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Para ver las aplicaciones recientes, desliza hacia arriba y mantén pulsado el panel táctil con tres dedos"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Para ver todas tus aplicaciones, pulsa la tecla de acción de tu teclado"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Oculta"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Desbloquea para ver"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Desbloquea para ver el código"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Educación contextual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Usa el panel táctil para volver atrás"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Desliza hacia la izquierda o hacia la derecha con tres dedos. Toca para aprender a usar más gestos."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconocido"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"¿Borrar todos los recuadros?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Todos los recuadros de ajustes rápidos se restablecerán a los ajustes originales del dispositivo"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-et/strings.xml b/packages/SystemUI/res/values-et/strings.xml
index 30b93b0..be021fc 100644
--- a/packages/SystemUI/res/values-et/strings.xml
+++ b/packages/SystemUI/res/values-et/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ühendatud: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Ühendatud ülekandega <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Grupi laiendamine."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Seadme lisamine gruppi."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Seadme eemaldamine grupist."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Rakenduse avamine."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Ühendus puudub."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Rändlus"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Sisend"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Kuuldeaparaadid"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Sisselülitamine …"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Heledust ei saa reguleerida, kuna seda juhib ülemine rakendus"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autom. pööramine"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Kuva automaatne pööramine"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Asukoht"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ümbritsevad helid"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vasakule"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Paremale"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Vasaku ja parema poole eraldi juhtimine"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Mõlema poole ühtne juhtimine"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Ümbritsevate helide vaigistamine"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Kuva madala prioriteediga märguande ikoonid"</string>
     <string name="other" msgid="429768510980739978">"Muu"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"muutke paani suurust"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"paani eemaldamiseks"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"lisage paan viimasesse asukohta"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Teisalda paan"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lisamine asendisse <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Sobimatu asukoht."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Asend <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Paan on lisatud"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Paan on eemaldatud"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Kiirseadete redigeerija."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Hiljutiste rakenduste kuvamiseks pühkige puuteplaadil kolme sõrmega üles ja hoidke sõrmi puuteplaadil."</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Kõigi oma rakenduste kuvamiseks vajutage klaviatuuril toiminguklahvi"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Peidetud"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Vaatamiseks avage"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Koodi vaatamiseks avage"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstipõhised õpetused"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Puuteplaadi kasutamine tagasiliikumiseks"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Pühkige kolme sõrmega vasakule või paremale. Puudutage liigutuste kohta lisateabe saamiseks."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Teadmata"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Kas lähtestada kõik paanid?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Kõik kiirseadete paanid lähtestatakse seadme algseadetele"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-eu/strings.xml b/packages/SystemUI/res/values-eu/strings.xml
index 50f8750..edcc172 100644
--- a/packages/SystemUI/res/values-eu/strings.xml
+++ b/packages/SystemUI/res/values-eu/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> gailura konektatuta."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Hona konektatuta: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Zabaldu taldea."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Gehitu gailua taldera"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Kendu gailua taldetik."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Ireki aplikazioa."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Konektatu gabe."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Ibiltaritza"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Sarrera"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audifonoak"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktibatzen…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Ezin da argitasuna doitu goiko aplikazioak kontrolatzen duelako"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Biratze automatikoa"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Biratu pantaila automatikoki"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Kokapena"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ingurunea"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Ezkerrekoa"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Eskuinekoa"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Zabaldu ezkerreko eta eskuineko kontrolatzeko aukerak bereiz erabiltzeko"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Tolestu kontrolatzeko aukerak bateratuta erabiltzeko"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Desaktibatu ingurunearen audioa"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Erakutsi lehentasun txikiko jakinarazpenen ikonoak"</string>
     <string name="other" msgid="429768510980739978">"Beste bat"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"aldatu lauzaren tamaina"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"kendu lauza"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"gehitu lauza azken posizioan"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mugitu lauza"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Gehitu <xliff:g id="POSITION">%1$d</xliff:g>garren lekuan"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Kokapenak ez du balio."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>garren lekua"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Gehitu da lauza"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kendu da lauza"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ezarpen bizkorren editorea."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Azkenaldiko aplikazioak ikusteko, pasatu 3 hatz ukipen-panelean gora eta eduki sakatuta"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Aplikazio guztiak ikusteko, sakatu teklatuko ekintza-tekla"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Desitxuratuta"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Desblokeatu ikusteko"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Desblokeatu kodea ikusteko"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Testuinguruaren araberako hezkuntza"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Erabili ukipen-panela atzera egiteko"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Pasatu 3 hatz ezkerrera edo eskuinera. Sakatu keinu gehiago ikasteko."</string>
@@ -1571,4 +1573,6 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ezezagunak"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Lauza guztiak berrezarri nahi dituzu?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Gailuaren jatorrizko ezarpenak berrezarriko dira ezarpen bizkorren lauza guztietan"</string>
+    <!-- no translation found for volume_slider_disabled_message_template (1305088816797803460) -->
+    <skip />
 </resources>
diff --git a/packages/SystemUI/res/values-fa/strings.xml b/packages/SystemUI/res/values-fa/strings.xml
index d53805d..f1f6a14 100644
--- a/packages/SystemUI/res/values-fa/strings.xml
+++ b/packages/SystemUI/res/values-fa/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"به <xliff:g id="BLUETOOTH">%s</xliff:g> متصل شد."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"به <xliff:g id="CAST">%s</xliff:g> متصل شد."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"گروه را از هم باز می‌کند."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"افزودن دستگاه به گروه."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"حذف دستگاه از گروه."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"برنامه را باز می‌کند."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"متصل نیست."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"فراگردی"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ورودی"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"سمعک"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"روشن کردن…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"نمی‌توان روشنایی را تنظیم کرد زیرا برنامه بالایی آن را کنترل می‌کند"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"چرخش خودکار"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"چرخش خودکار صفحه‌نمایش"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"مکان"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"پیرامون"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"چپ"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"راست"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ازهم بازکردن برای کنترل‌های جداگانه چپ و راست"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"جمع کردن برای کنترل یکپارچه"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"بی‌صدا کردن پیرامون"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"افزودن به موقعیت <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"موقعیت نامعتبر است."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"موقعیت <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"کاشی اضافه شد"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"کاشی حذف شد"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ویرایشگر تنظیمات سریع."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"نامشخص"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"همه کاشی‌ها بازنشانی شود؟"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"همه کاشی‌های «تنظیمات فوری» به تنظیمات اصلی دستگاه بازنشانی خواهد شد"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>، <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fi/strings.xml b/packages/SystemUI/res/values-fi/strings.xml
index fa9468d..7476599 100644
--- a/packages/SystemUI/res/values-fi/strings.xml
+++ b/packages/SystemUI/res/values-fi/strings.xml
@@ -254,10 +254,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Yhteys: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Yhdistetty kohteeseen <xliff:g id="CAST">%s</xliff:g>"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Laajenna ryhmä."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Lisää laite ryhmään."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Poista laite ryhmästä."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Avaa sovellus."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Ei yhteyttä."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -335,8 +333,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Syöttölaite"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Kuulolaitteet"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Otetaan käyttöön…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Kirkkautta ei voi säätää, koska ensisijainen sovellus ohjaa sitä"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automaattinen kääntö"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Käännä näyttöä automaattisesti."</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Sijainti"</string>
@@ -428,6 +425,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ympäristö"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vasen"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Oikea"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Laajenna vasemmalle ja oikealle erilliset ohjaimet"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Tiivistä yhtenäiseksi säätimeksi"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Mykistä ympäristö"</string>
@@ -993,8 +996,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Näytä vähemmän tärkeät ilmoituskuvakkeet"</string>
     <string name="other" msgid="429768510980739978">"Muu"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ruudun koko päälle/pois"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"poista kiekko"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"lisää laatta viimeiseen kohtaan"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Siirrä kiekkoa"</string>
@@ -1003,6 +1005,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lisää paikkaan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Virheellinen sijainti."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Paikka <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kiekko lisätty"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kiekko poistettu"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Pika-asetusten muokkausnäkymä"</string>
@@ -1547,10 +1551,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Näet äskeiset sovellukset, kun pyyhkäiset ylös ja pidät kosketuslevyä painettuna kolmella sormella."</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Jos haluat nähdä kaikki sovellukset, paina näppäimistön toimintonäppäintä"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Sensuroitu"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Avaa lukitus ja katso tiedot"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Avaa lukitus nähdäksesi koodin"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstuaalinen koulutus"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Takaisin siirtyminen kosketuslevyn avulla"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Pyyhkäise vasemmalle tai oikealle kolmella sormella. Lue lisää eleistä napauttamalla."</string>
@@ -1573,4 +1575,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Tuntematon"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Nollataanko kaikki laatat?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Kaikki pika-asetuslaatat palautetaan laitteen alkuperäisiin asetuksiin"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/strings.xml b/packages/SystemUI/res/values-fr-rCA/strings.xml
index 97702f0..e22f306 100644
--- a/packages/SystemUI/res/values-fr-rCA/strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Connecté à <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Développer le groupe."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Ajouter un appareil au groupe."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Retirer l\'appareil du groupe."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Ouvrir l\'appli."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Non connecté"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Itinérance"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrée"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Prothèses auditives"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activation en cours…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Impossible de régler la luminosité, car elle est contrôlée par l\'appli principale"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation auto"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Environnement"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Gauche"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Droit"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Développer les commandes distinctes à gauche et à droite"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Passer au contrôle unifié"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Ignorer les sons de l\'environnement"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Afficher les icônes de notification de faible priorité"</string>
     <string name="other" msgid="429768510980739978">"Autre"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"activer ou désactiver la taille de la tuile"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"retirer la tuile"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"Ajouter une tuile à la dernière position"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Déplacer la tuile"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ajouter à la position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Position incorrecte."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tuile ajoutée"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tuile retirée"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Éditeur de paramètres rapides."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Pour afficher les applis récentes, balayez l\'écran vers le haut avec trois doigts sur le pavé tactile et maintenez-les en place"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Pour afficher toutes vos applis, appuyez sur la touche d\'action de votre clavier"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Supprimé"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Déverrouillez pour afficher"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Déverrouillez pour afficher le code"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Enseignement contextuel"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Utiliser votre pavé tactile pour revenir en arrière"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Balayez vers la gauche ou vers la droite avec trois doigts. Touchez pour apprendre d\'autres gestes."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Inconnu"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Réinitialiser toutes les tuiles?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Toutes les tuiles des paramètres rapides seront réinitialisées aux paramètres par défaut de l\'appareil."</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
index e9d3c48..487c566 100644
--- a/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-fr-rCA/tiles_states_strings.xml
@@ -68,7 +68,7 @@
   </string-array>
   <string-array name="tile_states_bt">
     <item msgid="5330252067413512277">"Non disponible"</item>
-    <item msgid="5315121904534729843">"Désactivée"</item>
+    <item msgid="5315121904534729843">"Désactivé"</item>
     <item msgid="503679232285959074">"Activé"</item>
   </string-array>
   <string-array name="tile_states_airplane">
diff --git a/packages/SystemUI/res/values-fr/strings.xml b/packages/SystemUI/res/values-fr/strings.xml
index 1fefa2d..cceab1c 100644
--- a/packages/SystemUI/res/values-fr/strings.xml
+++ b/packages/SystemUI/res/values-fr/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connecté à : <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Connecté à <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Développer le groupe."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Ajouter l\'appareil au groupe."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Supprimer l\'appareil du groupe."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Ouvrir l\'application."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Non connecté"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Itinérance"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrée"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Appareils auditifs"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activation…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Impossible d\'ajuster la luminosité, car celle-ci est contrôlée par l\'appli principale"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotation auto"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotation automatique de l\'écran"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localisation"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Sons environnants"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Gauche"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Droite"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Développer les commandes gauche et droite"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Réduire en une commande unifiée"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Couper le mode Sons environnants"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ajouter à la position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Emplacement non valide."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Bloc ajouté"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Bloc supprimé"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Éditeur Réglages rapides"</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Inconnu"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Réinitialiser tous les blocs ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Tous les blocs \"Réglages rapides\" seront réinitialisés aux paramètres d\'origine de l\'appareil"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gl/strings.xml b/packages/SystemUI/res/values-gl/strings.xml
index d9a991e..f54a634 100644
--- a/packages/SystemUI/res/values-gl/strings.xml
+++ b/packages/SystemUI/res/values-gl/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Dispositivo conectado: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Despregar o grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Engadir o dispositivo ao grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Quitar o dispositivo do grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Abrir a aplicación."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Non conectada"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Itinerancia"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Audiófonos"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Activando…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Non se pode axustar o brillo porque o controla a aplicación principal"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Xirar automaticamente"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Xirar pantalla automaticamente"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localización"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ambiente"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Esquerdo"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Dereito"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Despregar para controis separados do lado esquerdo e do dereito"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Contraer para control unificado"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Silenciar o ambiente"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Engadir á posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posición non válida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posición <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Engadiuse a tarxeta"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Quitouse a tarxeta"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configuración rápida."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Categoría descoñecida"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Queres restablecer todos os atallos?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Restablecerase a configuración orixinal do dispositivo para todos os atallos de Configuración rápida"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-gu/strings.xml b/packages/SystemUI/res/values-gu/strings.xml
index 55f6e94..1830b34 100644
--- a/packages/SystemUI/res/values-gu/strings.xml
+++ b/packages/SystemUI/res/values-gu/strings.xml
@@ -426,6 +426,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"આસપાસના અવાજો"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ડાબે"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"જમણે"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ડાબે અને જમણે અલગ કરેલા નિયંત્રણો સુધી વિસ્તૃત કરો"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"એકીકૃત નિયંત્રણ સુધી નાનું કરો"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"આસપાસના અવાજો મ્યૂટ કરો"</string>
@@ -991,8 +997,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"ઓછી પ્રાધાન્યતાનું નોટિફિકેશન આઇકન બતાવો"</string>
     <string name="other" msgid="429768510980739978">"અન્ય"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ટાઇલના કદને ટૉગલ કરો"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ટાઇલ કાઢી નાખો"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"છેલ્લા સ્થાનમાં ટાઇલ ઉમેરો"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ટાઇલ ખસેડો"</string>
@@ -1001,6 +1006,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"જગ્યા પર <xliff:g id="POSITION">%1$d</xliff:g> ઉમેરો"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"સ્થિતિ અમાન્ય છે."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"જગ્યા <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ટાઇલ ઉમેરી"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ટાઇલ કાઢી નાખી"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ઝડપી સેટિંગ એડિટર."</string>
@@ -1545,10 +1552,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"તાજેતરની ઍપ જોવા માટે, ટચપૅડ પર ત્રણ આંગળીઓ વડે ઉપર સ્વાઇપ કરો અને દબાવી રાખો"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"તમારી બધી ઍપ જોવા માટે, તમારા કીબોર્ડ પર ઍક્શન કી દબાવો"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"બદલાવેલું"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"જોવા માટે અનલૉક કરો"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"કોડ જોવા માટે અનલૉક કરો"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"સંદર્ભાત્મક શિક્ષણ"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"પાછા જવા માટે તમારા ટચપૅડનો ઉપયોગ કરો"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ત્રણ આંગળીનો ઉપયોગ કરીને ડાબે અથવા જમણે સ્વાઇપ કરો. સંકેતો વિશે વધુ જાણવા માટે ટૅપ કરો."</string>
@@ -1571,4 +1576,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"અજાણ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"તમામ ટાઇલ રીસેટ કરીએ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"તમામ ઝડપી સેટિંગ ટાઇલને ડિવાઇસના ઑરિજિનલ સેટિંગ પર રીસેટ કરવામાં આવશે"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hi/strings.xml b/packages/SystemUI/res/values-hi/strings.xml
index 8878c14..6449800 100644
--- a/packages/SystemUI/res/values-hi/strings.xml
+++ b/packages/SystemUI/res/values-hi/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> से कनेक्ट किया गया."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> से कनेक्ट है."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ग्रुप को बड़ा करें."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"डिवाइस को ग्रुप में जोड़ें."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"डिवाइस को ग्रुप से हटाएं."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ऐप्लिकेशन खोलें."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"कनेक्ट नहीं है."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"रोमिंग"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"कान की मशीनें"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ब्लूटूथ चालू हो रहा है…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"स्क्रीन की रोशनी को अडजस्ट नहीं किया जा सकता, क्योंकि इसे टॉप ऐप्लिकेशन कंट्रोल कर रहा है"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ऑटो-रोटेट"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रीन का अपने-आप दिशा बदलना (ऑटो-रोटेट)"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"जगह की जानकारी"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"आस-पास का वॉल्यूम"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"बाईं ओर के वॉल्यूम के लिए"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"दाईं ओर के वॉल्यूम के लिए"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"दाईं और बाईं ओर के वॉल्यूम को अलग-अलग मैनेज करने के लिए, वॉल्यूम पैनल को बड़ा करें"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"यूनिफ़ाइड कंट्रोल पर जाने के लिए पैनल को छोटा करें"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"आस-पास के वॉल्यूम को म्यूट करें"</string>
@@ -606,7 +609,7 @@
     <string name="notification_settings_button_description" msgid="2441994740884163889">"सूचना सेटिंग"</string>
     <string name="notification_history_button_description" msgid="1578657591405033383">"सूचनाओं का इतिहास"</string>
     <string name="notification_section_header_incoming" msgid="850925217908095197">"नई सूचनाएं"</string>
-    <string name="notification_section_header_gentle" msgid="6804099527336337197">"साइलेंट मोड में मिली सूचनाएं"</string>
+    <string name="notification_section_header_gentle" msgid="6804099527336337197">"बिना आवाज़ के मिलने वाली सूचनाएं"</string>
     <string name="notification_section_header_alerting" msgid="5581175033680477651">"सूचनाएं"</string>
     <string name="notification_section_header_conversations" msgid="821834744538345661">"बातचीत"</string>
     <string name="accessibility_notification_section_header_gentle_clear_all" msgid="6490207897764933919">"बिना आवाज़ की सभी सूचनाएं हटाएं"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"कम प्राथमिकता वाली सूचना के आइकॉन दिखाएं"</string>
     <string name="other" msgid="429768510980739978">"अन्य"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"टाइल के साइज़ को टॉगल करने के लिए दो बार टैप करें"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"टाइल हटाएं"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"आखिरी जगह पर टाइल जोड़ें"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"टाइल को किसी और पोज़िशन पर ले जाएं"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"टाइल को <xliff:g id="POSITION">%1$d</xliff:g> पोज़िशन पर जोड़ें"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"मौजूदा जगह अमान्य है."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"टाइल की पोज़िशन <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"टाइल जोड़ी गई"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"टाइल हटाई गई"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"त्वरित सेटिंग संपादक."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"हाल ही में इस्तेमाल हुए ऐप देखने के लिए, टचपैड पर तीन उंगलियों से ऊपर की ओर स्वाइप करके दबाकर रखें"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"सभी ऐप्लिकेशन देखने के लिए, कीबोर्ड पर ऐक्शन बटन दबाएं"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"जानकारी छिपाने के लिए सूचना में बदलाव किया गया"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"सार्वजनिक सूचना देखने के लिए डिवाइस अनलॉक करें"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"कोड देखने के लिए अनलॉक करें"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"कॉन्टेक्स्ट के हिसाब से जानकारी"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"वापस जाने के लिए, अपने डिवाइस के टचपैड का इस्तेमाल करें"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"तीन उंगलियों से बाईं या दाईं ओर स्वाइप करें. ज़्यादा जेस्चर के बारे में जानने के लिए टैप करें."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"कोई जानकारी नहीं है"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"क्या सभी टाइल रीसेट करनी हैं?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"क्विक सेटिंग टाइल, डिवाइस की ओरिजनल सेटिंग पर रीसेट हो जाएंगी"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hr/strings.xml b/packages/SystemUI/res/values-hr/strings.xml
index 054f394..7db95fe 100644
--- a/packages/SystemUI/res/values-hr/strings.xml
+++ b/packages/SystemUI/res/values-hr/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Spojen na <xliff:g id="BLUETOOTH">%s</xliff:g> ."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Povezani ste sa sljedećim uređajem: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Proširite grupu."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Dodajte uređaj u grupu."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Uklonite uređaj iz grupe."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Otvorite aplikaciju."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nije povezano."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Unos"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušna pomagala"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Uključivanje…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Svjetlina se ne može prilagoditi jer njome upravlja aplikacija pri vrhu"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatsko zakretanje"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatsko zakretanje zaslona"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okruženje"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Lijevo"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Desno"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Proširi u zasebne kontrole slijeva i zdesna"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Sažmi u objedinjenu kontrolu"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Isključi zvuk okruženja"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodavanje na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Položaj nije važeći."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kartica je dodana"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kartica je uklonjena"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Uređivač brzih postavki."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nepoznato"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Želite li poništiti sve pločice?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Sve pločice Brze postavke vratit će se na izvorne postavke uređaja"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hu/strings.xml b/packages/SystemUI/res/values-hu/strings.xml
index 03f1bc6..906ce54 100644
--- a/packages/SystemUI/res/values-hu/strings.xml
+++ b/packages/SystemUI/res/values-hu/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Csatlakoztatva a következőhöz: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Csatlakozva a következőhöz: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Csoport kibontása."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Eszköz hozzáadása csoporthoz."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Eszköz eltávolítása csoportból."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Alkalmazás megnyitása."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nincs csatlakozva."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Bevitel"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hallókészülék"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Bekapcsolás…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Nem lehet módosítani a fényerőt, mert a felső alkalmazás vezérli"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatikus elforgatás"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatikus képernyőforgatás"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Tartózkodási hely"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Környezet"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Bal"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Jobb"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Kibontás a balra és jobbra elválasztott vezérlőkhöz"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Összecsukás az egységes vezérléshez"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Környezet némítása"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Alacsony prioritású értesítési ikonok mutatása"</string>
     <string name="other" msgid="429768510980739978">"Egyéb"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"a mozaik méretének módosítása"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"mozaik eltávolításához"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"mozaik hozzáadása az utolsó pozícióhoz"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mozaik áthelyezése"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Hozzáadás a következő pozícióhoz: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Érvénytelen pozíció."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. hely"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kártya hozzáadva"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kártya eltávolítva"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Gyorsbeállítások szerkesztője"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"A legutóbbi appokért csúsztasson lefelé három ujjal az érintőpadon, és tartsa lenyomva ujjait."</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Az összes alkalmazás megtekintéséhez nyomja meg a billentyűzet műveletbillentyűjét."</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Törölve"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Oldja fel a megtekintéshez"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Kód a megtekintéshez való feloldáshoz"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontextusfüggő tájékoztató párbeszédpanel"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"A visszalépéshez használja az érintőpadot"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Csúsztatasson gyorsan három ujjal balra vagy jobbra. Koppintson a további kézmozdulatokért."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ismeretlen"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Visszaállítja az összes mozaikot?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Az összes Gyorsbeállítások mozaik visszaáll az eszköz eredeti beállításaira"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-hy/strings.xml b/packages/SystemUI/res/values-hy/strings.xml
index e1b6639..57a822e 100644
--- a/packages/SystemUI/res/values-hy/strings.xml
+++ b/packages/SystemUI/res/values-hy/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Միացված է <xliff:g id="BLUETOOTH">%s</xliff:g>-ին:"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Միացված է <xliff:g id="CAST">%s</xliff:g>-ին:"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Ծավալել խումբը։"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Սարքը ավելացնել խմբին։"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Հեռացնել սարքը խմբից։"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Բացել հավելվածը։"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Միացված չէ:"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Ռոումինգ"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Մուտքագրում"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Լսողական սարք"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Միացում…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Հնարավոր չէ կարգավորել պայծառությունը, քանի որ այն կառավարվում է գլխավոր հավելվածի կողմից"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ինքնապտտում"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ավտոմատ պտտել էկրանը"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Տեղորոշում"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Շրջակայք"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Ձախ"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Աջ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Ծավալել՝ դարձնելով կառավարման աջ և ձախ առանձնացված տարրեր"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Ծալել՝ դարձնելով կառավարման մեկ միասնական տարր"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Անջատել շրջակայքի ձայները"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ավելացնել դիրք <xliff:g id="POSITION">%1$d</xliff:g>-ում"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Դիրքն անվավեր է։"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Դիրք <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Սալիկն ավելացվեց"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Սալիկը հեռացվեց"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Արագ կարգավորումների խմբագրիչ:"</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Անհայտ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Զրոյացնե՞լ բոլոր սալիկները"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Արագ կարգավորումների բոլոր սալիկները կզրոյացվեն սարքի սկզբնական կարգավորումների համաձայն։"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-in/strings.xml b/packages/SystemUI/res/values-in/strings.xml
index 6ef3cdc..2d38c8f 100644
--- a/packages/SystemUI/res/values-in/strings.xml
+++ b/packages/SystemUI/res/values-in/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Terhubung ke <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Terhubung ke <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Luaskan grup."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Tambahkan perangkat ke grup."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Hapus perangkat dari grup."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Buka aplikasi."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Tidak terhubung."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Alat bantu dengar"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Mengaktifkan…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Tidak dapat menyesuaikan kecerahan karena sedang dikontrol oleh aplikasi atas"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Putar Otomatis"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Putar layar otomatis"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Suara sekitar"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kiri"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Kanan"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Luaskan ke kontrol terpisah kiri dan kanan"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Ciutkan ke kontrol terpadu"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Bisukan suara sekitar"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Tampilkan ikon notifikasi prioritas rendah"</string>
     <string name="other" msgid="429768510980739978">"Lainnya"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"mengubah ukuran kartu"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"menghapus kartu"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"menambahkan kartu ke posisi terakhir"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Pindahkan kartu"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Tambahkan ke posisi <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posisi tidak valid."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisi <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kartu ditambahkan"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kartu dihapus"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor setelan cepat."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Untuk melihat aplikasi terkini, geser ke atas dan tahan menggunakan tiga jari di touchpad"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Untuk melihat semua aplikasi, tekan tombol tindakan di keyboard"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Disamarkan"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Buka kunci untuk melihat"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Buka kunci untuk melihat kode"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Pendidikan kontekstual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Gunakan touchpad untuk kembali"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Geser ke kiri atau kanan menggunakan tiga jari. Ketuk untuk mempelajari gestur lainnya."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Tidak diketahui"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reset semua kartu?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Semua kartu Setelan Cepat akan direset ke setelan asli perangkat"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-is/strings.xml b/packages/SystemUI/res/values-is/strings.xml
index 2b8a5cc..5c37bdb 100644
--- a/packages/SystemUI/res/values-is/strings.xml
+++ b/packages/SystemUI/res/values-is/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Tengt við <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Tengt við <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Stækka hóp."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Bæta tæki við hóp."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Fjarlægja tæki úr hóp."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Opna forrit."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Engin tenging."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Reiki"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Inntak"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Heyrnartæki"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Kveikir…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Ekki er hægt að breyta birtustiginu vegna þess að efsta forritið stjórnar því"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Sjálfvirkur snúningur"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Snúa skjá sjálfkrafa"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Staðsetning"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Umhverfi"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vinstri"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Hægri"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Aðskilja stýringar til vinstri og hægri"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Taka saman í eina stýringu"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Þagga umhverfi"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Bæta við í stöðu <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Staða ógild."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Staða <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Reit bætt við"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Reitur fjarlægður"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Flýtistillingaritill."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Óþekkt"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Endurstilla alla reiti?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Allir flýtistillingareitir munu endurstillast á upprunalegar stillingar tækisins"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-it/strings.xml b/packages/SystemUI/res/values-it/strings.xml
index 87507d6..a21b6db 100644
--- a/packages/SystemUI/res/values-it/strings.xml
+++ b/packages/SystemUI/res/values-it/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Connesso a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Connesso a: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Espandi il gruppo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Aggiungi il dispositivo al gruppo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Rimuovi il dispositivo dal gruppo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Apri l\'applicazione."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Non connesso."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ingresso"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Apparecchi acustici"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Attivazione…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Impossibile regolare la luminosità perché è controllata dall\'app in primo piano."</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotazione automatica"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotazione automatica dello schermo"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Posizione"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Audio ambientale"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Sinistra"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Destra"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Espandi controlli separati a sinistra e a destra"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Comprimi in controllo unificato"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Disattiva audio ambientale"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Aggiungi alla posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posizione non valida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posizione <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Riquadro aggiunto"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Riquadro rimosso"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor di impostazioni rapide."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Sconosciuti"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Reimpostare tutti i riquadri?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Tutti i riquadri Impostazioni rapide verranno reimpostati sulle impostazioni originali del dispositivo"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-iw/strings.xml b/packages/SystemUI/res/values-iw/strings.xml
index 8a687af..936b10e 100644
--- a/packages/SystemUI/res/values-iw/strings.xml
+++ b/packages/SystemUI/res/values-iw/strings.xml
@@ -245,12 +245,9 @@
     <string name="accessibility_bluetooth_connected" msgid="4745196874551115205">"‏Bluetooth מחובר."</string>
     <string name="accessibility_bluetooth_device_icon" msgid="9163840051642587982">"‏סמל של מכשיר Bluetooth"</string>
     <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"יש ללחוץ כדי להגדיר את פרטי המכשיר"</string>
-    <!-- no translation found for accessibility_bluetooth_device_settings_gear_with_name (114373701123165491) -->
-    <skip />
-    <!-- no translation found for accessibility_bluetooth_device_settings_see_all (5260390270128256620) -->
-    <skip />
-    <!-- no translation found for accessibility_bluetooth_device_settings_pair_new_device (7988547106800504256) -->
-    <skip />
+    <string name="accessibility_bluetooth_device_settings_gear_with_name" msgid="114373701123165491">"‫<xliff:g id="DEVICE_NAME">%s</xliff:g>. הגדרה של פרטי המכשיר"</string>
+    <string name="accessibility_bluetooth_device_settings_see_all" msgid="5260390270128256620">"הצגת כל המכשירים"</string>
+    <string name="accessibility_bluetooth_device_settings_pair_new_device" msgid="7988547106800504256">"התאמה של מכשיר חדש"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"אחוז טעינת הסוללה לא ידוע."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"התבצע חיבור אל <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"מחובר אל <xliff:g id="CAST">%s</xliff:g>."</string>
@@ -354,7 +351,7 @@
     <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"אין רשתות זמינות"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"‏אין רשתות Wi-Fi זמינות"</string>
     <string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"בתהליך הפעלה…"</string>
-    <string name="quick_settings_cast_title" msgid="3033553249449938182">"‏העברה (cast)"</string>
+    <string name="quick_settings_cast_title" msgid="3033553249449938182">"‏הפעלת Cast"</string>
     <string name="quick_settings_casting" msgid="1435880708719268055">"‏מופעל Cast"</string>
     <string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"מכשיר ללא שם"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"אין מכשירים זמינים"</string>
@@ -429,6 +426,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"הרעשים בסביבה"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"שמאל"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ימין"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"הרחבה לאמצעי בקרה נפרדים לצד שמאל ולצד ימין"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"כיווץ לאמצעי בקרה מאוחד"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"השתקת הרעשים בסביבה"</string>
@@ -589,7 +592,7 @@
     <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"‏הפעלת Cast של אפליקציה אחת"</string>
     <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"‏הפעלת Cast של כל המסך"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"‏כשמפעילים Cast של כל המסך, כל מה שמופיע בו יהיה גלוי לצופים. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
-    <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"‏כשמפעילים Cast של כל אפליקציה, כל מה שמופיע או מופעל בה יהיה גלוי לצופים. מומלץ להיזהר עם סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
+    <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"‏כשמפעילים Cast של אפליקציה, כל מה שרואים או מפעילים בה מופיע גם לצופים. מומלץ להיזהר ולא לחשוף פרטים אישיים כמו סיסמאות, פרטי תשלום, הודעות, תמונות, אודיו וסרטונים."</string>
     <string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"‏הפעלת Cast של המסך"</string>
     <string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"‏בחירת אפליקציה להפעלת Cast"</string>
     <string name="media_projection_entry_generic_permission_dialog_title" msgid="4519802931547483628">"להתחיל את השיתוף?"</string>
@@ -906,10 +909,8 @@
     <string name="keyboard_shortcut_group_system_multitasking" msgid="6967816258924795558">"ריבוי משימות"</string>
     <string name="system_multitasking_rhs" msgid="8779289852395243004">"שימוש במסך מפוצל כשהאפליקציה בצד ימין"</string>
     <string name="system_multitasking_lhs" msgid="7348595296208696452">"שימוש במסך מפוצל כשהאפליקציה בצד שמאל"</string>
-    <!-- no translation found for system_multitasking_full_screen (4221409316059910349) -->
-    <skip />
-    <!-- no translation found for system_multitasking_desktop_view (8829838918507805921) -->
-    <skip />
+    <string name="system_multitasking_full_screen" msgid="4221409316059910349">"שימוש במסך מלא"</string>
+    <string name="system_multitasking_desktop_view" msgid="8829838918507805921">"שימוש בתצוגה למחשב"</string>
     <string name="system_multitasking_splitscreen_focus_rhs" msgid="3838578650313318508">"מעבר לאפליקציה משמאל או למטה בזמן שימוש במסך מפוצל"</string>
     <string name="system_multitasking_splitscreen_focus_lhs" msgid="3164261844398662518">"מעבר לאפליקציה מימין או למעלה בזמן שימוש במסך מפוצל"</string>
     <string name="system_multitasking_replace" msgid="7410071959803642125">"כשהמסך מפוצל: החלפה בין אפליקציה אחת לאחרת"</string>
@@ -996,8 +997,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"הצגת סמלי התראות בעדיפות נמוכה"</string>
     <string name="other" msgid="429768510980739978">"אחר"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"שינוי גודל הלחצן"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"הסרת הלחצן"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"הוספת הלחצן במיקום האחרון"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"העברת הלחצן"</string>
@@ -1006,6 +1006,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"הוספה למיקום <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"המיקום לא תקין."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"מיקום <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"הלחצן נוסף"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"הלחצן הוסר"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"עורך הגדרות מהירות."</string>
@@ -1512,8 +1514,7 @@
     <string name="touchpad_tutorial_recent_apps_gesture_button" msgid="8919227647650347359">"הצגת האפליקציות האחרונות"</string>
     <string name="touchpad_tutorial_switch_apps_gesture_button" msgid="7768255095423767779">"מעבר בין אפליקציות"</string>
     <string name="touchpad_tutorial_done_button" msgid="176168488821755503">"סיום"</string>
-    <!-- no translation found for touchpad_tutorial_next_button (9169718126626806688) -->
-    <skip />
+    <string name="touchpad_tutorial_next_button" msgid="9169718126626806688">"הבא"</string>
     <string name="gesture_error_title" msgid="469064941635578511">"צריך לנסות שוב."</string>
     <string name="touchpad_back_gesture_action_title" msgid="7199067250654332735">"חזרה"</string>
     <string name="touchpad_back_gesture_guidance" msgid="5352221087725906542">"מחליקים שמאלה או ימינה עם שלוש אצבעות על לוח המגע"</string>
@@ -1551,10 +1552,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"כדי לראות את האפליקציות האחרונות, מחליקים למעלה לוחצים לחיצה ארוכה עם שלוש אצבעות על לוח המגע"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"כדי לראות את כל האפליקציות, מקישים על מקש הפעולה במקלדת"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"מצונזר"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"צריך לפתוח את הנעילה כדי לראות"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"כדי לראות את הקוד, צריך לפתוח את הנעילה"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"חינוך בהתאם להקשר"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"אפשר להשתמש בלוח המגע כדי לחזור אחורה"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"מחליקים ימינה או שמאלה עם שלוש אצבעות. ניתן ללחוץ כדי לקבל מידע נוסף על התנועות."</string>
@@ -1577,4 +1576,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"לא ידוע"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"לאפס את כל הלחצנים?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"כל הלחצנים ב\'הגדרות מהירות\' יאופסו להגדרות המקוריות של המכשיר"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"‫<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ja/strings.xml b/packages/SystemUI/res/values-ja/strings.xml
index 29f93cc..d5ecfe5 100644
--- a/packages/SystemUI/res/values-ja/strings.xml
+++ b/packages/SystemUI/res/values-ja/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>に接続しました。"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>に接続されています。"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"グループを開きます。"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"グループにデバイスを追加します。"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"グループからデバイスを削除します。"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"アプリを開きます。"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"接続されていません。"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ローミング"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"入力"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"補聴器"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ON にしています…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"明るさはトップ アプリによって制御されているため、調整できません"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動回転"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"画面を自動回転します"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"位置情報"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"周囲の音"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"左"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"右"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"開く - 左右それぞれで制御する"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"閉じる - まとめて制御する"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"周囲の音をミュート"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ポジション <xliff:g id="POSITION">%1$d</xliff:g> に追加"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"位置が無効です。"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"タイルを追加しました"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"タイルを削除しました"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"クイック設定エディタ"</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"不明"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"すべてのタイルをリセットしますか?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"すべてのクイック設定タイルがデバイスの元の設定にリセットされます"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>、<xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ka/strings.xml b/packages/SystemUI/res/values-ka/strings.xml
index d9a5824..2e3dc98 100644
--- a/packages/SystemUI/res/values-ka/strings.xml
+++ b/packages/SystemUI/res/values-ka/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"დაკავშირებულია <xliff:g id="BLUETOOTH">%s</xliff:g>-თან."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"დაკავშირებულია მოწყობილობასთან: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ჯგუფის გაფართოება."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"მოწყობილობის ჯგუფში დამატება."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"მოწყობილობის ჯგუფიდან ამოშლა."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"აპლიკაციის გახსნა."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"არ არის დაკავშირებული."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"როუმინგი"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"შეყვანა"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"სმენის მოწყობილობები"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ირთვება…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"სიკაშკაშის კორექტირება ვერ ხერხდება, რადგან ის იმართება გახსნილი აპის მიერ"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ავტოროტაცია"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ეკრანის ავტომატური შეტრიალება"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"მდებარეობა"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"გარემოცვა"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"მარცხენა"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"მარჯვენა"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"განცალკევებული მართვის საშუალებების გაფართოება მარცხნივ და მარჯვნივ"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ერთიანი მართვის ჩაკეცვა"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"გარემოცვის დადუმება"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"დამატება პოზიციაზე <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"პოზიცია არასწორია."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"პოზიცია <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"მოზაიკის ფილა დაემატა"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"მოზაიკის ფილა ამოიშალა"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"სწრაფი პარამეტრების რედაქტორი."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"უცნობი"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"გსურთ ყველა ფილის გადაყენება?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"სწრაფი პარამეტრების ყველა ფილა გადაყენდება მოწყობილობის ორიგინალ პარამეტრებზე"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kk/strings.xml b/packages/SystemUI/res/values-kk/strings.xml
index 141e99c..1c4d31a 100644
--- a/packages/SystemUI/res/values-kk/strings.xml
+++ b/packages/SystemUI/res/values-kk/strings.xml
@@ -147,7 +147,7 @@
     <string name="share_to_app_stop_dialog_message_generic" msgid="7622174291691249392">"Қазір қолданбамен бөлісіп жатырсыз."</string>
     <string name="share_to_app_stop_dialog_button" msgid="6334056916284230217">"Бөлісуді тоқтату"</string>
     <string name="cast_screen_to_other_device_chip_accessibility_label" msgid="4687917476203009885">"Экранды трансляциялап жатырсыз."</string>
-    <string name="cast_to_other_device_stop_dialog_title" msgid="7836517190930357326">"Трансляциялау тоқтасын ба?"</string>
+    <string name="cast_to_other_device_stop_dialog_title" msgid="7836517190930357326">"Трансляцияны тоқтату керек пе?"</string>
     <string name="cast_to_other_device_stop_dialog_message_entire_screen_with_device" msgid="1474703115926205251">"Қазір бүкіл экранды құрылғыға (<xliff:g id="DEVICE_NAME">%1$s</xliff:g>) трансляциялап жатырсыз."</string>
     <string name="cast_to_other_device_stop_dialog_message_entire_screen" msgid="8419219169553867625">"Қазір бүкіл экранды маңайдағы құрылғыға трансляциялап жатырсыз."</string>
     <string name="cast_to_other_device_stop_dialog_message_specific_app_with_device" msgid="2715934698604085519">"Қазір қолданбаны (<xliff:g id="APP_BEING_SHARED_NAME">%1$s</xliff:g>) құрылғыға (<xliff:g id="DEVICE_NAME">%2$s</xliff:g>) трансляциялап жатырсыз."</string>
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> қосылған."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> трансляциясына қосылды."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Топты жайыңыз."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Құрылғыны топқа қосады."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Құрылғыны топтан өшіреді."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Қолданбаны ашыңыз."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Жалғанбаған."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Кіріс"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Есту аппараттары"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Қосылып жатыр…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Жарықтықты реттеу мүмкін емес, себебі ол жетекші қолданба арқылы басқарылады."</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматты түрде бұру"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматты айналатын экран"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Локация"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Айнала"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Сол жақ"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Оң жақ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Сол жақ және оң жақ бөлек бақылау құралдарына жаю"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Біріктірілген бақылау құралына жию"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Айналаның дыбысын өшіру"</string>
@@ -586,7 +589,7 @@
     <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Бір қолданба экранын трансляциялау"</string>
     <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Бүкіл экранды трансляциялау"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"Бүкіл экранды трансляциялаған кезде экранда барлық нәрсе көрсетіледі. Сондықтан құпия сөздерге, төлем туралы мәліметке, хабарларға, фотосуреттерге, аудиоконтент пен бейнелерге сақ болыңыз."</string>
-    <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Қолданба экранын трансляциялаған кезде қолданбадағы барлық контент көрсетіледі. Сондықтан құпия сөздерге, төлем туралы мәліметке, хабарларға, фотосуреттерге, аудиоконтент пен бейнелерге сақ болыңыз."</string>
+    <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Қолданба экранын трансляциялаған кезде, қолданбадағы барлық контент көрсетіледі. Сондықтан құпия сөздерге, төлем туралы мәліметке, хабарларға, фотосуреттерге, аудиоконтент пен бейнелерге сақ болыңыз."</string>
     <string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"Экранды трансляциялау"</string>
     <string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"Трансляциялайтын қолданба экранын таңдау"</string>
     <string name="media_projection_entry_generic_permission_dialog_title" msgid="4519802931547483628">"Бөлісу басталсын ба?"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Маңызды емес хабарландыру белгішелерін көрсету"</string>
     <string name="other" msgid="429768510980739978">"Басқа"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"бөлшек өлшемін ауыстыру"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"бөлшекті өшіру"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"соңғы позицияға бөлшек қосу"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Бөлшекті жылжыту"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> орнына қосу"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Орын жарамсыз."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> орны"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Бөлшек қосылды."</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Бөлшек өшірілді."</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Жылдам параметрлер өңдегіші."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Сенсорлық тақтада үш саусақпен жоғары сырғытып, басып тұрсаңыз, соңғы ашылған қолданбаларды көресіз."</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Пернетақтада әрекет пернесін басып, барлық қолданбаны көре аласыз."</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Жасырылған"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Көру үшін құлыпты ашыңыз."</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Кодты көру үшін құлыпты ашыңыз."</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Контекстік білім"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Артқа қайту үшін сенсорлық тақтаны қолданыңыз"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Үш саусақпен солға не оңға сырғытыңыз. Басқа қимылдарды үйрену үшін түртіңіз."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Белгісіз"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Барлық бөлшекті бастапқы күйге қайтару керек пе?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Барлық \"Жылдам параметрлер\" бөлшегі құрылғының бастапқы параметрлеріне қайтарылады."</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-km/strings.xml b/packages/SystemUI/res/values-km/strings.xml
index 9323308..8b3bfcc 100644
--- a/packages/SystemUI/res/values-km/strings.xml
+++ b/packages/SystemUI/res/values-km/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"បាន​ភ្ជាប់​ទៅ <xliff:g id="BLUETOOTH">%s</xliff:g> ។"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"បានភ្ជាប់ទៅ <xliff:g id="CAST">%s</xliff:g>"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ពង្រីកក្រុម។"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"បញ្ចូលឧបករណ៍ទៅក្រុម។"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"ដកឧបករណ៍ចេញពីក្រុម។"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"បើកកម្មវិធី។"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"មិន​បាន​តភ្ជាប់​។"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"រ៉ូ​មីង"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"បញ្ចូល"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ឧបករណ៍ជំនួយការស្ដាប់"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"កំពុង​បើក..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"មិនអាចកែតម្រូវកម្រិតពន្លឺបានទេ ដោយសារវាកំពុងស្ថិតក្រោមការគ្រប់គ្រងរបស់កម្មវិធីខាងលើគេ"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"បង្វិល​ស្វ័យ​ប្រវត្តិ"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"បង្វិលអេក្រង់ស្វ័យប្រវត្តិ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ទី​តាំង​"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"មជ្ឈដ្ឋានជុំវិញ"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ឆ្វេង"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ស្ដាំ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ពង្រីកទៅជាការគ្រប់គ្រងខាងឆ្វេង និងខាងស្ដាំដាច់ដោយឡែកពីគ្នា"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"បង្រួមទៅជាការគ្រប់គ្រងដែលបានរួមបញ្ចូលគ្នា"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"បិទសំឡេងមជ្ឈដ្ឋានជុំវិញ"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"បញ្ចូលទៅ​ទីតាំងទី <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ទីតាំងគ្មានសុពលភាព។"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ទីតាំងទី <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"បានបញ្ចូលប្រអប់"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"បាន​ផ្លាស់ទី​ប្រអប់"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"កម្មវិធីកែការកំណត់រហ័ស"</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"មិនស្គាល់"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"កំណត់ប្រអប់ទាំងអស់​ឡើងវិញឬ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ប្រអប់​ការកំណត់រហ័សទាំងអស់នឹងកំណត់ឡើងវិញទៅការ​កំណត់ដើមរបស់ឧបករណ៍"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-kn/strings.xml b/packages/SystemUI/res/values-kn/strings.xml
index d7f8b89..50f8c60 100644
--- a/packages/SystemUI/res/values-kn/strings.xml
+++ b/packages/SystemUI/res/values-kn/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ಗೆ ಸಂಪರ್ಕಪಡಿಸಲಾಗಿದೆ."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> ಗೆ ಸಂಪರ್ಕಿಸಲಾಗಿದೆ."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ಗುಂಪು ವಿಸ್ತರಿಸಿ."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"ಸಾಧನವನ್ನು ಗುಂಪಿಗೆ ಸೇರಿಸಿ."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"ಸಾಧನವನ್ನು ಗುಂಪಿನಿಂದ ತೆಗೆದುಹಾಕಿ."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ಅಪ್ಲಿಕೇಶನ್ ತೆರೆಯಿರಿ."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"ಸಂಪರ್ಕಗೊಂಡಿಲ್ಲ."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ರೋಮಿಂಗ್"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ಇನ್‌ಪುಟ್"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ಶ್ರವಣ ಸಾಧನಗಳು"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ಆನ್ ಮಾಡಲಾಗುತ್ತಿದೆ..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ಬ್ರೈಟ್‌ನೆಸ್ ಅನ್ನು ಹೊಂದಾಣಿಕೆ ಮಾಡಲು ಸಾಧ್ಯವಿಲ್ಲ, ಏಕೆಂದರೆ ಅದನ್ನು ಟಾಪ್ ಆ್ಯಪ್ ನಿಯಂತ್ರಿಸುತ್ತಿದೆ"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ಸ್ವಯಂ-ತಿರುಗುವಿಕೆ"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ಪರದೆಯನ್ನು ಸ್ವಯಂ-ತಿರುಗಿಸಿ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ಸ್ಥಳ"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"ಆ್ಯಂಬಿಯೆಂಟ್ ವಾಲ್ಯೂಮ್"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ಎಡ"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ಬಲ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ಪ್ರತ್ಯೇಕ ಎಡ ಮತ್ತು ಬಲ ಕಂಟ್ರೋಲ್‌ಗಳಿಗಾಗಿ ವಿಸ್ತರಿಸಿ"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ಯೂನಿಫೈಡ್ ಕಂಟ್ರೋಲ್‌ಗಾಗಿ ಕುಗ್ಗಿಸಿ"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"ಆ್ಯಂಬಿಯೆಂಟ್ ವಾಲ್ಯೂಮ್ ಅನ್ನು ಮ್ಯೂಟ್ ಮಾಡಿ"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ಸ್ಥಾನಕ್ಕೆ ಸೇರಿಸಿ"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ಸ್ಥಾನವು ಅಮಾನ್ಯವಾಗಿದೆ."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ಸ್ಥಾನ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ಟೈಲ್ ಸೇರಿಸಲಾಗಿದೆ"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ಟೈಲ್ ತೆಗೆದುಹಾಕಲಾಗಿದೆ"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‍ಗಳ ಎಡಿಟರ್."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ಅಪರಿಚಿತ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ಎಲ್ಲಾ ಟೈಲ್‌ಗಳನ್ನು ರೀಸೆಟ್ ಮಾಡಬೇಕೆ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ಎಲ್ಲಾ ತ್ವರಿತ ಸೆಟ್ಟಿಂಗ್‌ಗಳ ಟೈಲ್‌ಗಳನ್ನು ಸಾಧನದ ಮೂಲ ಸೆಟ್ಟಿಂಗ್‌ಗಳಿಗೆ ರೀಸೆಟ್ ಮಾಡಲಾಗುತ್ತದೆ"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ko/strings.xml b/packages/SystemUI/res/values-ko/strings.xml
index 0c43ea1..7342f32 100644
--- a/packages/SystemUI/res/values-ko/strings.xml
+++ b/packages/SystemUI/res/values-ko/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>에 연결되었습니다."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>에 연결됨"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"그룹을 펼칩니다."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"기기를 그룹에 추가합니다."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"그룹에서 기기를 삭제합니다."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"애플리케이션을 엽니다."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"연결되지 않았습니다."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"로밍"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"입력"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"보청기"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"켜는 중..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"상위 앱에서 밝기를 제어하고 있으므로 밝기를 조절할 수 없습니다."</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"자동 회전"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"화면 자동 회전"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"위치"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"주변 소리"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"왼쪽"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"오른쪽"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"왼쪽 및 오른쪽 개별 제어로 확장"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"통합 제어로 축소"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"주변 소리 음소거"</string>
@@ -586,7 +589,7 @@
     <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"앱 1개 전송"</string>
     <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"전체 화면 전송"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"전체 화면을 전송하면 화면에 있는 모든 항목을 볼 수 있게 됩니다. 따라서 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string>
-    <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"앱을 전송하면 해당 앱에 표시되거나 재생되는 모든 항목을 볼 수 있게 됩니다. 따라서 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string>
+    <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"앱을 전송하면 해당 앱에 표시되거나 재생되는 모든 항목을 볼 수 있게 됩니다. 비밀번호, 결제 세부정보, 메시지, 사진, 오디오 및 동영상 등이 노출되지 않도록 주의하세요."</string>
     <string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"화면 전송"</string>
     <string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"전송할 앱 선택"</string>
     <string name="media_projection_entry_generic_permission_dialog_title" msgid="4519802931547483628">"공유를 시작하시겠습니까?"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"우선순위가 낮은 알림 아이콘 표시"</string>
     <string name="other" msgid="429768510980739978">"기타"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"타일 크기 전환"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"타일 삭제"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"마지막 위치에 타일 추가"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"타일 이동"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> 위치에 추가"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"위치가 잘못되었습니다."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> 위치"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"타일 추가됨"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"타일 삭제됨"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"빠른 설정 편집기"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"최근 앱을 보려면 터치패드에서 세 손가락으로 위로 스와이프한 후 잠시 기다리세요"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"모든 앱을 보려면 키보드의 작업 키를 누르세요"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"수정됨"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"잠금 해제하여 보기"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"잠금 해제하여 코드 보기"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"컨텍스트 교육"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"터치패드를 사용하여 돌아가기"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"세 손가락을 사용해 왼쪽 또는 오른쪽으로 스와이프하세요. 더 많은 동작을 알아보려면 탭하세요."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"알 수 없음"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"모든 타일을 재설정하시겠습니까?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"모든 빠른 설정 타일이 기기의 원래 설정으로 재설정됩니다."</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ky/strings.xml b/packages/SystemUI/res/values-ky/strings.xml
index b411bdc..f21ee1a 100644
--- a/packages/SystemUI/res/values-ky/strings.xml
+++ b/packages/SystemUI/res/values-ky/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> менен туташкан."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> менен туташты."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Топту жайып көрсөтүү."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Түзмөктү топко кошуңуз."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Түзмөктү топтон алып салыңыз."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Колдонмону ачуу."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Интернет жок."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Киргизүү"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Угуу аппараттары"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Күйгүзүлүүдө…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Жарыктыкты тууралоого болбойт, анткени аны жогорку колдонмо көзөмөлдөйт"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Авто буруу"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Экранды авто буруу"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Жайгашкан жер"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Айланадагы үндөр"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Сол"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Оң"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Cол жана оң жактагы өзүнчө башкаруу элементтерине жайып көрсөтүү"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Бирдиктүү башкаруу элементине жыйыштыруу"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Айланадагы үндөрдү басуу"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Анча маанилүү эмес билдирменин сүрөтчөлөрүн көрсөтүү"</string>
     <string name="other" msgid="429768510980739978">"Башка"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"плитканын өлчөмүн которуштуруу"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ыкчам баскычты өчүрүү"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"аягына карта кошуу"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Ыкчам баскычты жылдыруу"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g>-позицияга кошуу"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Абал жараксыз."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>-позиция"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Карта кошулду"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Карта өчүрүлдү"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ыкчам параметрлер түзөткүчү."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Акыркы колдонмолорду көрүү үчүн сенсордук тактаны үч манжаңыз менен өйдө сүрүп, кармап туруңуз"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Бардык колдонмолоруңузду көрүү үчүн баскычтобуңуздагы аракет баскычын басыңыз"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Жашырылды"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Көрүү үчүн кулпусун ачыңыз"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Кодду көрүү үчүн кулпусун ачыңыз"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Контексттик билим берүү"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Артка кайтуу үчүн сенсордук тактаны колдонуңуз"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Үч манжаңыз менен солго же оңго сүрүңүз. Башка жаңсоолорду үйрөнүү үчүн таптаңыз."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Белгисиз"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Бардык параметрлерди кайра коесузбу?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Бардык ыкчам параметрлер түзмөктүн баштапкы маанилерине кайтарылат"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lo/strings.xml b/packages/SystemUI/res/values-lo/strings.xml
index e9e585e..4c778d1 100644
--- a/packages/SystemUI/res/values-lo/strings.xml
+++ b/packages/SystemUI/res/values-lo/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"ເຊື່ອມ​ຕໍ່​ຫາ <xliff:g id="BLUETOOTH">%s</xliff:g> ແລ້ວ."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"ເຊື່ອມຕໍ່ຫາ <xliff:g id="CAST">%s</xliff:g> ແລ້ວ."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ຂະຫຍາຍກຸ່ມ."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"ເພີ່ມອຸປະກອນໃສ່ໃນກຸ່ມ."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"ລຶບອຸປະກອນອອກຈາກກຸ່ມ."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ເປີດແອັບພລິເຄຊັນ."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"ບໍ່ໄດ້ເຊື່ອມຕໍ່."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ໂຣມມິງ"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ການປ້ອນຂໍ້ມູນ"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ເຄື່ອງຊ່ວຍຟັງ"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ກຳລັງເປີດ..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ບໍ່ສາມາດປັບຄວາມສະຫວ່າງໄດ້ເນື່ອງຈາກຄວບຄຸມໂດຍແອັບທາງເທິງ"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ໝຸນ​ອັດ​ຕະ​ໂນ​ມັດ"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ໝຸນໜ້າຈໍອັດຕະໂນມັດ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ສະຖານທີ່"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"ສຽງແວດລ້ອມ"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ຊ້າຍ"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ຂວາ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ຂະຫຍາຍເປັນການຄວບຄຸມທີ່ແຍກເບື້ອງຊ້າຍ ແລະ ຂວາ"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ຫຍໍ້ລົງເປັນການຄວບຄຸມແບບຮວມ"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"ປິດສຽງແວດລ້ອມ"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"ເພີ່ມໃສ່ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ຕຳແໜ່ງບໍ່ຖືກຕ້ອງ."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ຕຳແໜ່ງ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ເພີ່ມແຜ່ນແລ້ວ"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ລຶບແຜ່ນແລ້ວ"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ຕົວແກ້ໄຂການຕັ້ງຄ່າດ່ວນ"</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ບໍ່ຮູ້ຈັກ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ຣີເຊັດແຜ່ນທັງໝົດບໍ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ແຜ່ນການຕັ້ງຄ່າດ່ວນທັງໝົດຈະຣີເຊັດເປັນການຕັ້ງຄ່າແບບເກົ່າຂອງອຸປະກອນ"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lt/strings.xml b/packages/SystemUI/res/values-lt/strings.xml
index 0d4398e..f387a4e 100644
--- a/packages/SystemUI/res/values-lt/strings.xml
+++ b/packages/SystemUI/res/values-lt/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Prisijungta prie „<xliff:g id="BLUETOOTH">%s</xliff:g>“."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Prisijungta prie <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Išskleisti grupę."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Pridėti įrenginį prie grupės."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Pašalinti įrenginį iš grupės."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Atidaryti programą."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Neprijungta."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Tarptinklinis ryšys"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Įvestis"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Klausos aparatai"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Įjungiama…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Negalima koreguoti šviesumo, nes jį valdo viršuje esanti programa"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatinis pasukimas"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatiškai sukti ekraną"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Vietovė"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Aplinka"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kairė"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Dešinė"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Išskleisti į atskirus kairįjį ir dešinįjį valdiklius"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Sutraukti į bendrą valdiklį"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Nutildyti aplinką"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pridėkite <xliff:g id="POSITION">%1$d</xliff:g> pozicijoje"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Padėtis netinkama."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> pozicija"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Išklotinė pridėta"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Išklotinė pašalinta"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Sparčiųjų nustatymų redagavimo priemonė."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nežinoma"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Iš naujo nustatyti visus išklotines elementus?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Visi sparčiųjų nustatymų išklotinės elementai bus iš naujo nustatyti į pradinius įrenginio nustatymus"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-lv/strings.xml b/packages/SystemUI/res/values-lv/strings.xml
index 60e1e6f..fd54921 100644
--- a/packages/SystemUI/res/values-lv/strings.xml
+++ b/packages/SystemUI/res/values-lv/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ir izveidots savienojum ar <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Savienots ar ierīci <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Izvērst grupu."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Pievienot ierīci grupai."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Noņemt ierīci no grupas."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Atvērt lietojumprogrammu."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Savienojums nav izveidots."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Viesabonēšana"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ievade"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Dzirdes aparāti"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Notiek ieslēgšana…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Nevar mainīt spilgtumu, jo to kontrolē lietotne augšpusē"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automātiska pagriešana"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automātiska ekrāna pagriešana"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Atrašanās vieta"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Apkārtnes skaņas"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Pa kreisi"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Pa labi"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Izvērst, lai rādītu atsevišķu kreiso un labo vadīklu"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Sakļaut, lai rādītu vienotu vadīklu"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Izslēgt apkārtnes skaņas"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pievienot elementu pozīcijā numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Nederīga pozīcija."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozīcija numur <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Elements ir pievienots"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Elements ir noņemts"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Ātro iestatījumu redaktors."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nezināma"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vai atiestatīt visus elementus?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Visiem ātro iestatījumu elementiem tiks atiestatīti sākotnējie iestatījumi"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mk/strings.xml b/packages/SystemUI/res/values-mk/strings.xml
index 761eac1..2afe93e 100644
--- a/packages/SystemUI/res/values-mk/strings.xml
+++ b/packages/SystemUI/res/values-mk/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Поврзано со <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Поврзано со <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Проширете ја групата."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Додај го уредот во групата."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Отстрани го уредот од групата."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Отворете ја апликацијата."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Не е поврзана"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роаминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Влез"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слушни помагала"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Се вклучува…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Не може да се приспособи осветленоста бидејќи е контролирана од горната апликација"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматско ротирање"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматско ротирање на екранот"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Опкружување"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Лево"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Десно"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Прошири на одвоените контроли одлево и оддесно"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Собери на унифицирана контрола"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Исклучи го звукот на опкружувањето"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Прикажувај икони за известувања со низок приоритет"</string>
     <string name="other" msgid="429768510980739978">"Друго"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"вклучување/исклучување на големината на плочката"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"отстранување на плочката"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"додајте плочка на последната позиција"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Преместување на плочката"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додавање на позиција <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Позицијата е погрешна."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиција <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Додадена е плочка"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Отстранета е плочка"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Уредник за брзи поставки."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"За да ги видите скорешните апликации, повлечете нагоре и задржете со три прста на допирната подлога"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Притиснете го копчето за дејство на тастатурата за да ги видите сите апликации"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Редактирано"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Отклучете за да прегледате"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Отклучете за да го прегледате кодот"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Контекстуално образование"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Користете ја допирната подлога за да се вратите назад"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Повлечете налево или надесно со три прста. Допрете за да научите повеќе движења."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Непознато"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Да се ресетираат сите плочки?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Сите плочки на „Брзи поставки“ ќе се ресетираат на првичните поставки на уредот"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ml/strings.xml b/packages/SystemUI/res/values-ml/strings.xml
index aae5ac48..48d07cb 100644
--- a/packages/SystemUI/res/values-ml/strings.xml
+++ b/packages/SystemUI/res/values-ml/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> എന്നതിലേക്ക് കണക്‌റ്റുചെയ്‌തു."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> എന്നതിലേക്ക് കണക്റ്റുചെയ്തു."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ഗ്രൂപ്പ് വികസിപ്പിക്കുക."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"ഉപകരണം ഗ്രൂപ്പിലേക്ക് ചേർക്കുക."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"ഉപകരണം ഗ്രൂപ്പിൽ നിന്ന് നീക്കം ചെയ്യുക."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ആപ്പ് തുറക്കുക."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"കണക്റ്റുചെയ്‌തിട്ടില്ല."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"റോമിംഗ്"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ഇൻപുട്ട്"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ശ്രവണ സഹായികൾ"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ഓണാക്കുന്നു…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"തെളിച്ചം അഡ്‌ജസ്റ്റ് ചെയ്യാനാകില്ല, അത് നിയന്ത്രിക്കുന്നത് ടോപ്പ് ആപ്പാണ്"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"സ്‌ക്രീൻ സ്വയമേവ തിരിയൽ"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"സ്‌ക്രീൻ സ്വയമേവ തിരിക്കുക"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ലൊക്കേഷൻ"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"സറൗണ്ടിംഗ്‌സ്"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ഇടത്"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"വലത്"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"വേർതിരിച്ച ഇടത്, വലത് നിയന്ത്രണങ്ങളിലേക്ക് വികസിപ്പിക്കുക"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ഏകീകൃത നിയന്ത്രണത്തിലേക്ക് ചുരുക്കുക"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"സറൗണ്ടിംഗ്‌സ് മ്യൂട്ട് ചെയ്യുക"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> എന്ന സ്ഥാനത്തേക്ക് ചേർക്കുക"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"സ്ഥാനം അസാധുവാണ്."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"സ്ഥാനം <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ടൈൽ ചേർത്തു"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ടൈൽ നീക്കം ചെയ്‌തു"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ദ്രുത ക്രമീകരണ എഡിറ്റർ."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"അജ്ഞാതം"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"എല്ലാ ടൈലുകളും റീസെറ്റ് ചെയ്യണോ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"എല്ലാ ദ്രുത ക്രമീകരണ ടൈലുകളും ഉപകരണത്തിന്റെ ഒറിജിനൽ ക്രമീകരണത്തിലേക്ക് റീസെറ്റ് ചെയ്യും"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mn/strings.xml b/packages/SystemUI/res/values-mn/strings.xml
index 5938893..c7fb7da 100644
--- a/packages/SystemUI/res/values-mn/strings.xml
+++ b/packages/SystemUI/res/values-mn/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>-тай холбогдсон."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>-д холбогдсон."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Бүлгийг дэлгэнэ үү."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Бүлэгт төхөөрөмж нэмнэ."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Бүлгээс төхөөрөмж хасна."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Аппликейшныг нээнэ үү."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Холбогдоогүй."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Оролт"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Сонсголын төхөөрөмж"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Асааж байна…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Гэрэлтүүлгийг давуу эрхтэй аппаас хянаж байгаа тул тохируулах боломжгүй"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоматаар эргэх"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Дэлгэцийг автоматаар эргүүлэх"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Байршил"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Орчин тойрон"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Зүүн"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Баруун"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Зүүн, баруун талын тусдаа тохиргоо руу дэлгэх"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Нэгдсэн тохиргоо руу хураах"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Орчин тойрны дууг хаах"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Бага ач холбогдолтой мэдэгдлийн дүрс тэмдгийг харуулах"</string>
     <string name="other" msgid="429768510980739978">"Бусад"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"хавтангийн хэмжээг асаах/унтраах"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"хавтанг хасна уу"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"хавтанг сүүлийн байрлалд нэмэх"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Хавтанг зөөх"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> байрлалд нэмнэ үү"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Байрлал буруу байна."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> байрлал"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Хавтан нэмсэн"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Хавтанг хассан"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Шуурхай тохиргоо засварлагч."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Саяхны аппуудыг харахын тулд мэдрэгч самбар дээр гурван хуруугаараа дээш шудраад, удаан дарна уу"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Бүх аппаа харахын тулд гар дээр тань байх тусгай товчлуурыг дарна уу"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Хассан"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Харахын тулд түгжээг тайлна уу"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Кодыг харахын тулд түгжээг тайлна уу"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Хам сэдэвт боловсрол"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Буцахын тулд мэдрэгч самбараа ашиглах"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Гурван хуруугаараа зүүн эсвэл баруун тийш шударна уу. Илүү олон зангаа сурахын тулд товшино уу."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Тодорхойгүй"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Бүх хавтанг шинэчлэх үү?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Шуурхай тохиргооны бүх хавтан төхөөрөмжийн эх тохиргоо руу шинэчлэгдэнэ"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-mr/strings.xml b/packages/SystemUI/res/values-mr/strings.xml
index c3c7160..2c5a9a8 100644
--- a/packages/SystemUI/res/values-mr/strings.xml
+++ b/packages/SystemUI/res/values-mr/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> शी कनेक्‍ट केले."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> शी कनेक्ट केले."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"गटाचा विस्तार करा."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"डिव्हाइस गटामध्ये जोडा."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"डिव्हाइस गटामधून काढून टाका."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"अ‍ॅप उघडा."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"कनेक्ट केले नाही."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"रोमिंग"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"श्रवणयंत्रे"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"सुरू करत आहे…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ब्राइटनेस टॉप ॲपद्वारे नियंत्रित केला जात असल्यामुळे ॲडजस्ट करू शकत नाही"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ऑटो-रोटेट"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ऑटो-रोटेट स्क्रीन"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"स्थान"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"जवळपासचे"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"डावे"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"उजवे"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"डाव्या आणि उजव्या स्वतंत्र नियंत्रणांचा विस्तार करा"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"युनिफाइड नियंत्रणासाठी कोलॅप्स करा"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"जवळपासचे आवाज म्यूट करा"</string>
@@ -696,7 +699,7 @@
     <string name="screen_pinning_start" msgid="7483998671383371313">"ॲप पिन केले"</string>
     <string name="screen_pinning_exit" msgid="4553787518387346893">"ॲप अनपिन केले"</string>
     <string name="stream_voice_call" msgid="7468348170702375660">"कॉल"</string>
-    <string name="stream_system" msgid="7663148785370565134">"सिस्टम"</string>
+    <string name="stream_system" msgid="7663148785370565134">"सिस्टीम"</string>
     <string name="stream_ring" msgid="7550670036738697526">"रिंग"</string>
     <string name="stream_music" msgid="2188224742361847580">"मीडिया"</string>
     <string name="stream_alarm" msgid="16058075093011694">"अलार्म"</string>
@@ -741,9 +744,9 @@
     <string name="media_output_label_title" msgid="872824698593182505">"<xliff:g id="LABEL">%s</xliff:g> वर प्ले करत आहे"</string>
     <string name="media_output_title_without_playing" msgid="3825663683169305013">"यावर ऑडिओ प्ले होईल"</string>
     <string name="media_output_title_ongoing_call" msgid="208426888064112006">"यावर कॉल करत आहे"</string>
-    <string name="system_ui_tuner" msgid="1471348823289954729">"सिस्टम UI ट्युनर"</string>
+    <string name="system_ui_tuner" msgid="1471348823289954729">"सिस्टीम UI ट्युनर"</string>
     <string name="status_bar" msgid="4357390266055077437">"स्टेटस बार"</string>
-    <string name="demo_mode" msgid="263484519766901593">"सिस्टम UI डेमो मोड"</string>
+    <string name="demo_mode" msgid="263484519766901593">"सिस्टीम UI डेमो मोड"</string>
     <string name="enable_demo_mode" msgid="3180345364745966431">"डेमो मोड सुरू करा"</string>
     <string name="show_demo_mode" msgid="3677956462273059726">"डेमो मोड दर्शवा"</string>
     <string name="status_bar_ethernet" msgid="5690979758988647484">"इथरनेट"</string>
@@ -781,12 +784,12 @@
     <string name="accessibility_signal_full" msgid="1519655809806462972">"पूर्ण सिग्नल"</string>
     <string name="accessibility_managed_profile" msgid="4703836746209377356">"कार्य प्रोफाईल"</string>
     <string name="tuner_warning_title" msgid="7721976098452135267">"सर्वांसाठी नाही तर काहींसाठी मजेदार असू शकते"</string>
-    <string name="tuner_warning" msgid="1861736288458481650">"सिस्टम UI ट्युनर आपल्‍याला Android यूझर इंटरफेस ट्विक आणि कस्टमाइझ करण्‍याचे अनेक प्रकार देते. ही प्रयोगात्मक वैशिष्‍ट्ये बदलू शकतात, खंडित होऊ शकतात किंवा भविष्‍यातील रिलीज मध्‍ये कदाचित दिसणार नाहीत. सावधगिरी बाळगून पुढे सुरू ठेवा."</string>
+    <string name="tuner_warning" msgid="1861736288458481650">"सिस्टीम UI ट्युनर आपल्याला Android यूझर इंटरफेस ट्विक आणि कस्टमाइझ करण्याचे अनेक प्रकार देते. ही प्रयोगात्मक वैशिष्ट्ये बदलू शकतात, खंडित होऊ शकतात किंवा भविष्यातील रिलीझ मध्ये कदाचित दिसणार नाहीत. सावधगिरी बाळगून पुढे सुरू ठेवा."</string>
     <string name="tuner_persistent_warning" msgid="230466285569307806">"ही प्रयोगात्मक वैशिष्‍ट्ये बदलू शकतात, खंडित होऊ शकतात किंवा भविष्‍यातील रिलीज मध्‍ये कदाचित दिसणार नाहीत."</string>
     <string name="got_it" msgid="477119182261892069">"समजले"</string>
-    <string name="tuner_toast" msgid="3812684836514766951">"अभिनंदन! सिस्टम UI ट्युनर सेटिंग्जमध्‍ये जोडले गेले आहे"</string>
+    <string name="tuner_toast" msgid="3812684836514766951">"अभिनंदन! सिस्टीम UI ट्युनर सेटिंग्जमध्ये जोडले गेले आहे"</string>
     <string name="remove_from_settings" msgid="633775561782209994">"सेटिंग्ज मधून काढा"</string>
-    <string name="remove_from_settings_prompt" msgid="551565437265615426">"सेटिंग्ज मधून सिस्टम UI ट्युनर काढून त्याची सर्व वैशिष्ट्‍ये वापरणे थांबवायचे?"</string>
+    <string name="remove_from_settings_prompt" msgid="551565437265615426">"सेटिंग्ज मधून सिस्टीम UI ट्युनर काढून त्याची सर्व वैशिष्ट्ये वापरणे थांबवायचे?"</string>
     <string name="enable_bluetooth_title" msgid="866883307336662596">"ब्लूटूथ सुरू करायचे?"</string>
     <string name="enable_bluetooth_message" msgid="6740938333772779717">"तुमचा कीबोर्ड तुमच्या टॅबलेटसह कनेक्ट करण्यासाठी, तुम्ही प्रथम ब्लूटूथ सुरू करणे आवश्यक आहे."</string>
     <string name="enable_bluetooth_confirmation_ok" msgid="2866408183324184876">"सुरू करा"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> स्थानावर जोडा"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"स्थान चुकीचे आहे."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"स्थान <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"टाइल जोडली"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"टाइल काढून टाकली"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"द्रुत सेटिंग्ज संपादक."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"अज्ञात"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"सर्व टाइल रीसेट करायच्या?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"सर्व क्विक सेटिंग्ज टाइल डिव्हाइसच्या मूळ सेटिंग्जवर रीसेट केल्या जातील"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ms/strings.xml b/packages/SystemUI/res/values-ms/strings.xml
index 3c96d0a..5575098 100644
--- a/packages/SystemUI/res/values-ms/strings.xml
+++ b/packages/SystemUI/res/values-ms/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Disambungkan kepada <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Disambungkan ke <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Kembangkan kumpulan."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Tambahkan peranti pada kumpulan."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Alih keluar peranti daripada kumpulan."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Buka aplikasi."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Tidak disambungkan."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Perayauan"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Alat bantu pendengaran"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Menghidupkan…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Tidak dapat melaraskan kecerahan kerana peranti dikawal oleh apl bahagian atas"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoputar"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoputar skrin"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasi"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Persekitaran"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kiri"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Kanan"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Kembangkan kepada kawalan berasingan sebelah kiri dan kanan"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Kuncupkan kepada kawalan yang disatukan"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Redamkan persekitaran"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Tambahkan pada kedudukan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Kedudukan tidak sah."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Kedudukan <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Jubin ditambah"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Jubin dialih keluar"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor tetapan pantas."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Tidak diketahui"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Tetapkan semula semua jubin?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Semua jubin Tetapan Pantas akan ditetapkan semula kepada tetapan asal peranti"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-my/strings.xml b/packages/SystemUI/res/values-my/strings.xml
index b259e39..b428422 100644
--- a/packages/SystemUI/res/values-my/strings.xml
+++ b/packages/SystemUI/res/values-my/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>သို့ ချိတ်ဆက်ထား"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> သို့ချိတ်ဆက်ထားပါသည်။"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"အုပ်စုကို ပိုပြသည်။"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"အဖွဲ့သို့ စက်ပစ္စည်းထည့်ရန်။"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"အဖွဲ့မှ စက်ပစ္စည်းကို ဖယ်ရှားရန်။"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"အပလီကေးရှင်းကို ဖွင့်သည်။"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"ချိတ်ဆက်မထားပါ"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ပြင်ပကွန်ရက်သုံးခြင်း"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"အဝင်"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"နားကြားကိရိယာ"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ဖွင့်နေသည်…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"အပေါ်အက်ပ်မှ ထိန်းချုပ်ထားသောကြောင့် တောက်ပမှုကို ချိန်ညှိ၍ မရပါ"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"အော်တို-လည်"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"မျက်နှာပြင်အား အလိုအလျောက်လှည့်ခြင်း"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"တည်နေရာ"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"ဝန်းကျင်အသံ"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ဘယ်"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ညာ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ဘယ်ညာခွဲထားသော ထိန်းချုပ်မှုများအဖြစ် ပိုပြပါ"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ပေါင်းစည်းထားသော ထိန်းချုပ်မှုအဖြစ် လျှော့ပြပါ"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"ဝန်းကျင်အသံ ပိတ်ရန်"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"အရေးမကြီးသော အကြောင်းကြားချက် သင်္ကေတများ ပြရန်"</string>
     <string name="other" msgid="429768510980739978">"အခြား"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"အကွက်ငယ်၏ အရွယ်အစားကို ပြောင်းရန်"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"အကွက်ငယ်ကို ဖယ်ရှားရန်"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"နောက်ဆုံးနေရာတွင် အကွက်ငယ် ထည့်ရန်"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"အကွက်ငယ်ကို ရွှေ့ရန်"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> အနေအထားသို့ ပေါင်းထည့်ရန်"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"နေရာ မမှန်ပါ။"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g> အနေအထား"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"အကွက်ငယ်ကို ထည့်ပြီးပါပြီ"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"အကွက်ငယ်ကို ဖယ်ရှားပြီးပါပြီ"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"မြန်ဆန်သည့် ဆက်တင်တည်းဖြတ်စနစ်"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"လတ်တလောအက်ပ်များကို ကြည့်ရန် တာ့ချ်ပက်ပေါ်တွင် လက်သုံးချောင်းဖြင့် အပေါ်သို့ပွတ်ဆွဲပြီး ဖိထားပါ"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"သင့်အက်ပ်အားလုံးကြည့်ရန် ကီးဘုတ်ပေါ်ရှိ လုပ်ဆောင်ချက်ကီးကို နှိပ်ပါ"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"အစားထိုးထားသည်"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"ကြည့်ရန် ဖွင့်ပါ"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"ကုဒ်ကြည့်ရန် ဖွင့်ပါ"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"အကြောင်းအရာအလိုက် ပညာရေး"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"နောက်ပြန်သွားရန် သင့်တာ့ချ်ပက်ကို သုံးပါ"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"လက်သုံးချောင်းဖြင့် ဘယ် (သို့) ညာသို့ ပွတ်ဆွဲပါ။ လက်ဟန်များ ပိုမိုလေ့လာရန် တို့ပါ။"</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"အမျိုးအမည်မသိ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"အကွက်ငယ်အားလုံးကို ပြင်ဆင်သတ်မှတ်မလား။"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"အမြန်ဆက်တင်များ အကွက်ငယ်အားလုံးကို စက်ပစ္စည်း၏ မူရင်းဆက်တင်များသို့ ပြင်ဆင်သတ်မှတ်ပါမည်"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>၊ <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nb/strings.xml b/packages/SystemUI/res/values-nb/strings.xml
index 1c655f1..9574075 100644
--- a/packages/SystemUI/res/values-nb/strings.xml
+++ b/packages/SystemUI/res/values-nb/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Koblet til <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Koblet til <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Utvid gruppen."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Legg til enheten i gruppen."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Fjern enheten fra gruppen."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Åpne appen."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Ikke tilkoblet."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Innenhet"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Høreapparater"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Slår på …"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Kan ikke justere lysstyrken, fordi den kontrolleres av den øvre appen"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotér automatisk"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotér skjermen automatisk"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Sted"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Omgivelser"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Venstre"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Høyre"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Utvid til separate kontroller for venstre og høyre"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Skjul til samlet kontroll"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Kutt lyden for omgivelsene"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Vis ikoner for varsler med lav prioritet"</string>
     <string name="other" msgid="429768510980739978">"Annet"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"bytt størrelse på brikken"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"fjerne infobrikken"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"legge til en brikke på den siste posisjonen"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Flytt infobrikken"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Legg til posisjonen <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posisjonen er ugyldig."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisjon <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"En infobrikke er lagt til"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"En infobrikke er fjernet"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigeringsvindu for hurtiginnstillinger."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"For å se nylige apper, sveip opp og hold med tre fingre på styreflaten"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"For å se alle appene dine, trykk på handlingstasten på tastaturet"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Fjernet"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Lås opp for å se"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Lås opp for å se koden"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstuell opplæring"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Bruk styreflaten for å gå tilbake"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Sveip til venstre eller høyre med tre fingre. Trykk for å lære flere bevegelser."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Ukjent"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vil du tilbakestille alle brikkene?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle brikker for hurtiginnstillinger tilbakestilles til enhetens opprinnelige innstillinger"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ne/strings.xml b/packages/SystemUI/res/values-ne/strings.xml
index 133003e..4d37f8f 100644
--- a/packages/SystemUI/res/values-ne/strings.xml
+++ b/packages/SystemUI/res/values-ne/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> मा जडित।"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> मा कनेक्ट गरियो।"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"समूह एक्स्पान्ड गर्नुहोस्।"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"समूहमा डिभाइस हाल्नुहोस्।"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"समूहबाट डिभाइस हटाउनुहोस्।"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"एप खोल्नुहोस्।"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"जडान नगरिएको।"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"रोमिङ"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"इनपुट"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"हियरिङ डिभाइसहरू"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"सक्रिय गर्दै…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"सिरानको एपले चमक नियन्त्रण गरिरहेकाले चमक मिलाउन मिल्दैन"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"अटो रोटेट"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"स्क्रिन स्वतःघुम्ने"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"लोकेसन"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"वरपरका आवाज"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"बायाँ"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"दायाँ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"दायाँ र बायाँतर्फको भोल्युम छुट्टाछुट्टै व्यवस्थापन गर्न भोल्युम प्यानल छुट्ट्याउनुहोस्"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"कोल्याप्स गरी एउटै कन्ट्रोल बनाउनुहोस्"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"वरपरका आवाज म्युट गर्नुहोस्"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"कम प्राथमिकताका सूचना आइकनहरू देखाउनुहोस्"</string>
     <string name="other" msgid="429768510980739978">"अन्य"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"टाइलको आकार टगल गर्नुहोस्"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"टाइल हटाउनुहोस्"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"अन्तिम स्थानमा टाइल हाल्नुहोस्"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"टाइल सार्नुहोस्"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"टाइल यो अवस्था <xliff:g id="POSITION">%1$d</xliff:g> मा हाल्नुहोस्"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"पोजिसन अवैध छ।"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"स्थिति <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"टाइल हालियो"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"टाइल हटाइयो"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"द्रुत सेटिङ सम्पादक।"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"आफूले हालसालै चलाएका एपहरू हेर्न तीन वटा औँलाले टचप्याडमा माथितिर स्वाइप गर्नुहोस् र होल्ड गर्नुहोस्"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"आफ्ना सबै एपहरू हेर्न आफ्नो किबोर्डमा भएको एक्सन की थिच्नुहोस्"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"जानकारी लुकाउन सम्पादन गरिएको"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"हेर्न अनलक गर्नुहोस्"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"कोड हेर्न अनलक गर्नुहोस्"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"सान्दर्भिक शिक्षा"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"पछाडि जान आफ्नो टचप्याड प्रयोग गर्नुहोस्"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"तीन वटा औँला प्रयोग गरी बायाँ वा दायाँतिर स्वाइप गर्नुहोस्। थप जेस्चर प्रयोग गर्ने तरिका सिक्न ट्याप गर्नुहोस्।"</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"अज्ञात"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"सबै टाइलहरू रिसेट गर्ने हो?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"द्रुत सेटिङका सबै टाइलहरू रिसेट गरी डिभाइसका मूल सेटिङ लागू गरिने छन्"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-nl/strings.xml b/packages/SystemUI/res/values-nl/strings.xml
index 3881907..26d8752 100644
--- a/packages/SystemUI/res/values-nl/strings.xml
+++ b/packages/SystemUI/res/values-nl/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Verbonden met <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Verbonden met <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Groep uitvouwen."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Voeg het apparaat aan de groep toe."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Verwijder het apparaat uit de groep."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"App openen."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Niet verbonden."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Invoer"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hoortoestellen"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aanzetten…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Kan de helderheid niet aanpassen omdat deze wordt beheerd door de bovenste app"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatisch draaien"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Scherm automatisch draaien"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Locatie"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Omgevingsgeluid"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Links"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Rechts"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Uitvouwen naar gescheiden bediening voor links en rechts"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Samenvouwen tot geïntegreerde bediening"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Omgevingsgeluid uitzetten"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Iconen voor meldingen met lage prioriteit tonen"</string>
     <string name="other" msgid="429768510980739978">"Overig"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"het formaat van de tegel schakelen"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"tegel verwijderen"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"tegel toevoegen op de laatste positie"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Tegel verplaatsen"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Toevoegen aan positie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Positie ongeldig."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Positie <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Tegel toegevoegd"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Tegel verwijderd"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor voor \'Snelle instellingen\'."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Als je recente apps wilt bekijken, swipe je met 3 vingers omhoog op de touchpad en houd je vast"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Als je alle apps wilt bekijken, druk je op de actietoets op je toetsenbord"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Verborgen"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Ontgrendelen om te bekijken"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Ontgrendelen om de code te bekijken"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Contextuele educatie"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Je touchpad gebruiken om terug te gaan"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swipe met 3 vingers naar links of rechts. Tik voor meer gebaren."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Onbekend"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Alle tegels resetten?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alle tegels voor Snelle instellingen worden teruggezet naar de oorspronkelijke instellingen van het apparaat"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-or/strings.xml b/packages/SystemUI/res/values-or/strings.xml
index 9c561c9..a0e360c 100644
--- a/packages/SystemUI/res/values-or/strings.xml
+++ b/packages/SystemUI/res/values-or/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ସହ ସଂଯୁକ୍ତ"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> ସହିତ ସଂଯୁକ୍ତ।"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ଗ୍ରୁପକୁ ବିସ୍ତାର କରନ୍ତୁ।"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"ଗ୍ରୁପରେ ଡିଭାଇସ ଯୋଗ କରନ୍ତୁ।"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"ଗ୍ରୁପରୁ ଡିଭାଇସ କାଢ଼ି ଦିଅନ୍ତୁ।"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ଆପ୍ଲିକେସନ ଖୋଲନ୍ତୁ।"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"କନେକ୍ଟ ହୋଇନାହିଁ।"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ରୋମିଙ୍ଗ"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ଇନପୁଟ୍"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ଶ୍ରବଣ ଯନ୍ତ୍ର"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ଅନ୍ ହେଉଛି…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ଟପ ଆପ ଦ୍ୱାରା ଉଜ୍ଜ୍ୱଳତା ନିୟନ୍ତ୍ରିତ ହେଉଥିବା ଯୋଗୁଁ ଏହାକୁ ଆଡଜଷ୍ଟ କରିପାରିବେ ନାହିଁ"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ଅଟୋ-ରୋଟେଟ"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ଅଟୋ-ରୋଟେଟ ସ୍କ୍ରିନ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ଲୋକେସନ"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"ପରିପାର୍ଶ୍ୱ"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ବାମ"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ଡାହାଣ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ବାମ ଏବଂ ଡାହାଣ ଅଲଗା ନିୟନ୍ତ୍ରଣକୁ ବିସ୍ତାର କରନ୍ତୁ"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ଏକତ୍ରିତ ନିୟନ୍ତ୍ରଣକୁ ସଙ୍କୁଚିତ କରନ୍ତୁ"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"ପରିପାର୍ଶ୍ୱକୁ ମ୍ୟୁଟ କରନ୍ତୁ"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"କମ୍‍-ଅଗ୍ରାଧିକାର ବିଜ୍ଞପ୍ତି ଆଇକନ୍‍ ଦେଖାନ୍ତୁ"</string>
     <string name="other" msgid="429768510980739978">"ଅନ୍ୟ"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ଟାଇଲର ସାଇଜକୁ ଟୋଗଲ କରନ୍ତୁ"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ଟାଇଲ୍ କାଢ଼ି ଦିଅନ୍ତୁ"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"ଶେଷ ପୋଜିସନରେ ଟାଇଲ ଯୋଗ କରିବା"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ଟାଇଲ୍ ମୁଭ୍ କରନ୍ତୁ"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ଅବସ୍ଥିତିରେ ଯୋଗ କରନ୍ତୁ"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ଅବସ୍ଥିତି ଅବୈଧ ଅଟେ।"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ଅବସ୍ଥିତି <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ଟାଇଲ୍ ଯୋଗ କରାଯାଇଛି"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ଟାଇଲ୍ କାଢ଼ି ଦିଆଯାଇଛି"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ଦ୍ରୁତ ସେଟିଙ୍ଗ ଏଡିଟର୍।"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"ବର୍ତ୍ତମାନର ଆପ୍ସ ଭ୍ୟୁ କରିବାକୁ, ଟଚପେଡରେ ତିନୋଟି ଆଙ୍ଗୁଠିରେ ଉପରକୁ ସ୍ୱାଇପ କରି ଧରି ରଖନ୍ତୁ"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"ଆପଣଙ୍କ ସମସ୍ତ ଆପ୍ସ ଭ୍ୟୁ କରିବା ପାଇଁ ଆପଣଙ୍କ କୀବୋର୍ଡରେ ଆକ୍ସନ କୀ\'କୁ ଦବାନ୍ତୁ"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"ଲୁଚା ଯାଇଥିବା"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"ଭ୍ୟୁ କରିବାକୁ ଅନଲକ କରନ୍ତୁ"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"ଭ୍ୟୁ କରିବାକୁ ଅନଲକ କରିବା କୋଡ"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"ପ୍ରାସଙ୍ଗିକ ଶିକ୍ଷା"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ପଛକୁ ଫେରିବା ପାଇଁ ଆପଣଙ୍କ ଟଚପେଡକୁ ବ୍ୟବହାର କରନ୍ତୁ"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ତିନୋଟି ଆଙ୍ଗୁଠିରେ ବାମ ବା ଡାହାଣକୁ ସ୍ୱାଇପ କରନ୍ତୁ। ଜେଶ୍ଚରଗୁଡ଼ିକ ବିଷୟରେ ଅଧିକ ଜାଣିବାକୁ ଟାପ କରନ୍ତୁ।"</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ଅଜଣା"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ସମସ୍ତ ଟାଇଲକୁ ରିସେଟ କରିବେ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ସମସ୍ତ କୁଇକ ସେଟିଂସ ଟାଇଲ ଡିଭାଇସର ମୂଳ ସେଟିଂସରେ ରିସେଟ ହୋଇଯିବ"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pa/strings.xml b/packages/SystemUI/res/values-pa/strings.xml
index 6027538..f2a6612 100644
--- a/packages/SystemUI/res/values-pa/strings.xml
+++ b/packages/SystemUI/res/values-pa/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ।"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> ਨਾਲ ਕਨੈਕਟ ਕੀਤਾ ਗਿਆ।"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ਗਰੁੱਪ ਦਾ ਵਿਸਤਾਰ ਕਰੋ।"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"ਗਰੁੱਪ ਵਿੱਚ ਡੀਵਾਈਸ ਸ਼ਾਮਲ ਕਰੋ।"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"ਗਰੁੱਪ ਤੋਂ ਡੀਵਾਈਸ ਹਟਾਓ।"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ਐਪਲੀਕੇਸ਼ਨ ਖੋਲ੍ਹੋ।"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"ਕਨੈਕਟ ਨਹੀਂ ਕੀਤਾ।"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ਰੋਮਿੰਗ"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ਇਨਪੁੱਟ"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ਸੁਣਨ ਦੇ ਸਾਧਨ"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ਚਾਲੂ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ਚਮਕ ਨੂੰ ਵਿਵਸਥਿਤ ਨਹੀਂ ਕੀਤਾ ਜਾ ਸਕਦਾ ਕਿਉਂਕਿ ਪਹਿਲਾਂ ਤੋਂ ਚੱਲ ਰਹੀ ਐਪ ਇਸਨੂੰ ਕੰਟਰੋਲ ਕਰ ਰਹੀ ਹੈ"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ਸਵੈ-ਘੁਮਾਓ"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ਸਕ੍ਰੀਨ ਨੂੰ ਆਪਣੇ ਆਪ ਘੁੰਮਾਓ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ਟਿਕਾਣਾ"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"ਆਲੇ-ਦੁਆਲੇ"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ਖੱਬੇ"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ਸੱਜੇ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ਖੱਬੇ ਅਤੇ ਸੱਜੇ ਪਾਸੇ ਦੇ ਸ਼ੋਰ ਨੂੰ ਵੱਖ-ਵੱਖ ਕੰਟਰੋਲ ਕਰਨ ਲਈ ਵਿਸਤਾਰ ਕਰੋ"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ਏਕੀਕ੍ਰਿਤ ਕੰਟਰੋਲ \'ਤੇ ਜਾਣ ਲਈ ਸਮੇਟੋ"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"ਆਲੇ-ਦੁਆਲੇ ਦੇ ਸ਼ੋਰ ਨੂੰ ਮਿਊਟ ਕਰੋ"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ਸਥਾਨ \'ਤੇ ਸ਼ਾਮਲ ਕਰੋ"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ਮੌਜੂਦਾ ਥਾਂ ਅਵੈਧ ਹੈ।"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ਸਥਾਨ <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ਟਾਇਲ ਨੂੰ ਸ਼ਾਮਲ ਕੀਤਾ ਗਿਆ"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ਟਾਇਲ ਨੂੰ ਹਟਾ ਦਿੱਤਾ ਗਿਆ"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਸੰਪਾਦਕ।"</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ਅਗਿਆਤ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"ਕੀ ਸਾਰੀਆਂ ਟਾਇਲਾਂ ਨੂੰ ਰੀਸੈੱਟ ਕਰਨਾ ਹੈ?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"ਸਾਰੀਆਂ ਤਤਕਾਲ ਸੈਟਿੰਗਾਂ ਟਾਇਲਾਂ ਡੀਵਾਈਸ ਦੀਆਂ ਮੂਲ ਸੈਟਿੰਗਾਂ \'ਤੇ ਰੀਸੈੱਟ ਹੋ ਜਾਣਗੀਆਂ"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pl/strings.xml b/packages/SystemUI/res/values-pl/strings.xml
index 35ff6c9..99e99e1 100644
--- a/packages/SystemUI/res/values-pl/strings.xml
+++ b/packages/SystemUI/res/values-pl/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Połączono z <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Połączono z urządzeniem <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Rozwiń grupę."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Dodaj urządzenie do grupy."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Usuń urządzenie z grupy."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Otwórz aplikację."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nie połączono."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Wejście"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparaty słuchowe"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Włączam…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Nie można dostosować jasności, ponieważ reguluje ją aplikacja na pierwszym planie"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Autoobracanie"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Autoobracanie ekranu"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokalizacja"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Otoczenie"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Po lewej"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Po prawej"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Rozwiń, aby oddzielić elementy sterujące po lewej i po prawej stronie"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Zwiń do ujednoliconego sterowania"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Wycisz otoczenie"</string>
@@ -582,13 +585,13 @@
     <string name="media_projection_entry_app_permission_dialog_continue_entire_screen" msgid="1850848182344377579">"Udostępnij ekran"</string>
     <string name="media_projection_entry_app_permission_dialog_single_app_disabled" msgid="8999903044874669995">"<xliff:g id="APP_NAME">%1$s</xliff:g> ma wyłączoną tę opcję"</string>
     <string name="media_projection_entry_share_app_selector_title" msgid="1419515119767501822">"Wybierz aplikację do udostępniania"</string>
-    <string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Włączyć przesyłanie treści wyświetlanych na ekranie?"</string>
+    <string name="media_projection_entry_cast_permission_dialog_title" msgid="752756942658159416">"Włączyć przesyłanie treści z ekranu?"</string>
     <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Przesyłanie obrazu z 1 aplikacji"</string>
     <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Przesyłanie całego ekranu"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"Kiedy przesyłasz treści z całego ekranu, widoczny jest cały obraz z wyświetlacza. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string>
-    <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Kiedy przesyłasz obraz z aplikacji, widoczne jest wszystko to, co jest w niej wyświetlane lub odtwarzane. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, audio i filmów."</string>
+    <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Kiedy przesyłasz obraz z aplikacji, widoczne jest wszystko, co jest w niej wyświetlane lub odtwarzane. Uważaj więc na takie treści jak hasła, dane do płatności, wiadomości, zdjęcia, audio czy filmy."</string>
     <string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"Prześlij ekran"</string>
-    <string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"Wybieranie aplikacji do przesyłania"</string>
+    <string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"Wybierz aplikację do przesyłania"</string>
     <string name="media_projection_entry_generic_permission_dialog_title" msgid="4519802931547483628">"Rozpocząć udostępnianie?"</string>
     <string name="media_projection_entry_generic_permission_dialog_warning_entire_screen" msgid="5407906851409410209">"Podczas udostępniania, nagrywania lub przesyłania treści Android ma dostęp do wszystkiego, co jest widoczne na ekranie lub odtwarzane na urządzeniu. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, dźwięku i filmów."</string>
     <string name="media_projection_entry_generic_permission_dialog_warning_single_app" msgid="3454859977888159495">"Podczas udostępniania, nagrywania lub przesyłania treści Android ma dostęp do wszystkiego, co jest w niej wyświetlane lub odtwarzane. Dlatego zachowaj ostrożność w zakresie haseł, danych do płatności, wiadomości, zdjęć, dźwięku i filmów."</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Pokazuj ikony powiadomień o niskim priorytecie"</string>
     <string name="other" msgid="429768510980739978">"Inne"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"przełącz rozmiar kafelka"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"usunąć kartę"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"dodaj kafelek do ostatniej pozycji"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Przenieś kartę"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodaj w pozycji <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Nieprawidłowa pozycja."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozycja <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Dodano kartę"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Usunięto kartę"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Edytor szybkich ustawień."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Aby wyświetlić ostatnie aplikacje, przesuń w górę za pomocą 3 palców na touchpadzie i przytrzymaj."</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Aby wyświetlić wszystkie swoje aplikacje, naciśnij klawisz działania na klawiaturze"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Usunięto"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Odblokuj, aby zobaczyć"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Odblokuj, aby zobaczyć kod"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Edukacja kontekstowa"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Przechodzenie wstecz za pomocą touchpada"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Przesuń trzema palcami w prawo lub lewo. Kliknij, aby poznać więcej gestów."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nieznane"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Zresetować wszystkie kafelki?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Wszystkie kafelki Szybkich ustawień zostaną zresetowane do oryginalnych ustawień urządzenia"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rBR/strings.xml b/packages/SystemUI/res/values-pt-rBR/strings.xml
index fc7e2af..4663dba 100644
--- a/packages/SystemUI/res/values-pt-rBR/strings.xml
+++ b/packages/SystemUI/res/values-pt-rBR/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expandir grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Adicionar dispositivo ao grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Remover dispositivo do grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Abrir aplicativo."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Sem conexão."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparelhos auditivos"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ativando…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Não é possível ajustar o brilho, porque ele está sendo controlado pelo app principal"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
@@ -351,7 +348,7 @@
     <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Redes indisponíveis"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nenhuma rede Wi-Fi disponível"</string>
     <string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Ativando…"</string>
-    <string name="quick_settings_cast_title" msgid="3033553249449938182">"Transmitir"</string>
+    <string name="quick_settings_cast_title" msgid="3033553249449938182">"Transmissão"</string>
     <string name="quick_settings_casting" msgid="1435880708719268055">"Transmitindo"</string>
     <string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Dispositivo sem nome"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Não há dispositivos disponíveis"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Som ambiente"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Lado esquerdo"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Lado direito"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Abrir para controles separados da esquerda e da direita"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Fechar para controle unificado"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Silenciar som ambiente"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar ícones de notificações de baixa prioridade"</string>
     <string name="other" msgid="429768510980739978">"Outros"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"alternar o tamanho do bloco"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remover o bloco"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"adicionar o bloco à última posição"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover bloco"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicionar à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posição inválida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Bloco adicionado"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Bloco removido"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configurações rápidas."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Se quiser ver os apps recentes, deslize para cima e pressione o touchpad com três dedos"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Para ver todos os apps, pressione a tecla de ação no teclado"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Encoberto"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Desbloqueie para ver"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Desbloqueie para ver o código"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Educação contextual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Use o touchpad para voltar"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Deslize para a esquerda ou direita usando três dedos. Toque para aprender outros gestos."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconhecidos"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Redefinir todos os blocos?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Todos os blocos \"Configurações rápidas\" serão redefinidos para as configurações originais do dispositivo"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt-rPT/strings.xml b/packages/SystemUI/res/values-pt-rPT/strings.xml
index 14b85b7..7a0e4f6 100644
--- a/packages/SystemUI/res/values-pt-rPT/strings.xml
+++ b/packages/SystemUI/res/values-pt-rPT/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ligado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Ligado a <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expanda o grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Adicionar dispositivo ao grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Remover dispositivo do grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Abra a aplicação."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Sem ligação."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparelhos auditivos"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"A ativar..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Não é possível ajustar o brilho porque está a ser controlado pela app principal"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotação auto."</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rodar o ecrã automaticamente"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ambiente"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Esquerda"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Direita"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Expandir para controlos separados do lado direito e esquerdo"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Reduzir para controlo unificado"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Desativar som do ambiente"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicione à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posição inválida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Cartão adicionado"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Cartão removido"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de definições rápidas."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconhecido"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Repor todos os mosaicos?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Todos os mosaicos de Definições rápidas vão ser repostos para as definições originais do dispositivo"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-pt/strings.xml b/packages/SystemUI/res/values-pt/strings.xml
index fc7e2af..4663dba 100644
--- a/packages/SystemUI/res/values-pt/strings.xml
+++ b/packages/SystemUI/res/values-pt/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectado a <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Conectado a <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Expandir grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Adicionar dispositivo ao grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Remover dispositivo do grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Abrir aplicativo."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Sem conexão."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Entrada"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparelhos auditivos"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ativando…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Não é possível ajustar o brilho, porque ele está sendo controlado pelo app principal"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Giro automático"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Giro automático da tela"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Localização"</string>
@@ -351,7 +348,7 @@
     <string name="quick_settings_networks_unavailable" msgid="1167847013337940082">"Redes indisponíveis"</string>
     <string name="quick_settings_wifi_detail_empty_text" msgid="483130889414601732">"Nenhuma rede Wi-Fi disponível"</string>
     <string name="quick_settings_wifi_secondary_label_transient" msgid="7501659015509357887">"Ativando…"</string>
-    <string name="quick_settings_cast_title" msgid="3033553249449938182">"Transmitir"</string>
+    <string name="quick_settings_cast_title" msgid="3033553249449938182">"Transmissão"</string>
     <string name="quick_settings_casting" msgid="1435880708719268055">"Transmitindo"</string>
     <string name="quick_settings_cast_device_default_name" msgid="6988469571141331700">"Dispositivo sem nome"</string>
     <string name="quick_settings_cast_detail_empty_text" msgid="2846282280014617785">"Não há dispositivos disponíveis"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Som ambiente"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Lado esquerdo"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Lado direito"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Abrir para controles separados da esquerda e da direita"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Fechar para controle unificado"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Silenciar som ambiente"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Mostrar ícones de notificações de baixa prioridade"</string>
     <string name="other" msgid="429768510980739978">"Outros"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"alternar o tamanho do bloco"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"remover o bloco"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"adicionar o bloco à última posição"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mover bloco"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adicionar à posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Posição inválida."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posição <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Bloco adicionado"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Bloco removido"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor de configurações rápidas."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Se quiser ver os apps recentes, deslize para cima e pressione o touchpad com três dedos"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Para ver todos os apps, pressione a tecla de ação no teclado"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Encoberto"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Desbloqueie para ver"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Desbloqueie para ver o código"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Educação contextual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Use o touchpad para voltar"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Deslize para a esquerda ou direita usando três dedos. Toque para aprender outros gestos."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Desconhecidos"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Redefinir todos os blocos?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Todos os blocos \"Configurações rápidas\" serão redefinidos para as configurações originais do dispositivo"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ro/strings.xml b/packages/SystemUI/res/values-ro/strings.xml
index b577be5..e8b826b 100644
--- a/packages/SystemUI/res/values-ro/strings.xml
+++ b/packages/SystemUI/res/values-ro/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Conectat la <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"S-a stabilit conexiunea la <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Extinde grupul."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Adaugă dispozitivul în grup."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Elimină dispozitivul din grup."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Deschide aplicația."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Neconectat."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Intrare"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparate auditive"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Se activează..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Nu se poate ajusta luminozitatea deoarece este controlată de aplicația de sus"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotire automată"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotirea automată a ecranului"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Locație"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Împrejurimi"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Stânga"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Dreapta"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Extinde comenzile separate la stânga și la dreapta"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Restrânge la comanda unificată"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Dezactivează sunetul ambiental"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Afișează pictogramele de notificare cu prioritate redusă"</string>
     <string name="other" msgid="429768510980739978">"Altele"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"comută dimensiunea cardului"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"elimină cardul"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"adaugă cardul în ultima poziție"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Mută cardul"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Adaugă pe poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Poziție nevalidă."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Poziția <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Cardul a fost adăugat"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Cardul a fost eliminat"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editorul pentru setări rapide."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Ca să vezi aplicațiile recente, glisează în sus și ține apăsat cu trei degete pe touchpad"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Ca să vezi toate aplicațiile, apasă tasta de acțiuni de pe tastatură"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Ascunsă"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Deblochează pentru a afișa"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Deblochează pentru a vedea codul"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Educație contextuală"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Folosește-ți touchpadul ca să revii"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Glisează la stânga sau la dreapta cu trei degete. Atinge ca să înveți mai multe gesturi."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Necunoscută"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Resetezi toate cardurile?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Toate cardurile Setări rapide se vor reseta la setările inițiale ale dispozitivului"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ru/strings.xml b/packages/SystemUI/res/values-ru/strings.xml
index 03b5423..52458eb 100644
--- a/packages/SystemUI/res/values-ru/strings.xml
+++ b/packages/SystemUI/res/values-ru/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>: подключено."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Подключено к: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Развернуть группу."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Добавить устройство в группу."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Удалить устройство из группы."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Открыть приложение."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Не подключено"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роуминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Устройство ввода"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слуховые аппараты"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Включение…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Невозможно изменить яркость, поскольку ею управляет приложение сверху"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автоповорот"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоповорот экрана"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Геолокация"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Окружающие звуки"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Левый"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Правый"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Разделить на левый и правый элемент управления"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Объединить в один элемент управления"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Заглушить окружающие звуки"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Добавить на позицию <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Недопустимое расположение."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиция <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Панель добавлена"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Панель удалена"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор быстрых настроек."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Неизвестно"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Сбросить все параметры?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Для всех параметров быстрых настроек будут восстановлены значения по умолчанию."</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-si/strings.xml b/packages/SystemUI/res/values-si/strings.xml
index 15441b5..84a981f 100644
--- a/packages/SystemUI/res/values-si/strings.xml
+++ b/packages/SystemUI/res/values-si/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> වෙත සම්බන්ධ කරන ලදි."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> වෙත සම්බන්ධ විය."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"සමූහය දිගහැරීම"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"සමූහයට උපාංගය එක් කරන්න."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"උපාංගය සමූහයෙන් ඉවත් කරන්න."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"යෙදුම විවෘත කරන්න."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"සම්බන්ධ වී නැත."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"රෝමිං"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ආදානය"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"ශ්‍රවණාධාරක"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ක්‍රියාත්මක කරමින්…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ඉහළ යෙදුම මඟින් එය පාලනය වන නිසා දීප්තිය ගැළපුම් කළ නොහැක"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ස්වයංක්‍රීය කරකැවීම"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"ස්වයංක්‍රීයව-භ්‍රමණය වන තිරය"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ස්ථානය"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"වටපිටාව"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"වම"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"දකුණ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"වමට සහ දකුණට වෙන් වූ පාලන වෙත පුළුල් කරන්න"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ඒකාබද්ධ පාලනයට හකුළන්න"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"අවට පරිසරය නිහඬ කරන්න"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"අඩු ප්‍රමුඛතා දැනුම්දීම් අයිකන පෙන්වන්න"</string>
     <string name="other" msgid="429768510980739978">"වෙනත්"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ටයිල් එකේ ප්‍රමාණය මාරු කරන්න"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ටයිල් ඉවත් කරන්න"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"ටයිල් එක අවසාන ස්ථානයට එක් කරන්න"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ටයිල් ගෙන යන්න"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> ස්ථානයට එක් කරන්න"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ස්ථානය අවලංගුයි."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ස්ථානය <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ටයිල් එක එක් කරන ලදි"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ටයිල් ඉවත් කරන ලදි"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ඉක්මන් සැකසුම් සංස්කාරකය."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"මෑත යෙදුම් බැලීමට, ඉහළට ස්වයිප් කර ස්පර්ශ පුවරුව මත ඇඟිලි තුනකින් අල්ලාගෙන සිටින්න"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"ඔබේ සියලුම යෙදුම් බැලීමට, ඔබේ යතුරුපුවරුවේ ක්‍රියාකාරී යතුර ඔබන්න"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"නැවත සකස් කරන ලද"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"බැලීමට අගුළු හරින්න"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"කේතය බැලීමට අගුළු හරින්න"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"සන්දර්භීය අධ්‍යාපනය"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ආපසු යාමට ඔබේ ස්පර්ශ පුවරුව භාවිත කරන්න"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ඇඟිලි තුනක් භාවිතයෙන් වමට හෝ දකුණට ස්වයිප් කරන්න. තව ඉංගිත දැන ගැනීමට තට්ටු කරන්න."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"නොදනී"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"සියලු ටයිල් නැවත සකසන්න ද?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"සියලු ඉක්මන් සැකසීම් ටයිල් උපාංගයේ මුල් සැකසීම් වෙත නැවත සකසනු ඇත"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sk/strings.xml b/packages/SystemUI/res/values-sk/strings.xml
index 868e939..78a332a 100644
--- a/packages/SystemUI/res/values-sk/strings.xml
+++ b/packages/SystemUI/res/values-sk/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Pripojené k zariadeniu <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Pripojené k zariadeniu <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Rozbaliť skupinu"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Pridať zariadenie do skupiny"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Odstrániť zariadenie zo skupiny"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Otvoriť aplikáciu"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nepripojené."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vstup"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Načúvadlá"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Zapína sa…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Jas sa nedá upraviť, pretože ho ovláda horná aplikácia"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Automatické otáčanie"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Automatické otáčanie obrazovky"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Poloha"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okolie"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vľavo"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Vpravo"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Rozbaliť na samostatné ovládanie ľavej a pravej strany"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Zbaliť na jednotné ovládanie"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Vypnúť zvuk okolia"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Zobraziť ikony upozornení s nízkou prioritou"</string>
     <string name="other" msgid="429768510980739978">"Ďalšie"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"prepnúť veľkosť karty"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"odstrániť kartu"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"pridáte kartu na poslednú pozíciu"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Presunúť kartu"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Pridať na <xliff:g id="POSITION">%1$d</xliff:g>. pozíciu"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozícia je neplatná."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. pozícia"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Karta bola pridaná"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Karta bola odstránená"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor rýchlych nastavení"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Ak si chcete zobraziť nedávne aplikácie, potiahnite po touchpade troma prstami nahor a pridržte ich."</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Ak si chcete zobraziť všetky aplikácie, stlačte na klávesnici akčný kláves"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Zamaskované"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Zobrazíte odomknutím"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Kód sa zobrazí po odomknutí"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontextová náuka"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Prechádzajte späť pomocou touchpadu"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Potiahnite troma prstami doľava alebo doprava. Viac o gestách sa dozviete klepnutím."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Neznáme"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Chcete resetovať všetky karty?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Všetky karty rýchlych nastavení sa resetujú na pôvodné nastavenia zariadenia"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sl/strings.xml b/packages/SystemUI/res/values-sl/strings.xml
index e6d133e..93649f5 100644
--- a/packages/SystemUI/res/values-sl/strings.xml
+++ b/packages/SystemUI/res/values-sl/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Povezava vzpostavljena z: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Vzpostavljena povezava: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Razširitev skupine."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Dodajte napravo v skupino."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Odstranite napravo iz skupine."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Odpiranje aplikacije."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Ni povezan."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Gostovanje"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vhodna naprava"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Slušni aparati"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Vklapljanje …"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Svetlosti ni mogoče prilagoditi, ker jo nadzoruje aplikacija na vrhu"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Samodejno sukanje"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Samodejno sukanje zaslona"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokacija"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Okolica"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Levo"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Desno"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Razširitev na ločene kontrolnike za levo in desno stran"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Strnitev v enotni kontrolnik"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Izklop okoliškega zvoka"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Pokaži ikone obvestil z nizko stopnjo prednosti"</string>
     <string name="other" msgid="429768510980739978">"Drugo"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"preklop velikosti ploščice"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"odstranitev ploščice"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"dodajanje ploščice na zadnji položaj"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Premik ploščice"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Dodajanje na položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Položaj je neveljaven."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Položaj <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Ploščica je bila dodana"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Ploščica je bila odstranjena"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Urejevalnik hitrih nastavitev."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Za ogled nedavnih aplikacij povlecite s tremi prsti navzgor po sledilni ploščici in pridržite"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Za ogled vseh aplikacij pritisnite tipko za dejanja na tipkovnici"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Zakrito"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Odklenite za ogled"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Odklenite za ogled kode"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstualno izobraževanje"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Uporaba sledilne ploščice za pomik nazaj"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"S tremi prsti povlecite levo ali desno. Dotaknite se, če želite spoznati več potez."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Neznano"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Želite ponastaviti vse ploščice?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Vse ploščice v hitrih nastavitvah bodo ponastavljene na prvotne nastavitve naprave."</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sq/strings.xml b/packages/SystemUI/res/values-sq/strings.xml
index 724c6c0..5e69808 100644
--- a/packages/SystemUI/res/values-sq/strings.xml
+++ b/packages/SystemUI/res/values-sq/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Lidhur me <xliff:g id="BLUETOOTH">%s</xliff:g>"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Është lidhur me <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Zgjero grupin."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Shto pajisjen te grupi."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Hiq pajisjen nga grupi."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Hap aplikacionin."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Nuk është i lidhur."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Hyrja"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Aparatet e dëgjimit"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Po aktivizohet…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Ndriçimi nuk mund të rregullohet pasi po kontrollohet nga aplikacioni lart"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rrotullim automatik"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rrotullimi automatik i ekranit"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Vendndodhja"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Ambienti rrethues"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Majtas"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Djathtas"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Zgjero te kontrollet e veçuara majtas dhe djathtas"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Palos te kontrolli i unifikuar"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Vendos në heshtje ambientin rrethues"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Shfaq ikonat e njoftimeve me përparësi të ulët"</string>
     <string name="other" msgid="429768510980739978">"Të tjera"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ndrysho madhësinë e pllakëzës"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"hiq pllakëzën"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"shtuar pllakëzën në pozicionin e fundit"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Zhvendos pllakëzën"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Shto te pozicioni <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozicion i pavlefshëm."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Pozicioni <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Pllakëza u shtua"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Pllakëza u hoq"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redaktori i cilësimeve të shpejta."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Për aplikacionet e fundit, rrëshqit shpejt lart dhe mbaj shtypur me tre gishta në bllokun me prekje"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Për të shikuar të gjitha aplikacionet, shtyp tastin e veprimit në tastierë"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Redaktuar"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Shkyçe për ta parë"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Shkyçe për të parë kodin"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Edukimi kontekstual"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Përdor bllokun me prekje për t\'u kthyer prapa"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Rrëshqit shpejt majtas ose djathtas duke përdorur tre gishta. Trokit për të mësuar më shumë gjeste."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Nuk njihet"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Të rivendosen të gjitha pllakëzat?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Të gjitha pllakëzat e \"Cilësimeve të shpejta\" do të rivendosen te cilësimet origjinale të pajisjes"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sr/strings.xml b/packages/SystemUI/res/values-sr/strings.xml
index e6471eb..1b645a8 100644
--- a/packages/SystemUI/res/values-sr/strings.xml
+++ b/packages/SystemUI/res/values-sr/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Повезани сте са <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Повезани смо са уређајем <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Проширите групу."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Додајте уређај у групу."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Уклоните уређај из групе."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Отворите апликацију."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Није повезано."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роминг"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Унос"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слушни апарати"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Укључује се..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Не можете да прилагодите осветљеност јер је контролише апликација у првом плану"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Аутоматска ротација"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Аутоматско ротирање екрана"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Локација"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Окружење"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Лево"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Десно"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Прошири на контроле раздвојене на леву и десну страну"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Скупи у јединствену контролу"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Искључи звук окружења"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додајте на <xliff:g id="POSITION">%1$d</xliff:g>. позицију"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Позиција је неважећа."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"<xliff:g id="POSITION">%1$d</xliff:g>. позиција"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Плочица је додата"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Плочица је уклоњена"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Уређивач за Брза подешавања."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Непознато"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Желите да ресетујете све плочице?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Све плочице Брзих подешавања ће се ресетовати на првобитна подешавања уређаја"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sv/strings.xml b/packages/SystemUI/res/values-sv/strings.xml
index 9f2a208..a4129e0 100644
--- a/packages/SystemUI/res/values-sv/strings.xml
+++ b/packages/SystemUI/res/values-sv/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ansluten till <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Ansluten till <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Utöka gruppen."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Lägg till enheten i gruppen."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Ta bort enheten från gruppen."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Öppna appen."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Inte ansluten."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Ingång"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Hörapparater"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Aktiverar …"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Det går inte att ändra ljusstyrkan eftersom den styrs av den översta appen"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Rotera automatiskt"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Rotera skärmen automatiskt"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Plats"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Omgivningsläge"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Vänster"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Höger"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Utöka till kontroller till vänster och höger"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Komprimera till enhetlig kontroll"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Stäng av omgivningsljudet"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Lägg till på position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Positionen är ogiltig."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Position <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kortet har lagts till"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kortet har tagits bort"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Redigerare för snabbinställningar."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Okänt"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Vill du återställa alla rutor?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Alla Snabbinställningsrutor återställs till enhetens ursprungliga inställningar"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/strings.xml b/packages/SystemUI/res/values-sw/strings.xml
index 6222a76..cb82aff 100644
--- a/packages/SystemUI/res/values-sw/strings.xml
+++ b/packages/SystemUI/res/values-sw/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Imeunganishwa kwenye <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Imeunganishwa kwenye <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Panua kikundi."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Weka kifaa kwenye kikundi."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Ondoa kifaa kwenye kikundi."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Fungua programu."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Haijaunganishwa."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Mitandao ya ng\'ambo"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Vifaa vya kuingiza sauti"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Visaidizi vya kusikia"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Inawasha..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Imeshindwa kurekebisha mwangaza kwa sababu inadhibitiwa na programu iliyo juu"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Zungusha kiotomatiki"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Skrini ijizungushe kiotomatiki"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Mahali"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Mazingira"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kushoto"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Kulia"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Panua iwe vidhibiti vilivyotenganishwa kushoto na kulia"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Kunja iwe kidhibiti cha pamoja"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Zima sauti ya mazingira"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Onyesha aikoni za arifa zisizo muhimu"</string>
     <string name="other" msgid="429768510980739978">"Nyingine"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"ubadilishe ukubwa wa kigae"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"ondoa kigae"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"weka kigae kwenye nafasi ya mwisho"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Hamisha kigae"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Ongeza kwenye nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Nafasi si sahihi."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Nafasi ya <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kigae kimewekwa"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kigae kimeondolewa"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Kihariri cha Mipangilio ya haraka."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Telezesha vidole vitatu juu na ushikilie kwenye padi ya kugusa ili uangalie programu za hivi majuzi"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Bonyeza kitufe cha vitendo kwenye kibodi yako ili uangalie programu zako zote"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Maandishi yameondolewa"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Fungua ili uone"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Fungua ili uone msimbo"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Elimu inayolingana na muktadha"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Kutumia padi yako ya kugusa ili kurudi nyuma"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Telezesha vidole vitatu kulia au kushoto. Gusa ili upate maelezo kuhusu miguso zaidi."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Visivyojulikana"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Ungependa kubadilisha vigae vyote?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Vigae vyote vya Mipangilio ya Haraka vitabadilishwa kuwa katika mipangilio halisi ya kifaa"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-sw/tiles_states_strings.xml b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
index fb6e38f..a16a7b7 100644
--- a/packages/SystemUI/res/values-sw/tiles_states_strings.xml
+++ b/packages/SystemUI/res/values-sw/tiles_states_strings.xml
@@ -68,7 +68,7 @@
   </string-array>
   <string-array name="tile_states_bt">
     <item msgid="5330252067413512277">"Hakipatikani"</item>
-    <item msgid="5315121904534729843">"Kimezimwa"</item>
+    <item msgid="5315121904534729843">"Imezimwa"</item>
     <item msgid="503679232285959074">"Imewashwa"</item>
   </string-array>
   <string-array name="tile_states_airplane">
diff --git a/packages/SystemUI/res/values-sw720dp-land/dimens.xml b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
index 41bb37e..f4f0424 100644
--- a/packages/SystemUI/res/values-sw720dp-land/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-land/dimens.xml
@@ -30,11 +30,6 @@
          not appear immediately after user swipes to the side -->
     <dimen name="qs_tiles_page_horizontal_margin">20dp</dimen>
 
-    <!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
-    <dimen name="qs_media_rec_icon_top_margin">16dp</dimen>
-    <dimen name="qs_media_rec_album_size">112dp</dimen>
-    <dimen name="qs_media_rec_album_side_margin">16dp</dimen>
-
     <dimen name="controls_panel_corner_radius">40dp</dimen>
 
     <dimen name="lockscreen_shade_max_over_scroll_amount">42dp</dimen>
diff --git a/packages/SystemUI/res/values-ta/strings.xml b/packages/SystemUI/res/values-ta/strings.xml
index 0bf5f22..77be6ea 100644
--- a/packages/SystemUI/res/values-ta/strings.xml
+++ b/packages/SystemUI/res/values-ta/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>க்கு இணைக்கப்பட்டது."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> உடன் இணைக்கப்பட்டுள்ளது."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"குழுவை விரிவாக்கும்."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"குழுவில் சாதனத்தைச் சேர்க்கும்."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"குழுவிலிருந்து சாதனத்தை அகற்றும்."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ஆப்ஸைத் திறக்கும்."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"இணைக்கப்படவில்லை."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"ரோமிங்"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"உள்ளீடு"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"செவித்துணைக் கருவி"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ஆன் செய்கிறது…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ஒளிர்வை மேலுள்ள ஆப்ஸ் கட்டுப்படுத்துவதால் அதை மாற்ற முடியவில்லை"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"தானாகச் சுழற்று"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"திரையைத் தானாகச் சுழற்று"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"இருப்பிடம்"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"சுற்றுப்புறங்கள்"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"இடது"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"வலது"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"இடது மற்றும் வலதுபுறம் உள்ள கட்டுப்பாடுகளை விரிவாக்கும்"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ஒருங்கிணைந்த கட்டுப்பாட்டுக்குச் சுருக்கும்"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"சுற்றுப்புறங்களின் ஒலியை அடக்கும்"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"குறைந்த முன்னுரிமை உள்ள அறிவிப்பு ஐகான்களைக் காட்டு"</string>
     <string name="other" msgid="429768510980739978">"மற்றவை"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"கட்டத்தின் அளவை நிலைமாற்றும்"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"கட்டத்தை அகற்றும்"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"கடைசி இடத்தில் கட்டத்தைச் சேர்க்கலாம்"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"கட்டத்தை நகர்த்து"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g>ல் சேர்க்கும்"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"நிலை தவறானது."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"இடம்: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"கட்டம் சேர்க்கப்பட்டது"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"கட்டம் அகற்றப்பட்டது"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"விரைவு அமைப்புகள் திருத்தி."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"சமீபத்திய ஆப்ஸைப் பார்க்க, டச்பேடில் மூன்று விரல்களால் மேல்நோக்கி ஸ்வைப் செய்து பிடிக்கவும்"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"அனைத்து ஆப்ஸையும் பார்க்க, உங்கள் கீபோர்டில் உள்ள ஆக்ஷன் பட்டனை அழுத்தவும்"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"அர்த்தம் புரியாதபடி திருத்தப்பட்டது"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"பார்ப்பதற்கு அன்லாக் செய்யவும்"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"குறியீட்டைப் பார்க்க அன்லாக் செய்யவும்"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"சூழல் சார்ந்த கல்வி"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"பின்செல்ல, உங்கள் டச்பேடைப் பயன்படுத்துங்கள்"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"மூன்று விரல்களால் இடது அல்லது வலதுபுறம் ஸ்வைப் செய்யவும். சைகைகள் குறித்து மேலும் அறிய தட்டவும்."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"தெரியவில்லை"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"அனைத்துக் கட்டங்களையும் மீட்டமைக்கவா?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"விரைவு அமைப்புகளின் கட்டங்கள் அனைத்தும் சாதனத்தின் அசல் அமைப்புகளுக்கு மீட்டமைக்கப்படும்"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-te/strings.xml b/packages/SystemUI/res/values-te/strings.xml
index 2042ead..b466519 100644
--- a/packages/SystemUI/res/values-te/strings.xml
+++ b/packages/SystemUI/res/values-te/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g>కి కనెక్ట్ చేయబడింది."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"గ్రూప్‌ను విస్తరించండి."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"గ్రూప్‌కి పరికరాన్ని జోడించండి."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"గ్రూప్ నుండి పరికరాన్ని తీసివేయండి."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"యాప్‌ను తెరవండి."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"కనెక్ట్ చేయబడలేదు."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"రోమింగ్"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ఇన్‌పుట్"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"వినికిడి పరికరాలు"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"ఆన్ చేస్తోంది…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"దీనిని టాప్ యాప్ కంట్రోల్ చేస్తోంది కనుక బ్రైట్‌నెస్‌ను సర్దుబాటు చేయడం సాధ్యం కాదు"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"ఆటో-రొటేట్‌"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"స్క్రీన్ ఆటో-రొటేట్‌"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"లొకేషన్"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"పరిసరాలు"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ఎడమ వైపునకు"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"కుడి వైపునకు"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ఎడమ, కుడి అని వేరు చేయబడిన కంట్రోల్స్‌కు విస్తరించండి"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"యూనిఫైడ్ కంట్రోల్‌కు కుదించండి"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"పరిసరాలను మ్యూట్ చేయండి"</string>
@@ -1001,6 +1004,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> స్థానానికి జోడించండి"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ప్రస్తుత పొజిషన్ చెల్లదు."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"స్థానం <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"టైల్ జోడించబడింది"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"టైల్ తీసివేయబడింది"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"శీఘ్ర సెట్టింగ్‌ల ఎడిటర్."</string>
@@ -1571,4 +1576,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"తెలియదు"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"టైల్స్ అన్ని రీసెట్ చేయాలా?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"అన్ని క్విక్ సెట్టింగ్‌ల టైల్స్, పరికరం తాలూకు ఒరిజినల్ సెట్టింగ్‌లకు రీసెట్ చేయబడతాయి"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-th/strings.xml b/packages/SystemUI/res/values-th/strings.xml
index 9ac9d01b..e816c04 100644
--- a/packages/SystemUI/res/values-th/strings.xml
+++ b/packages/SystemUI/res/values-th/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"เชื่อมต่อกับ <xliff:g id="BLUETOOTH">%s</xliff:g> แล้ว"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"เชื่อมต่อกับ <xliff:g id="CAST">%s</xliff:g>"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"ขยายกลุ่ม"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"เพิ่มอุปกรณ์ลงในกลุ่ม"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"นำอุปกรณ์ออกจากกลุ่ม"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"เปิดแอปพลิเคชัน"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"ไม่ได้เชื่อมต่อ"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"โรมมิ่ง"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"อินพุต"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"เครื่องช่วยฟัง"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"กำลังเปิด..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"ปรับความสว่างไม่ได้เนื่องจากควบคุมโดยแอปที่อยู่ด้านบน"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"หมุนอัตโนมัติ"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"หมุนหน้าจออัตโนมัติ"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"ตำแหน่ง"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"เสียงแวดล้อม"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"ซ้าย"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"ขวา"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"ขยายเป็นการควบคุมที่แยกด้านซ้ายและขวา"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"ยุบเป็นการควบคุมแบบรวม"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"ปิดเสียงแวดล้อม"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"แสดงไอคอนการแจ้งเตือนลำดับความสำคัญต่ำ"</string>
     <string name="other" msgid="429768510980739978">"อื่นๆ"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"สลับขนาดของการ์ด"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"นำชิ้นส่วนออก"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"เพิ่มการ์ดไปยังตำแหน่งสุดท้าย"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"ย้ายชิ้นส่วน"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"เพิ่มไปยังตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"ตำแหน่งไม่ถูกต้อง"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"ตำแหน่ง <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"เพิ่มชิ้นส่วนแล้ว"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"นำชิ้นส่วนออกแล้ว"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"ตัวแก้ไขการตั้งค่าด่วน"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"หากต้องการดูแอปล่าสุด ให้ใช้ 3 นิ้วปัดขึ้นแล้วค้างไว้บนทัชแพด"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"หากต้องการดูแอปทั้งหมด ให้กดปุ่มดำเนินการบนแป้นพิมพ์"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"ปกปิดไว้"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"ปลดล็อกเพื่อดู"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"ปลดล็อกเพื่อดูรหัส"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"การศึกษาตามบริบท"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"ใช้ทัชแพดเพื่อย้อนกลับ"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"ใช้ 3 นิ้วปัดไปทางซ้ายหรือขวา แตะเพื่อดูข้อมูลเพิ่มเติมเกี่ยวกับท่าทางสัมผัสต่างๆ"</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"ไม่ทราบ"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"รีเซ็ตการ์ดทั้งหมดใช่ไหม"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"การ์ดการตั้งค่าด่วนทั้งหมดจะรีเซ็ตเป็นการตั้งค่าเดิมของอุปกรณ์"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tl/strings.xml b/packages/SystemUI/res/values-tl/strings.xml
index 516386b..d996218 100644
--- a/packages/SystemUI/res/values-tl/strings.xml
+++ b/packages/SystemUI/res/values-tl/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Nakakonekta sa <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Nakakonekta sa <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"I-expand ang grupo."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Idagdag ang device sa grupo."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Alisin ang device sa grupo."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Buksan ang application."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Hindi nakakonekta."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Roaming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Input"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Mga hearing aid"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Ino-on…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Hindi ma-adjust ang liwanag dahil kinokontrol ito ng nangingibabaw na app"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"I-auto rotate"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Awtomatikong i-rotate ang screen"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Lokasyon"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Paligid"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kaliwa"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Kanan"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"I-expand sa kaliwa at kanang magkahiwalay na mga kontrol"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"I-collapse sa pinag-isang kontrol"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"I-mute ang paligid"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Idagdag sa posisyong <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Invalid ang posisyon."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Posisyon <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Idinagdag ang tile"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Inalis ang tile"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Editor ng Mga mabilisang setting."</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Hindi Alam"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"I-reset ang lahat ng tile?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Magre-reset sa mga orihinal na setting ng device ang lahat ng tile ng Mga Mabilisang Setting"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-tr/strings.xml b/packages/SystemUI/res/values-tr/strings.xml
index b643203..9d78941 100644
--- a/packages/SystemUI/res/values-tr/strings.xml
+++ b/packages/SystemUI/res/values-tr/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> ile bağlı."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> bağlantısı kuruldu."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Grubu genişlet."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Cihazı gruba ekle."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Cihazı gruptan kaldır."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Uygulama aç."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Bağlanmadı."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Dolaşım"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Giriş"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"İşitme cihazları"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Açılıyor…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Parlaklık ayarlanamıyor, çünkü bu özellik en üstteki uygulama tarafından kontrol ediliyor"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Otomatik döndür"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranı otomatik döndür"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Konum"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Çevredeki sesler"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Sol"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Sağ"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Sol ve sağ kontrolleri ayırarak genişlet"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Kontrolleri birleştirerek daralt"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Çevredeki sesleri kapat"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Düşük öncelikli bildirim simgelerini göster"</string>
     <string name="other" msgid="429768510980739978">"Diğer"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"kutu boyutunu değiştir"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"Kutuyu kaldırmak için"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"kutuyu son konuma ekleyin"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Kutuyu taşı"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"<xliff:g id="POSITION">%1$d</xliff:g> konumuna ekle"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Konum geçersiz."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Konum: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Kutu eklendi"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Kutu kaldırıldı"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Hızlı ayar düzenleyicisi."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Son uygulamaları görüntülemek için dokunmatik alanda üç parmağınızla yukarı kaydırıp basılı tutun"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Tüm uygulamalarınızı görüntülemek için klavyenizdeki eylem tuşuna basın"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Çıkartıldı"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Görüntülemek için kilidi açın"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Kodu görüntülemek için kilidi açın"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Bağlama dayalı eğitim"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Geri dönmek için dokunmatik alanınızı kullanın"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Üç parmağınızla sola veya sağa kaydırın. Daha fazla hareket öğrenmek için dokunun."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Bilinmiyor"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Tüm ayar kutuları sıfırlansın mı?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Tüm Hızlı Ayarlar kutuları cihazın özgün ayarlarına sıfırlanır"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uk/strings.xml b/packages/SystemUI/res/values-uk/strings.xml
index db3c02d..97e5bb7 100644
--- a/packages/SystemUI/res/values-uk/strings.xml
+++ b/packages/SystemUI/res/values-uk/strings.xml
@@ -247,15 +247,13 @@
     <string name="accessibility_bluetooth_device_settings_gear" msgid="3314916468105272540">"Натисніть, щоб змінити налаштування пристрою"</string>
     <string name="accessibility_bluetooth_device_settings_gear_with_name" msgid="114373701123165491">"<xliff:g id="DEVICE_NAME">%s</xliff:g>. Змінити налаштування пристрою"</string>
     <string name="accessibility_bluetooth_device_settings_see_all" msgid="5260390270128256620">"Переглянути всі пристрої"</string>
-    <string name="accessibility_bluetooth_device_settings_pair_new_device" msgid="7988547106800504256">"Підключити новий пристрій"</string>
+    <string name="accessibility_bluetooth_device_settings_pair_new_device" msgid="7988547106800504256">"Зв’язати новий пристрій"</string>
     <string name="accessibility_battery_unknown" msgid="1807789554617976440">"Відсоток заряду акумулятора невідомий."</string>
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Підключено до <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Під’єднано до пристрою <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Розгорнути групу"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Додати пристрій у групу."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Вилучити пристрій із групи."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Відкрити додаток"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Не з’єднано."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Роумінг"</string>
@@ -308,7 +306,7 @@
     <string name="quick_settings_bluetooth_label" msgid="7018763367142041481">"Bluetooth"</string>
     <string name="quick_settings_bluetooth_detail_empty_text" msgid="5760239584390514322">"Немає спарених пристроїв"</string>
     <string name="quick_settings_bluetooth_tile_subtitle" msgid="212752719010829550">"Натисніть, щоб під’єднати або від’єднати пристрій"</string>
-    <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Підключити новий пристрій"</string>
+    <string name="pair_new_bluetooth_devices" msgid="4601767620843349645">"Зв’язати новий пристрій"</string>
     <string name="see_all_bluetooth_devices" msgid="1761596816620200433">"Показати всі"</string>
     <string name="turn_on_bluetooth" msgid="5681370462180289071">"Увімкнути Bluetooth"</string>
     <string name="quick_settings_bluetooth_device_connected" msgid="7884777006729260996">"Підключено"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Джерело сигналу"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Слухові апарати"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Увімкнення…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Не вдається змінити яскравість, оскільки нею керує основний додаток"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Автообертання"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Автоматично обертати екран"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Геодані"</string>
@@ -418,7 +415,7 @@
     <string name="quick_settings_hearing_devices_connected" msgid="6519069502397037781">"Під’єднано"</string>
     <string name="quick_settings_hearing_devices_disconnected" msgid="8907061223998176187">"Від’єднано"</string>
     <string name="quick_settings_hearing_devices_dialog_title" msgid="9004774017688484981">"Слухові апарати"</string>
-    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Підключити новий пристрій"</string>
+    <string name="quick_settings_pair_hearing_devices" msgid="5987105102207447322">"Зв’язати новий пристрій"</string>
     <string name="accessibility_hearing_device_pair_new_device" msgid="8440082580186130090">"Натисніть, щоб підключити новий пристрій"</string>
     <string name="hearing_devices_presets_error" msgid="350363093458408536">"Не вдалось оновити набір налаштувань"</string>
     <string name="hearing_devices_preset_label" msgid="7878267405046232358">"Набір налаштувань"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Звуки оточення"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Ліворуч"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Праворуч"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Розгорнути в окремі елементи керування ліворуч і праворуч"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Згорнути в єдиний елемент керування"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Вимкнути звуки оточення"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Показувати значки сповіщень із низьким пріоритетом"</string>
     <string name="other" msgid="429768510980739978">"Інше"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"змінити розмір плитки"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"вилучити опцію"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"додати панель на останню позицію"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Перемістити опцію"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Додати на позицію <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Позиція недійсна."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Позиція <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Опцію додано"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Опцію вилучено"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Редактор швидких налаштувань."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Щоб переглянути останні додатки, проведіть трьома пальцями вгору по сенсорній панелі й утримуйте їх"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Щоб переглянути всі додатки, натисніть клавішу дії на клавіатурі"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Замасковано"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Розблокуйте, щоб переглянути"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Розблокуйте, щоб переглянути код"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Контекстне навчання"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Щоб повернутися, використовуйте сенсорну панель"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Проведіть трьома пальцями вліво чи вправо. Натисніть, щоб дізнатися про інші жести."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Невідомо"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Скинути всі панелі?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Усі панелі швидких налаштувань буде скинуто до стандартних налаштувань пристрою"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-ur/strings.xml b/packages/SystemUI/res/values-ur/strings.xml
index ffc3f5e..41ba6b2 100644
--- a/packages/SystemUI/res/values-ur/strings.xml
+++ b/packages/SystemUI/res/values-ur/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"<xliff:g id="BLUETOOTH">%s</xliff:g> سے منسلک ہیں۔"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"<xliff:g id="CAST">%s</xliff:g> سے منسلک ہے۔"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"گروپ کو پھیلائیں۔"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"آلہ کو گروپ شامل کریں۔"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"آلہ کو گروپ سے ہٹائیں"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"ایپلیکیشن کھولیں۔"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"مربوط نہیں ہے۔"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"رومنگ"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"ان پٹ"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"سماعتی آلات"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"آن ہو رہا ہے…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"چمک کو ایڈجسٹ نہیں کیا جا سکتا کیونکہ اسے سرفہرست ایپ کے ذریعے کنٹرول کیا جا رہا ہے"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"خود کار طور پر گھمائیں"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"اسکرین کو خود کار طور پر گھمائیں"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"مقام"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"اطراف"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"دائیں"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"بائیں"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"بائیں اور دائیں علیحدہ کردہ کنٹرولز کو پھیلائیں"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"یونیفائیڈ کنٹرول کیلئے سکیڑیں"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"اطراف کو خاموش کریں"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g> میں شامل کریں"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"پوزیشن غلط ہے۔"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"پوزیشن <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"ٹائل کو شامل کیا گیا"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"ٹائل کو ہٹا دیا گیا"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"فوری ترتیبات کا ایڈیٹر۔"</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"نامعلوم"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"سبھی ٹائلز ری سیٹ کریں؟"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"سبھی فوری ترتیبات کی ٹائلز آلہ کی اصل ترتیبات پر ری سیٹ ہو جائیں گی"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>، <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-uz/strings.xml b/packages/SystemUI/res/values-uz/strings.xml
index e325cf3..f713ddc 100644
--- a/packages/SystemUI/res/values-uz/strings.xml
+++ b/packages/SystemUI/res/values-uz/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Ulangan: <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Bunga ulangan: <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Guruhni yoying."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Qurilmani guruhga kiritish."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Qurilmani guruhdan olib tashlash."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Ilovani oching."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Ulanmagan."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Rouming"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Kirish"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Eshitish moslamalari"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Yoqilmoqda…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Yorqinlikni sozlash imkonsiz, chunki tepadago ilova tomonidan boshqariladi"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Avto-burilish"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Ekranning avtomatik burilishi"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Joylashuv"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Atrof-muhit"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Chap"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Oʻng"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Chap va oʻngga ajratilgan boshqaruv elementlariga yoyish"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Yagona boshqaruvga yigʻish"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Atrof-muhitni ovozsiz qilish"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Muhim boʻlmagan bildirishnoma ikonkalarini koʻrsatish"</string>
     <string name="other" msgid="429768510980739978">"Boshqa"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"katak oʻlchamini almashtirish"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"katakchani olib tashlash"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"kartochkani oxirgi oʻringa qoʻshish"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Katakchani boshqa joyga olish"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Bu joyga kiritish: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Pozitsiya yaroqsiz."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Joylashuv: <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Katakcha kiritildi"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Katakcha olib tashlandi"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Tezkor sozlamalar muharriri"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Oxirgi ilovalarni koʻrish uchun sensorli panelda uchta barmoq bilan tepaga surib, bosib turing"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Barcha ishoralarni koʻrish uchun klaviaturadagi amal tugmasini bosing"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Chiqarildi"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Koʻrish uchun qulfdan chiqaring"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Kodni koʻrish uchun qulfdan chiqaring"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Kontekstual taʼlim"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Sensorli panel orqali orqaga qaytish"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Uchta barmoq bilan chapga yoki oʻngga suring. Boshqa ishoralar bilan tanishish uchun bosing."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Noaniq"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Barcha katakchalar asliga qaytarilsinmi?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Barcha Tezkor sozlamalar katakchalari qurilmaning asl sozlamalariga qaytariladi"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-vi/strings.xml b/packages/SystemUI/res/values-vi/strings.xml
index f64f084..2f266a7 100644
--- a/packages/SystemUI/res/values-vi/strings.xml
+++ b/packages/SystemUI/res/values-vi/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Đã kết nối với <xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Đã kết nối với <xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Mở rộng nhóm."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Thêm thiết bị vào nhóm."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Xoá thiết bị khỏi nhóm."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Mở ứng dụng."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Chưa được kết nối."</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Chuyển vùng"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Thiết bị đầu vào"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Thiết bị trợ thính"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Đang bật…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Không điều chỉnh được độ sáng do ứng dụng ở trên cùng đang điều khiển độ sáng"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Tự động xoay"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Tự động xoay màn hình"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Vị trí"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Âm lượng xung quanh"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Trái"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Phải"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Mở rộng thành các nút điều khiển tách biệt bên trái và bên phải"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Thu gọn thành nút điều khiển hợp nhất"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Tắt tiếng xung quanh"</string>
@@ -586,7 +589,7 @@
     <string name="media_projection_entry_cast_permission_dialog_option_text_single_app" msgid="6073353940838561981">"Truyền một ứng dụng"</string>
     <string name="media_projection_entry_cast_permission_dialog_option_text_entire_screen" msgid="8389508187954155307">"Truyền toàn bộ màn hình"</string>
     <string name="media_projection_entry_cast_permission_dialog_warning_entire_screen" msgid="4040447861037324017">"Khi bạn truyền toàn bộ màn hình thì người khác sẽ thấy được mọi nội dung trên màn hình của bạn. Vì vậy, hãy thận trọng đối với những thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string>
-    <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Khi bạn truyền một ứng dụng, thì người khác sẽ thấy được mọi nội dung xuất hiện hoặc phát trên ứng dụng đó. Vì vậy, hãy thận trọng đối với những thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string>
+    <string name="media_projection_entry_cast_permission_dialog_warning_single_app" msgid="7487834861348460736">"Khi bạn truyền một ứng dụng, mọi nội dung xuất hiện hoặc phát trên ứng dụng đó đều hiển thị trên thiết bị được truyền tới. Vì vậy, hãy thận trọng đối với những thông tin như mật khẩu, thông tin thanh toán, tin nhắn, ảnh, âm thanh và video."</string>
     <string name="media_projection_entry_cast_permission_dialog_continue_entire_screen" msgid="3261124185304676483">"Màn hình truyền"</string>
     <string name="media_projection_entry_cast_app_selector_title" msgid="6323062146661922387">"Chọn ứng dụng để truyền"</string>
     <string name="media_projection_entry_generic_permission_dialog_title" msgid="4519802931547483628">"Bắt đầu chia sẻ?"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Hiển thị biểu tượng thông báo có mức ưu tiên thấp"</string>
     <string name="other" msgid="429768510980739978">"Khác"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"bật hoặc tắt kích thước của ô"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"xóa ô"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"thêm ô vào vị trí cuối cùng"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Di chuyển ô"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Thêm vào vị trí <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Vị trí không hợp lệ."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Vị trí <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Đã thêm thẻ thông tin"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Đã xóa thẻ thông tin"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Trình chỉnh sửa cài đặt nhanh."</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Để xem các ứng dụng gần đây, hãy dùng 3 ngón tay vuốt lên và giữ trên bàn di chuột"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Để xem tất cả ứng dụng của bạn, hãy nhấn phím hành động trên bàn phím"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Bị loại bỏ"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Mở khoá để xem"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Mở khoá để xem mã"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Hướng dẫn theo bối cảnh"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Dùng bàn di chuột để quay lại"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Dùng 3 ngón tay vuốt sang trái hoặc sang phải. Hãy nhấn để tìm hiểu các cử chỉ khác."</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Không xác định"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Đặt lại mọi ô?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Mọi ô Cài đặt nhanh sẽ được đặt lại về chế độ cài đặt ban đầu của thiết bị"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rCN/strings.xml b/packages/SystemUI/res/values-zh-rCN/strings.xml
index a355a67..480debc 100644
--- a/packages/SystemUI/res/values-zh-rCN/strings.xml
+++ b/packages/SystemUI/res/values-zh-rCN/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已连接到<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"已连接到 <xliff:g id="CAST">%s</xliff:g>。"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"展开群组。"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"将设备添加到群组。"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"从群组中移除设备。"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"打开应用。"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"未连接。"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"漫游"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"输入"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"助听器"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"正在开启…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"亮度无法调整,因为它正在被顶层应用控制"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自动屏幕旋转"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自动旋转屏幕"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"位置信息"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"周围声音"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"左侧"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"右侧"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"展开为左侧和右侧的单独控件"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"收起为统一控件"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"将周围声音静音"</string>
@@ -991,8 +994,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"显示低优先级的通知图标"</string>
     <string name="other" msgid="429768510980739978">"其他"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"切换功能块大小"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"移除功能块"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"将功能块添加到最后一个位置"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"移动功能块"</string>
@@ -1001,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"添加到位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"位置无效。"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"已添加功能块"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"已移除功能块"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快捷设置编辑器。"</string>
@@ -1545,10 +1549,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"如要查看最近用过的应用,请用三根手指在触控板上向上滑动并按住"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"如要查看所有应用,请按下键盘上的快捷操作按键"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"已隐去"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"解锁即可查看"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"解锁即可查看验证码"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"内容相关指导"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"使用触控板返回"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"用三根手指向左或向右滑动。点按即可了解更多手势。"</string>
@@ -1571,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"未知"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"要重置所有功能块吗?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"所有“快捷设置”功能块都将重置为设备的原始设置"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>,<xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rHK/strings.xml b/packages/SystemUI/res/values-zh-rHK/strings.xml
index c5a81fb2..bc9e0c5 100644
--- a/packages/SystemUI/res/values-zh-rHK/strings.xml
+++ b/packages/SystemUI/res/values-zh-rHK/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"已連接至 <xliff:g id="CAST">%s</xliff:g>。"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"展開群組。"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"將裝置新增至群組。"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"從群組移除裝置。"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"開啟應用程式。"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"未連線。"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"漫遊"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"輸入"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"助聽器"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"正在開啟…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"無法調整亮度,因為目前是由上層應用程式控制亮度"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動旋轉"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自動旋轉螢幕"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"位置"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"環境聲音"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"左"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"右"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"打開就可以分開左右控制"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"收埋就可以統一控制"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"環境聲音靜音"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"加去位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"位置冇效。"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"加咗圖塊"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"移除咗圖塊"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快速設定編輯工具。"</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"不明"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"要重設所有圖塊嗎?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"所有「快速設定」圖塊將重設為裝置的原始設定"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>,<xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zh-rTW/strings.xml b/packages/SystemUI/res/values-zh-rTW/strings.xml
index 24a15a1..02fda5a 100644
--- a/packages/SystemUI/res/values-zh-rTW/strings.xml
+++ b/packages/SystemUI/res/values-zh-rTW/strings.xml
@@ -252,10 +252,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"已連線至<xliff:g id="BLUETOOTH">%s</xliff:g>。"</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"已連線至 <xliff:g id="CAST">%s</xliff:g>。"</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"展開群組。"</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"將裝置加入群組。"</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"從群組中移除裝置。"</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"開啟應用程式。"</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"尚未連線。"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"漫遊"</string>
@@ -333,8 +331,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"輸入"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"助聽器"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"開啟中…"</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"無法調整亮度,因為目前是由上層應用程式控制亮度"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"自動旋轉"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"自動旋轉螢幕"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"定位"</string>
@@ -426,6 +423,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"環境"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"左"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"右"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"展開為左右獨立控制選項"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"收合為統合控制選項"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"將環境靜音"</string>
@@ -1000,6 +1003,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"新增到位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"位置無效。"</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"位置 <xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"已新增設定方塊"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"已移除設定方塊"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"快速設定編輯器。"</string>
@@ -1568,4 +1573,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"不明"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"要重設所有設定方塊嗎?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"所有快速設定方塊都會恢復裝置的原始設定"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>、<xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values-zu/strings.xml b/packages/SystemUI/res/values-zu/strings.xml
index 9188648..886cbdf 100644
--- a/packages/SystemUI/res/values-zu/strings.xml
+++ b/packages/SystemUI/res/values-zu/strings.xml
@@ -254,10 +254,8 @@
     <string name="accessibility_bluetooth_name" msgid="7300973230214067678">"Xhuma ku-<xliff:g id="BLUETOOTH">%s</xliff:g>."</string>
     <string name="accessibility_cast_name" msgid="7344437925388773685">"Ixhumeke ku-<xliff:g id="CAST">%s</xliff:g>."</string>
     <string name="accessibility_expand_group" msgid="521237935987978624">"Nweba iqembu."</string>
-    <!-- no translation found for accessibility_add_device_to_group (5446422960697860806) -->
-    <skip />
-    <!-- no translation found for accessibility_remove_device_from_group (3114694270949142228) -->
-    <skip />
+    <string name="accessibility_add_device_to_group" msgid="5446422960697860806">"Faka idivayisi eqenjini."</string>
+    <string name="accessibility_remove_device_from_group" msgid="3114694270949142228">"Susa idivayisi eqenjini."</string>
     <string name="accessibility_open_application" msgid="1749126077501259712">"Vula i-application."</string>
     <string name="accessibility_not_connected" msgid="4061305616351042142">"Akuxhunyiwe"</string>
     <string name="data_connection_roaming" msgid="375650836665414797">"Iyazulazula"</string>
@@ -335,8 +333,7 @@
     <string name="quick_settings_bluetooth_secondary_label_input" msgid="3887552721233148132">"Okokufaka"</string>
     <string name="quick_settings_bluetooth_secondary_label_hearing_aids" msgid="5553051568867097111">"Imishini yendlebe"</string>
     <string name="quick_settings_bluetooth_secondary_label_transient" msgid="3882884317600669650">"Iyavula..."</string>
-    <!-- no translation found for quick_settings_brightness_unable_adjust_msg (4124028416057617517) -->
-    <skip />
+    <string name="quick_settings_brightness_unable_adjust_msg" msgid="4124028416057617517">"Ayikwazi ukulungisa ukukhanya ngoba ilawulwa yi-app ephezulu"</string>
     <string name="quick_settings_rotation_unlocked_label" msgid="2359922767950346112">"Ukuphenduka okuzenzakalelayo"</string>
     <string name="accessibility_quick_settings_rotation" msgid="4800050198392260738">"Phendula iskrini ngokuzenzakalela"</string>
     <string name="quick_settings_location_label" msgid="2621868789013389163">"Indawo"</string>
@@ -428,6 +425,12 @@
     <string name="hearing_devices_ambient_label" msgid="629440938614895797">"Izindawo ezizungezile"</string>
     <string name="hearing_devices_ambient_control_left" msgid="3586965448230412600">"Kwesokunxele"</string>
     <string name="hearing_devices_ambient_control_right" msgid="6192137602448918383">"Kwesokudla"</string>
+    <!-- no translation found for hearing_devices_ambient_control_description (3663947879732939509) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_left_description (4440988622896213511) -->
+    <skip />
+    <!-- no translation found for hearing_devices_ambient_control_right_description (2230461103493378003) -->
+    <skip />
     <string name="hearing_devices_ambient_expand_controls" msgid="2131816068187709200">"Nwebela ezilawulini ezihlukanisiwe zakwesokunxele nakwesokudla"</string>
     <string name="hearing_devices_ambient_collapse_controls" msgid="2261097656446201581">"Goqa ezilawulini ezihlanganisiwe"</string>
     <string name="hearing_devices_ambient_mute" msgid="1836882837647429416">"Thulisa izindawo ezizungezile"</string>
@@ -993,8 +996,7 @@
   </string-array>
     <string name="tuner_low_priority" msgid="8412666814123009820">"Bonisa izithonjana zesaziso zokubaluleka okuncane"</string>
     <string name="other" msgid="429768510980739978">"Okunye"</string>
-    <!-- no translation found for accessibility_qs_edit_toggle_tile_size_action (1485194410119733586) -->
-    <skip />
+    <string name="accessibility_qs_edit_toggle_tile_size_action" msgid="1485194410119733586">"guqula usayizi wethayela"</string>
     <string name="accessibility_qs_edit_remove_tile_action" msgid="775511891457193480">"susa ithayela"</string>
     <string name="accessibility_qs_edit_tile_add_action" msgid="8311378984458545661">"faka ithayela endaweni yokugcina"</string>
     <string name="accessibility_qs_edit_tile_start_move" msgid="2009373939914517817">"Hambisa ithayela"</string>
@@ -1003,6 +1005,8 @@
     <string name="accessibility_qs_edit_tile_add_to_position" msgid="9029163095148274690">"Engeza kusikhundla se-<xliff:g id="POSITION">%1$d</xliff:g>"</string>
     <string name="accessibilit_qs_edit_tile_add_move_invalid_position" msgid="2858467994472624487">"Indawo ayivumelekile."</string>
     <string name="accessibility_qs_edit_position" msgid="4509277359815711830">"Isikhundla se-<xliff:g id="POSITION">%1$d</xliff:g>"</string>
+    <!-- no translation found for accessibility_qs_edit_tile_already_added (5900071201690226752) -->
+    <skip />
     <string name="accessibility_qs_edit_tile_added" msgid="9067146040380836334">"Ithayela lingeziwe"</string>
     <string name="accessibility_qs_edit_tile_removed" msgid="1175925632436612036">"Ithayela likhishiwe"</string>
     <string name="accessibility_desc_quick_settings_edit" msgid="741658939453595297">"Isihleli sezilungiselelo ezisheshayo."</string>
@@ -1547,10 +1551,8 @@
     <string name="overview_edu_toast_content" msgid="5797030644017804518">"Ukuze ubuke ama-app akamuva, swayiphela phezulu bese ubambe ngeminwe emithathu ephedini yokuthinta"</string>
     <string name="all_apps_edu_toast_content" msgid="8807496014667211562">"Ukuze ubuke wonke ama-app wakho, cindezela inkinobho yokufinyelela kukhibhodi yakho"</string>
     <string name="redacted_notification_single_line_title" msgid="212019960919261670">"Kwenziwe iredact"</string>
-    <!-- no translation found for public_notification_single_line_text (3576190291791654933) -->
-    <skip />
-    <!-- no translation found for redacted_otp_notification_single_line_text (5179964116354454118) -->
-    <skip />
+    <string name="public_notification_single_line_text" msgid="3576190291791654933">"Vula ukuze ubuke"</string>
+    <string name="redacted_otp_notification_single_line_text" msgid="5179964116354454118">"Vula ukuze ubone ikhodi"</string>
     <string name="contextual_education_dialog_title" msgid="4630392552837487324">"Imfundo yokuqukethwe"</string>
     <string name="back_edu_notification_title" msgid="5624780717751357278">"Sebenzisa iphedi yokuthinta ukuze ubuyele emuva"</string>
     <string name="back_edu_notification_content" msgid="2497557451540954068">"Swayiphela kwesokunxele noma kwesokudla usebenzisa iminwe emithathu. Thepha ukuze ufunde kabanzi ngokunyakazisa umzimba."</string>
@@ -1573,4 +1575,5 @@
     <string name="qs_edit_mode_category_unknown" msgid="509314252124053550">"Akwaziwa"</string>
     <string name="qs_edit_mode_reset_dialog_title" msgid="5344853290033761627">"Qala kabusha onke amathayela?"</string>
     <string name="qs_edit_mode_reset_dialog_content" msgid="7474773130622653653">"Ithayela Lamasethingi Asheshayo lizosetha kabusha libuyele kumasethingi okuqala edivayisi"</string>
+    <string name="volume_slider_disabled_message_template" msgid="1305088816797803460">"<xliff:g id="STREAM_NAME">%1$s</xliff:g>, <xliff:g id="DISABLED_MESSAGE">%2$s</xliff:g>"</string>
 </resources>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 4995858..78e719f 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -98,10 +98,6 @@
     TODO (b/293252410) - change this comment/resource when flag is enabled -->
     <integer name="small_land_lockscreen_quick_settings_max_rows">2</integer>
 
-    <!-- If the dp width of the available space is <= this value, potentially adjust the number
-         of media recommendation items-->
-    <integer name="default_qs_media_rec_width_dp">380</integer>
-
     <!-- The number of columns that the top level tiles span in the QuickSettings -->
 
     <!-- The default tiles to display in QuickSettings -->
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index 7c370d3..8342a9c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -1342,19 +1342,6 @@
     <dimen name="qs_media_session_collapsed_legacy_guideline">144dp</dimen>
     <dimen name="qs_media_session_collapsed_guideline">168dp</dimen>
 
-    <!-- Size of Smartspace media recommendations cards in the QSPanel carousel -->
-    <dimen name="qs_media_rec_default_width">380dp</dimen>
-    <dimen name="qs_media_rec_icon_top_margin">16dp</dimen>
-    <dimen name="qs_media_rec_album_icon_size">16dp</dimen>
-    <dimen name="qs_media_rec_album_size">88dp</dimen>
-    <dimen name="qs_media_rec_album_width">110dp</dimen>
-    <dimen name="qs_media_rec_album_height_expanded">108dp</dimen>
-    <dimen name="qs_media_rec_album_height_collapsed">77dp</dimen>
-    <dimen name="qs_media_rec_album_side_margin">16dp</dimen>
-    <dimen name="qs_media_rec_album_bottom_margin">8dp</dimen>
-    <dimen name="qs_media_rec_album_title_bottom_margin">22dp</dimen>
-    <dimen name="qs_media_rec_album_subtitle_height">12dp</dimen>
-
     <!-- Chipbar -->
     <!-- (Used for media tap-to-transfer chip for sender device and active unlock) -->
     <dimen name="chipbar_outer_padding">16dp</dimen>
@@ -2202,11 +2189,6 @@
     <dimen name="volume_dialog_background_square_corner_radius">12dp</dimen>
 
     <dimen name="volume_dialog_ringer_drawer_margin">@dimen/volume_dialog_buttons_margin</dimen>
-    <!--
-     (volume_dialog_slider_width - volume_dialog_button_size) / 2
-     This centers ringer drawer against the volume slider
-    -->
-    <dimen name="volume_dialog_ringer_drawer_diff_end_margin">6dp</dimen>
     <dimen name="volume_dialog_ringer_drawer_button_size">@dimen/volume_dialog_button_size</dimen>
     <dimen name="volume_dialog_ringer_drawer_button_icon_radius">10dp</dimen>
     <dimen name="volume_dialog_ringer_selected_button_background_radius">20dp</dimen>
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 43ea2c3..c06c17a 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1042,6 +1042,8 @@
     <string name="hearing_devices_tools_label">Tools</string>
     <!-- QuickSettings: Tool name for hearing devices dialog related tools [CHAR LIMIT=40] [BACKUP_MESSAGE_ID=8916875614623730005]-->
     <string name="quick_settings_hearing_devices_live_caption_title">Live Caption</string>
+    <!-- QuickSettings: Label for button to go to hearing devices settings page [CHAR_LIMIT=20] -->
+    <string name="hearing_devices_settings_button">Settings</string>
 
     <!-- QuickSettings: Notes tile. The label of a quick settings tile for launching the default notes taking app. [CHAR LIMIT=NONE] -->
     <string name="quick_settings_notes_label">Note</string>
@@ -2599,6 +2601,9 @@
     <!-- Accessibility description indicating the currently selected tile's position. Only used for tiles that are currently in use [CHAR LIMIT=NONE] -->
     <string name="accessibility_qs_edit_position">Position <xliff:g id="position" example="5">%1$d</xliff:g></string>
 
+    <!-- Accessibility description indicating the currently selected tile is already added [CHAR LIMIT=NONE] -->
+    <string name="accessibility_qs_edit_tile_already_added">Tile already added</string>
+
     <!-- Accessibility announcement after a tile has been added [CHAR LIMIT=NONE] -->
     <string name="accessibility_qs_edit_tile_added">Tile added</string>
 
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 4431dda..7895ff7 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -895,57 +895,6 @@
         <item name="android:textColor">@android:color/system_on_primary_dark</item>
     </style>
 
-    <style name="MediaPlayer.Recommendation"/>
-
-    <style name="MediaPlayer.Recommendation.Header">
-        <item name="android:layout_width">wrap_content</item>
-        <item name="android:layout_height">wrap_content</item>
-        <item name="android:layout_marginTop">@dimen/qs_media_padding</item>
-        <item name="android:layout_marginStart">@dimen/qs_media_padding</item>
-        <item name="android:fontFamily">=@*android:string/config_headlineFontFamilyMedium</item>
-        <item name="android:singleLine">true</item>
-        <item name="android:textSize">14sp</item>
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
-    </style>
-
-    <style name="MediaPlayer.Recommendation.AlbumContainer">
-        <item name="android:layout_width">@dimen/qs_media_rec_album_size</item>
-        <item name="android:layout_height">@dimen/qs_media_rec_album_size</item>
-        <item name="android:background">@drawable/qs_media_light_source</item>
-        <item name="android:layout_marginTop">@dimen/qs_media_padding</item>
-        <item name="android:layout_marginBottom">@dimen/qs_media_rec_album_bottom_margin</item>
-    </style>
-
-    <style name="MediaPlayer.Recommendation.AlbumContainer.Updated">
-        <item name="android:layout_width">@dimen/qs_media_rec_album_width</item>
-        <item name="android:minWidth">@dimen/qs_media_rec_album_width</item>
-        <item name="android:minHeight">@dimen/qs_media_rec_album_height_collapsed</item>
-        <item name="android:background">@drawable/qs_media_light_source</item>
-        <item name="android:layout_marginTop">@dimen/qs_media_info_spacing</item>
-    </style>
-
-    <style name="MediaPlayer.Recommendation.Album">
-        <item name="android:backgroundTint">@color/media_player_album_bg</item>
-    </style>
-
-    <style name="MediaPlayer.Recommendation.Text">
-        <item name="android:layout_width">@dimen/qs_media_rec_album_size</item>
-        <item name="android:layout_height">wrap_content</item>
-        <item name="android:maxLines">1</item>
-        <item name="android:ellipsize">end</item>
-        <item name="android:textSize">14sp</item>
-        <item name="android:gravity">start</item>
-    </style>
-
-    <style name="MediaPlayer.Recommendation.Text.Title">
-        <item name="android:textColor">?android:attr/textColorPrimary</item>
-    </style>
-
-    <style name="MediaPlayer.Recommendation.Text.Subtitle">
-        <item name="android:textColor">?android:attr/textColorSecondary</item>
-    </style>
-
-
     <!-- Used to style charging animation AVD animation -->
     <style name="ChargingAnim" />
 
diff --git a/packages/SystemUI/res/xml/media_recommendations_collapsed.xml b/packages/SystemUI/res/xml/media_recommendations_collapsed.xml
deleted file mode 100644
index d3be3c7..0000000
--- a/packages/SystemUI/res/xml/media_recommendations_collapsed.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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
-  -->
-<ConstraintSet
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    >
-
-    <Constraint
-        android:id="@+id/sizing_view"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/qs_media_session_height_collapsed"
-        />
-
-    <Constraint
-        android:id="@+id/media_rec_title"
-        style="@style/MediaPlayer.Recommendation.Header"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"/>
-
-    <Constraint
-        android:id="@+id/media_cover1_container"
-        style="@style/MediaPlayer.Recommendation.AlbumContainer.Updated"
-        android:layout_height="@dimen/qs_media_rec_album_height_collapsed"
-        android:layout_marginEnd="@dimen/qs_media_info_spacing"
-        android:layout_marginStart="@dimen/qs_media_padding"
-        app:layout_constraintTop_toBottomOf="@+id/media_rec_title"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/media_cover2_container"/>
-
-
-    <Constraint
-        android:id="@+id/media_cover2_container"
-        style="@style/MediaPlayer.Recommendation.AlbumContainer.Updated"
-        android:layout_height="@dimen/qs_media_rec_album_height_collapsed"
-        android:layout_marginEnd="@dimen/qs_media_info_spacing"
-        app:layout_constraintTop_toBottomOf="@+id/media_rec_title"
-        app:layout_constraintStart_toEndOf="@id/media_cover1_container"
-        app:layout_constraintEnd_toStartOf="@id/media_cover3_container"/>
-
-    <Constraint
-        android:id="@+id/media_cover3_container"
-        style="@style/MediaPlayer.Recommendation.AlbumContainer.Updated"
-        android:layout_height="@dimen/qs_media_rec_album_height_collapsed"
-        android:layout_marginEnd="@dimen/qs_media_padding"
-        app:layout_constraintTop_toBottomOf="@+id/media_rec_title"
-        app:layout_constraintStart_toEndOf="@id/media_cover2_container"
-        app:layout_constraintEnd_toEndOf="parent"/>
-
-
-</ConstraintSet>
diff --git a/packages/SystemUI/res/xml/media_recommendations_expanded.xml b/packages/SystemUI/res/xml/media_recommendations_expanded.xml
deleted file mode 100644
index 88c7055..0000000
--- a/packages/SystemUI/res/xml/media_recommendations_expanded.xml
+++ /dev/null
@@ -1,71 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-  ~ 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
-  -->
-<ConstraintSet
-    xmlns:android="http://schemas.android.com/apk/res/android"
-    xmlns:app="http://schemas.android.com/apk/res-auto"
-    >
-
-    <Constraint
-        android:id="@+id/sizing_view"
-        android:layout_width="match_parent"
-        android:layout_height="@dimen/qs_media_session_height_expanded"
-        />
-
-    <Constraint
-        android:id="@+id/media_rec_title"
-        android:layout_width="wrap_content"
-        android:layout_height="wrap_content"
-        android:layout_marginTop="@dimen/qs_media_padding"
-        android:layout_marginStart="@dimen/qs_media_padding"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintTop_toTopOf="parent"
-        android:fontFamily="@*android:string/config_headlineFontFamilyMedium"
-        android:singleLine="true"
-        android:textSize="14sp"
-        android:textColor="@color/notification_primary_text_color"/>
-
-    <Constraint
-        android:id="@+id/media_cover1_container"
-        style="@style/MediaPlayer.Recommendation.AlbumContainer.Updated"
-        android:layout_height="@dimen/qs_media_rec_album_height_expanded"
-        android:layout_marginEnd="@dimen/qs_media_info_spacing"
-        android:layout_marginStart="@dimen/qs_media_padding"
-        app:layout_constraintTop_toBottomOf="@+id/media_rec_title"
-        app:layout_constraintStart_toStartOf="parent"
-        app:layout_constraintEnd_toStartOf="@id/media_cover2_container"/>
-
-
-    <Constraint
-        android:id="@+id/media_cover2_container"
-        style="@style/MediaPlayer.Recommendation.AlbumContainer.Updated"
-        android:layout_height="@dimen/qs_media_rec_album_height_expanded"
-        android:layout_marginEnd="@dimen/qs_media_info_spacing"
-        app:layout_constraintTop_toBottomOf="@+id/media_rec_title"
-        app:layout_constraintStart_toEndOf="@id/media_cover1_container"
-        app:layout_constraintEnd_toStartOf="@id/media_cover3_container"/>
-
-    <Constraint
-        android:id="@+id/media_cover3_container"
-        style="@style/MediaPlayer.Recommendation.AlbumContainer.Updated"
-        android:layout_height="@dimen/qs_media_rec_album_height_expanded"
-        android:layout_marginEnd="@dimen/qs_media_padding"
-        app:layout_constraintTop_toBottomOf="@+id/media_rec_title"
-        app:layout_constraintStart_toEndOf="@id/media_cover2_container"
-        app:layout_constraintEnd_toEndOf="parent"/>
-
-
-</ConstraintSet>
diff --git a/packages/SystemUI/shared/Android.bp b/packages/SystemUI/shared/Android.bp
index ae3a76e..8d7cab4 100644
--- a/packages/SystemUI/shared/Android.bp
+++ b/packages/SystemUI/shared/Android.bp
@@ -51,6 +51,7 @@
         ":wm_shell-shared-aidls",
     ],
     static_libs: [
+        "com.android.systemui.dagger-api",
         "BiometricsSharedLib",
         "PlatformAnimationLib",
         "PluginCoreLib",
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt
index a2b6e2c..f276a82 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/CombinedCondition.kt
@@ -41,7 +41,7 @@
 constructor(
     private val scope: CoroutineScope,
     private val conditions: Collection<Condition>,
-    @Evaluator.ConditionOperand private val operand: Int
+    @Evaluator.ConditionOperand private val operand: Int,
 ) : Condition(scope, null, false) {
 
     private var job: Job? = null
@@ -54,7 +54,7 @@
 
                 lazilyEvaluate(
                         conditions = groupedConditions.getOrDefault(true, emptyList()),
-                        filterUnknown = true
+                        filterUnknown = true,
                     )
                     .distinctUntilChanged()
                     .flatMapLatest { overriddenValue ->
@@ -62,7 +62,7 @@
                         if (overriddenValue == null) {
                             lazilyEvaluate(
                                 conditions = groupedConditions.getOrDefault(false, emptyList()),
-                                filterUnknown = false
+                                filterUnknown = false,
                             )
                         } else {
                             flowOf(overriddenValue)
@@ -188,7 +188,6 @@
         return startStrategy
     }
 
-    override fun getStartStrategy(): Int {
-        return _startStrategy
-    }
+    override val startStrategy: Int
+        get() = _startStrategy
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java
deleted file mode 100644
index 670feeb..0000000
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.java
+++ /dev/null
@@ -1,306 +0,0 @@
-/*
- * Copyright (C) 2022 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.shared.condition;
-
-import android.util.Log;
-
-import androidx.annotation.IntDef;
-import androidx.annotation.NonNull;
-import androidx.lifecycle.Lifecycle;
-import androidx.lifecycle.LifecycleEventObserver;
-import androidx.lifecycle.LifecycleOwner;
-
-import kotlinx.coroutines.CoroutineScope;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.ref.WeakReference;
-import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.List;
-
-/**
- * Base class for a condition that needs to be fulfilled in order for {@link Monitor} to inform
- * its callbacks.
- */
-public abstract class Condition {
-    private final String mTag = getClass().getSimpleName();
-
-    private final ArrayList<WeakReference<Callback>> mCallbacks = new ArrayList<>();
-    private final boolean mOverriding;
-    private final CoroutineScope mScope;
-    private Boolean mIsConditionMet;
-    private boolean mStarted = false;
-
-    /**
-     * By default, conditions have an initial value of false and are not overriding.
-     */
-    public Condition(CoroutineScope scope) {
-        this(scope, false, false);
-    }
-
-    /**
-     * Constructor for specifying initial state and overriding condition attribute.
-     *
-     * @param initialConditionMet Initial state of the condition.
-     * @param overriding          Whether this condition overrides others.
-     */
-    protected Condition(CoroutineScope scope, Boolean initialConditionMet, boolean overriding) {
-        mIsConditionMet = initialConditionMet;
-        mOverriding = overriding;
-        mScope = scope;
-    }
-
-    /**
-     * Starts monitoring the condition.
-     */
-    protected abstract void start();
-
-    /**
-     * Stops monitoring the condition.
-     */
-    protected abstract void stop();
-
-    /**
-     * Condition should be started as soon as there is an active subscription.
-     */
-    public static final int START_EAGERLY = 0;
-    /**
-     * Condition should be started lazily only if needed. But once started, it will not be cancelled
-     * unless there are no more active subscriptions.
-     */
-    public static final int START_LAZILY = 1;
-    /**
-     * Condition should be started lazily only if needed, and can be stopped when not needed. This
-     * should be used for conditions which are expensive to keep running.
-     */
-    public static final int START_WHEN_NEEDED = 2;
-
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({START_EAGERLY, START_LAZILY, START_WHEN_NEEDED})
-    @interface StartStrategy {
-    }
-
-    @StartStrategy
-    protected abstract int getStartStrategy();
-
-    /**
-     * Returns whether the current condition overrides
-     */
-    public boolean isOverridingCondition() {
-        return mOverriding;
-    }
-
-    /**
-     * Registers a callback to receive updates once started. This should be called before
-     * {@link #start()}. Also triggers the callback immediately if already started.
-     */
-    public void addCallback(@NonNull Callback callback) {
-        if (shouldLog()) Log.d(mTag, "adding callback");
-        mCallbacks.add(new WeakReference<>(callback));
-
-        if (mStarted) {
-            callback.onConditionChanged(this);
-            return;
-        }
-
-        start();
-        mStarted = true;
-    }
-
-    /**
-     * Removes the provided callback from further receiving updates.
-     */
-    public void removeCallback(@NonNull Callback callback) {
-        if (shouldLog()) Log.d(mTag, "removing callback");
-        final Iterator<WeakReference<Callback>> iterator = mCallbacks.iterator();
-        while (iterator.hasNext()) {
-            final Callback cb = iterator.next().get();
-            if (cb == null || cb == callback) {
-                iterator.remove();
-            }
-        }
-
-        if (!mCallbacks.isEmpty() || !mStarted) {
-            return;
-        }
-
-        stop();
-        mStarted = false;
-    }
-
-    /**
-     * Wrapper to {@link #addCallback(Callback)} when a lifecycle is in the resumed state
-     * and {@link #removeCallback(Callback)} when not resumed automatically.
-     */
-    public Callback observe(LifecycleOwner owner, Callback listener) {
-        return observe(owner.getLifecycle(), listener);
-    }
-
-    /**
-     * Wrapper to {@link #addCallback(Callback)} when a lifecycle is in the resumed state
-     * and {@link #removeCallback(Condition.Callback)} when not resumed automatically.
-     */
-    public Callback observe(Lifecycle lifecycle, Callback listener) {
-        lifecycle.addObserver((LifecycleEventObserver) (lifecycleOwner, event) -> {
-            if (event == Lifecycle.Event.ON_RESUME) {
-                addCallback(listener);
-            } else if (event == Lifecycle.Event.ON_PAUSE) {
-                removeCallback(listener);
-            }
-        });
-        return listener;
-    }
-
-    /**
-     * Updates the value for whether the condition has been fulfilled, and sends an update if the
-     * value changes and any callback is registered.
-     *
-     * @param isConditionMet True if the condition has been fulfilled. False otherwise.
-     */
-    protected void updateCondition(boolean isConditionMet) {
-        if (mIsConditionMet != null && mIsConditionMet == isConditionMet) {
-            return;
-        }
-
-        if (shouldLog()) Log.d(mTag, "updating condition to " + isConditionMet);
-        mIsConditionMet = isConditionMet;
-        sendUpdate();
-    }
-
-    /**
-     * Clears the set condition value. This is purposefully separate from
-     * {@link #updateCondition(boolean)} to avoid confusion around {@code null} values.
-     */
-    protected void clearCondition() {
-        if (mIsConditionMet == null) {
-            return;
-        }
-
-        if (shouldLog()) Log.d(mTag, "clearing condition");
-
-        mIsConditionMet = null;
-        sendUpdate();
-    }
-
-    private void sendUpdate() {
-        final Iterator<WeakReference<Callback>> iterator = mCallbacks.iterator();
-        while (iterator.hasNext()) {
-            final Callback cb = iterator.next().get();
-            if (cb == null) {
-                iterator.remove();
-            } else {
-                cb.onConditionChanged(this);
-            }
-        }
-    }
-
-    /**
-     * Returns whether the condition is set. This method should be consulted to understand the
-     * value of {@link #isConditionMet()}.
-     *
-     * @return {@code true} if value is present, {@code false} otherwise.
-     */
-    public boolean isConditionSet() {
-        return mIsConditionMet != null;
-    }
-
-    /**
-     * Returns whether the condition has been met. Note that this method will return {@code false}
-     * if the condition is not set as well.
-     */
-    public boolean isConditionMet() {
-        return Boolean.TRUE.equals(mIsConditionMet);
-    }
-
-    protected final boolean shouldLog() {
-        return Log.isLoggable(mTag, Log.DEBUG);
-    }
-
-    protected final String getTag() {
-        if (isOverridingCondition()) {
-            return mTag + "[OVRD]";
-        }
-
-        return mTag;
-    }
-
-    /**
-     * Returns the state of the condition.
-     * - "Invalid", condition hasn't been set / not monitored
-     * - "True", condition has been met
-     * - "False", condition has not been met
-     */
-    protected final String getState() {
-        if (!isConditionSet()) {
-            return "Invalid";
-        }
-        return isConditionMet() ? "True" : "False";
-    }
-
-    /**
-     * Creates a new condition which will only be true when both this condition and all the provided
-     * conditions are true.
-     */
-    public Condition and(@NonNull Collection<Condition> others) {
-        final List<Condition> conditions = new ArrayList<>();
-        conditions.add(this);
-        conditions.addAll(others);
-        return new CombinedCondition(mScope, conditions, Evaluator.OP_AND);
-    }
-
-    /**
-     * Creates a new condition which will only be true when both this condition and the provided
-     * condition is true.
-     */
-    public Condition and(@NonNull Condition... others) {
-        return and(Arrays.asList(others));
-    }
-
-    /**
-     * Creates a new condition which will only be true when either this condition or any of the
-     * provided conditions are true.
-     */
-    public Condition or(@NonNull Collection<Condition> others) {
-        final List<Condition> conditions = new ArrayList<>();
-        conditions.add(this);
-        conditions.addAll(others);
-        return new CombinedCondition(mScope, conditions, Evaluator.OP_OR);
-    }
-
-    /**
-     * Creates a new condition which will only be true when either this condition or the provided
-     * condition is true.
-     */
-    public Condition or(@NonNull Condition... others) {
-        return or(Arrays.asList(others));
-    }
-
-    /**
-     * Callback that receives updates about whether the condition has been fulfilled.
-     */
-    public interface Callback {
-        /**
-         * Called when the fulfillment of the condition changes.
-         *
-         * @param condition The condition in question.
-         */
-        void onConditionChanged(Condition condition);
-    }
-}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.kt
new file mode 100644
index 0000000..69236b4
--- /dev/null
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/Condition.kt
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.android.systemui.shared.condition
+
+import android.util.Log
+import androidx.annotation.IntDef
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.LifecycleEventObserver
+import androidx.lifecycle.LifecycleOwner
+import java.lang.ref.WeakReference
+import kotlinx.coroutines.CoroutineScope
+
+/**
+ * Base class for a condition that needs to be fulfilled in order for [Monitor] to inform its
+ * callbacks.
+ */
+abstract class Condition
+/**
+ * Constructor for specifying initial state and overriding condition attribute.
+ *
+ * @param initialConditionMet Initial state of the condition.
+ * @param overriding Whether this condition overrides others.
+ */
+@JvmOverloads
+protected constructor(
+    private val _scope: CoroutineScope,
+    private var _isConditionMet: Boolean? = false,
+    /** Returns whether the current condition overrides */
+    val isOverridingCondition: Boolean = false,
+) {
+    private val mTag: String = javaClass.simpleName
+
+    private val _callbacks = mutableListOf<WeakReference<Callback>>()
+    private var _started = false
+
+    /** Starts monitoring the condition. */
+    protected abstract fun start()
+
+    /** Stops monitoring the condition. */
+    protected abstract fun stop()
+
+    @Retention(AnnotationRetention.SOURCE)
+    @IntDef(START_EAGERLY, START_LAZILY, START_WHEN_NEEDED)
+    annotation class StartStrategy
+
+    @get:StartStrategy abstract val startStrategy: Int
+
+    /**
+     * Registers a callback to receive updates once started. This should be called before [.start].
+     * Also triggers the callback immediately if already started.
+     */
+    fun addCallback(callback: Callback) {
+        if (shouldLog()) Log.d(mTag, "adding callback")
+        _callbacks.add(WeakReference(callback))
+
+        if (_started) {
+            callback.onConditionChanged(this)
+            return
+        }
+
+        start()
+        _started = true
+    }
+
+    /** Removes the provided callback from further receiving updates. */
+    fun removeCallback(callback: Callback) {
+        if (shouldLog()) Log.d(mTag, "removing callback")
+        val iterator = _callbacks.iterator()
+        while (iterator.hasNext()) {
+            val cb = iterator.next().get()
+            if (cb == null || cb === callback) {
+                iterator.remove()
+            }
+        }
+
+        if (_callbacks.isNotEmpty() || !_started) {
+            return
+        }
+
+        stop()
+        _started = false
+    }
+
+    /**
+     * Wrapper to [.addCallback] when a lifecycle is in the resumed state and [.removeCallback] when
+     * not resumed automatically.
+     */
+    fun observe(owner: LifecycleOwner, listener: Callback): Callback {
+        return observe(owner.lifecycle, listener)
+    }
+
+    /**
+     * Wrapper to [.addCallback] when a lifecycle is in the resumed state and [.removeCallback] when
+     * not resumed automatically.
+     */
+    fun observe(lifecycle: Lifecycle, listener: Callback): Callback {
+        lifecycle.addObserver(
+            LifecycleEventObserver { lifecycleOwner: LifecycleOwner?, event: Lifecycle.Event ->
+                if (event == Lifecycle.Event.ON_RESUME) {
+                    addCallback(listener)
+                } else if (event == Lifecycle.Event.ON_PAUSE) {
+                    removeCallback(listener)
+                }
+            }
+        )
+        return listener
+    }
+
+    /**
+     * Updates the value for whether the condition has been fulfilled, and sends an update if the
+     * value changes and any callback is registered.
+     *
+     * @param isConditionMet True if the condition has been fulfilled. False otherwise.
+     */
+    protected fun updateCondition(isConditionMet: Boolean) {
+        if (_isConditionMet != null && _isConditionMet == isConditionMet) {
+            return
+        }
+
+        if (shouldLog()) Log.d(mTag, "updating condition to $isConditionMet")
+        _isConditionMet = isConditionMet
+        sendUpdate()
+    }
+
+    /**
+     * Clears the set condition value. This is purposefully separate from [.updateCondition] to
+     * avoid confusion around `null` values.
+     */
+    fun clearCondition() {
+        if (_isConditionMet == null) {
+            return
+        }
+
+        if (shouldLog()) Log.d(mTag, "clearing condition")
+
+        _isConditionMet = null
+        sendUpdate()
+    }
+
+    private fun sendUpdate() {
+        val iterator = _callbacks.iterator()
+        while (iterator.hasNext()) {
+            val cb = iterator.next().get()
+            if (cb == null) {
+                iterator.remove()
+            } else {
+                cb.onConditionChanged(this)
+            }
+        }
+    }
+
+    val isConditionSet: Boolean
+        /**
+         * Returns whether the condition is set. This method should be consulted to understand the
+         * value of [.isConditionMet].
+         *
+         * @return `true` if value is present, `false` otherwise.
+         */
+        get() = _isConditionMet != null
+
+    val isConditionMet: Boolean
+        /**
+         * Returns whether the condition has been met. Note that this method will return `false` if
+         * the condition is not set as well.
+         */
+        get() = true == _isConditionMet
+
+    protected fun shouldLog(): Boolean {
+        return Log.isLoggable(mTag, Log.DEBUG)
+    }
+
+    val tag: String
+        get() {
+            if (isOverridingCondition) {
+                return "$mTag[OVRD]"
+            }
+
+            return mTag
+        }
+
+    val state: String
+        /**
+         * Returns the state of the condition.
+         * - "Invalid", condition hasn't been set / not monitored
+         * - "True", condition has been met
+         * - "False", condition has not been met
+         */
+        get() {
+            if (!isConditionSet) {
+                return "Invalid"
+            }
+            return if (isConditionMet) "True" else "False"
+        }
+
+    /**
+     * Creates a new condition which will only be true when both this condition and all the provided
+     * conditions are true.
+     */
+    fun and(others: Collection<Condition>): Condition {
+        val conditions: List<Condition> = listOf(this, *others.toTypedArray())
+        return CombinedCondition(_scope, conditions, Evaluator.OP_AND)
+    }
+
+    /**
+     * Creates a new condition which will only be true when both this condition and the provided
+     * condition is true.
+     */
+    fun and(vararg others: Condition): Condition {
+        return and(listOf(*others))
+    }
+
+    /**
+     * Creates a new condition which will only be true when either this condition or any of the
+     * provided conditions are true.
+     */
+    fun or(others: Collection<Condition>): Condition {
+        val conditions: MutableList<Condition> = ArrayList()
+        conditions.add(this)
+        conditions.addAll(others)
+        return CombinedCondition(_scope, conditions, Evaluator.OP_OR)
+    }
+
+    /**
+     * Creates a new condition which will only be true when either this condition or the provided
+     * condition is true.
+     */
+    fun or(vararg others: Condition): Condition {
+        return or(listOf(*others))
+    }
+
+    /** Callback that receives updates about whether the condition has been fulfilled. */
+    fun interface Callback {
+        /**
+         * Called when the fulfillment of the condition changes.
+         *
+         * @param condition The condition in question.
+         */
+        fun onConditionChanged(condition: Condition)
+    }
+
+    companion object {
+        /** Condition should be started as soon as there is an active subscription. */
+        const val START_EAGERLY: Int = 0
+
+        /**
+         * Condition should be started lazily only if needed. But once started, it will not be
+         * cancelled unless there are no more active subscriptions.
+         */
+        const val START_LAZILY: Int = 1
+
+        /**
+         * Condition should be started lazily only if needed, and can be stopped when not needed.
+         * This should be used for conditions which are expensive to keep running.
+         */
+        const val START_WHEN_NEEDED: Int = 2
+    }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt
index 84edc35..0f535cd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/condition/ConditionExtensions.kt
@@ -14,7 +14,7 @@
 fun Flow<Boolean>.toCondition(
     scope: CoroutineScope,
     @StartStrategy strategy: Int,
-    initialValue: Boolean? = null
+    initialValue: Boolean? = null,
 ): Condition {
     return object : Condition(scope, initialValue, false) {
         var job: Job? = null
@@ -28,7 +28,8 @@
             job = null
         }
 
-        override fun getStartStrategy() = strategy
+        override val startStrategy: Int
+            get() = strategy
     }
 }
 
@@ -36,13 +37,16 @@
 fun Condition.toFlow(): Flow<Boolean?> {
     return callbackFlow {
             val callback =
-                Condition.Callback { condition ->
-                    if (condition.isConditionSet) {
-                        trySend(condition.isConditionMet)
-                    } else {
-                        trySend(null)
+                object : Condition.Callback {
+                    override fun onConditionChanged(condition: Condition) {
+                        if (condition.isConditionSet) {
+                            trySend(condition.isConditionMet)
+                        } else {
+                            trySend(null)
+                        }
                     }
                 }
+
             addCallback(callback)
             callback.onConditionChanged(this@toFlow)
             awaitClose { removeCallback(callback) }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ILauncherProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ILauncherProxy.aidl
index 10b9303..ade63b1 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ILauncherProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ILauncherProxy.aidl
@@ -66,7 +66,7 @@
     /**
      * Sent when some system ui state changes.
      */
-    void onSystemUiStateChanged(long stateFlags) = 16;
+    void onSystemUiStateChanged(long stateFlags, int displayId) = 16;
 
     /**
      * Sent when suggested rotation button could be shown
diff --git a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
index dcbacec..c880f05 100644
--- a/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
+++ b/packages/SystemUI/src/com/android/keyguard/CarrierTextManager.java
@@ -203,7 +203,9 @@
             CarrierTextManagerLogger logger) {
 
         mContext = context;
-        mIsEmergencyCallCapable = telephonyManager.isVoiceCapable();
+        boolean hasTelephony = mContext.getPackageManager()
+                .hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
+        mIsEmergencyCallCapable = telephonyManager.isVoiceCapable() && hasTelephony;
 
         mShowAirplaneMode = showAirplaneMode;
         mShowMissingSim = showMissingSim;
@@ -221,9 +223,7 @@
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLogger = logger;
         mBgExecutor.execute(() -> {
-            boolean supported = mContext.getPackageManager()
-                    .hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
-            if (supported && mNetworkSupported.compareAndSet(false, supported)) {
+            if (hasTelephony && mNetworkSupported.compareAndSet(false, hasTelephony)) {
                 // This will set/remove the listeners appropriately. Note that it will never double
                 // add the listeners.
                 handleSetListening(mCarrierTextCallback);
diff --git a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
index 9434234..1549b69 100644
--- a/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
+++ b/packages/SystemUI/src/com/android/keyguard/ClockEventController.kt
@@ -56,6 +56,7 @@
 import com.android.systemui.modes.shared.ModesUi
 import com.android.systemui.plugins.clocks.AlarmData
 import com.android.systemui.plugins.clocks.ClockController
+import com.android.systemui.plugins.clocks.ClockEventListener
 import com.android.systemui.plugins.clocks.ClockFaceController
 import com.android.systemui.plugins.clocks.ClockMessageBuffers
 import com.android.systemui.plugins.clocks.ClockTickRate
@@ -148,7 +149,7 @@
         val clockStr = clock.toString()
         loggers.forEach { it.d({ "New Clock: $str1" }) { str1 = clockStr } }
 
-        clock.initialize(isDarkTheme(), dozeAmount.value, 0f, { onClockBoundsChanged.value = it })
+        clock.initialize(isDarkTheme(), dozeAmount.value, 0f, clockListener)
 
         if (!regionSamplingEnabled) {
             updateColors()
@@ -312,6 +313,13 @@
     private var zenData: ZenData? = null
     private var alarmData: AlarmData? = null
 
+    private val clockListener =
+        object : ClockEventListener {
+            override fun onBoundsChanged(bounds: RectF) {
+                onClockBoundsChanged.value = bounds
+            }
+        }
+
     private val configListener =
         object : ConfigurationController.ConfigurationListener {
             override fun onThemeChanged() {
@@ -386,7 +394,7 @@
 
     @VisibleForTesting
     internal fun listenForDnd(scope: CoroutineScope): Job {
-        ModesUi.assertInNewMode()
+        ModesUi.unsafeAssertInNewMode()
         return scope.launch {
             zenModeInteractor.dndMode.collect {
                 val zenMode =
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index bd09e39..d84b034 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -2923,13 +2923,13 @@
     private boolean isPrimaryBouncerShowingOrWillBeShowing(
             ObservableTransitionState transitionState
     ) {
-        SceneContainerFlag.assertInNewMode();
+        SceneContainerFlag.unsafeAssertInNewMode();
         return isPrimaryBouncerFullyShown(transitionState)
                 || transitionState.isTransitioning(null, Overlays.Bouncer);
     }
 
     private boolean isPrimaryBouncerFullyShown(ObservableTransitionState transitionState) {
-        SceneContainerFlag.assertInNewMode();
+        SceneContainerFlag.unsafeAssertInNewMode();
         return transitionState.isIdle(Overlays.Bouncer);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesChecker.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesChecker.java
index 2d1cd03..20290f7 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesChecker.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesChecker.java
@@ -99,10 +99,7 @@
 
     private boolean isExclusivelyManagedBluetoothDevice(
             @NonNull CachedBluetoothDevice cachedDevice) {
-        if (com.android.settingslib.flags.Flags.enableHideExclusivelyManagedBluetoothDevice()) {
-            return BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext,
-                    cachedDevice.getDevice());
-        }
-        return false;
+        return BluetoothUtils.isExclusivelyManagedBluetoothDevice(mContext,
+                cachedDevice.getDevice());
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
index b730c93..08559f2 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesDialogDelegate.java
@@ -19,6 +19,8 @@
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
 
+import static com.android.internal.accessibility.AccessibilityShortcutController.ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME;
+
 import static java.util.Collections.emptyList;
 
 import android.bluetooth.BluetoothHapClient;
@@ -263,6 +265,20 @@
         dialog.setTitle(R.string.quick_settings_hearing_devices_dialog_title);
         dialog.setView(LayoutInflater.from(dialog.getContext()).inflate(
                 R.layout.hearing_devices_tile_dialog, null));
+        dialog.setNegativeButton(
+                R.string.hearing_devices_settings_button,
+                (dialogInterface, which) -> {
+                    mUiEventLogger.log(HearingDevicesUiEvent.HEARING_DEVICES_SETTINGS_CLICK,
+                            mLaunchSourceId);
+                    final Intent intent = new Intent(Settings.ACTION_ACCESSIBILITY_DETAILS_SETTINGS)
+                            .putExtra(Intent.EXTRA_COMPONENT_NAME,
+                                    ACCESSIBILITY_HEARING_AIDS_COMPONENT_NAME.flattenToString());
+                    mActivityStarter.postStartActivityDismissingKeyguard(intent, /* delay= */ 0,
+                            mDialogTransitionAnimator.createActivityTransitionController(
+                                    dialog));
+                },
+                /* dismissOnClick = */ true
+        );
         dialog.setPositiveButton(
                 R.string.quick_settings_done,
                 /* onClick = */ null,
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt
index fe1d504..4a695d6 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/hearingaid/HearingDevicesUiEvent.kt
@@ -39,7 +39,9 @@
     @UiEvent(doc = "Expand the ambient volume controls")
     HEARING_DEVICES_AMBIENT_EXPAND_CONTROLS(2153),
     @UiEvent(doc = "Collapse the ambient volume controls")
-    HEARING_DEVICES_AMBIENT_COLLAPSE_CONTROLS(2154);
+    HEARING_DEVICES_AMBIENT_COLLAPSE_CONTROLS(2154),
+    @UiEvent(doc = "Click on the device settings to enter hearing devices page")
+    HEARING_DEVICES_SETTINGS_CLICK(2172);
 
     override fun getId(): Int = this.id
 }
diff --git a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
index 0b578c6..113df20 100644
--- a/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/back/domain/interactor/BackActionInteractor.kt
@@ -122,6 +122,10 @@
         return false
     }
 
+    fun isBackCallbackRegistered(): Boolean {
+        return isCallbackRegistered
+    }
+
     private fun registerBackCallback() {
         if (isCallbackRegistered) {
             return
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
index 4c8a8f1..b8e95ee 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthContainerView.java
@@ -539,7 +539,8 @@
     }
 
     public void show(WindowManager wm) {
-        wm.addView(this, getLayoutParams(mWindowToken, mConfig.mPromptInfo.getTitle()));
+        wm.addView(this, getLayoutParams(mWindowToken, mConfig.mPromptInfo.getTitle(),
+                mPromptViewModel.getPromptKind().getValue().isCredential()));
     }
 
     private void forceExecuteAnimatedIn() {
@@ -738,7 +739,8 @@
     }
 
     @VisibleForTesting
-    static WindowManager.LayoutParams getLayoutParams(IBinder windowToken, CharSequence title) {
+    static WindowManager.LayoutParams getLayoutParams(IBinder windowToken, CharSequence title,
+            boolean isCredentialView) {
         final int windowFlags = WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED
                 | WindowManager.LayoutParams.FLAG_SECURE
                 | WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED
@@ -754,7 +756,7 @@
                 & ~WindowInsets.Type.systemBars());
         lp.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
         lp.setTitle("BiometricPrompt");
-        lp.accessibilityTitle = title;
+        lp.accessibilityTitle = isCredentialView ? " " : title;
         lp.dimAmount = BACKGROUND_DIM_AMOUNT;
         lp.token = windowToken;
         return lp;
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 88694ae..dfe8eb2 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -179,7 +179,6 @@
     @NonNull private final PowerInteractor mPowerInteractor;
     @NonNull private final CoroutineScope mScope;
     @NonNull private final InputManager mInputManager;
-    @NonNull private final UdfpsKeyguardAccessibilityDelegate mUdfpsKeyguardAccessibilityDelegate;
     @NonNull private final SelectedUserInteractor mSelectedUserInteractor;
     private final boolean mIgnoreRefreshRate;
     private final KeyguardTransitionInteractor mKeyguardTransitionInteractor;
@@ -292,7 +291,6 @@
                             mActivityTransitionAnimator,
                         mPrimaryBouncerInteractor,
                         mAlternateBouncerInteractor,
-                        mUdfpsKeyguardAccessibilityDelegate,
                         mKeyguardTransitionInteractor,
                         mSelectedUserInteractor,
                         mDeviceEntryUdfpsTouchOverlayViewModel,
@@ -691,7 +689,6 @@
             @NonNull AlternateBouncerInteractor alternateBouncerInteractor,
             @NonNull InputManager inputManager,
             @NonNull DeviceEntryFaceAuthInteractor deviceEntryFaceAuthInteractor,
-            @NonNull UdfpsKeyguardAccessibilityDelegate udfpsKeyguardAccessibilityDelegate,
             @NonNull SelectedUserInteractor selectedUserInteractor,
             @NonNull KeyguardTransitionInteractor keyguardTransitionInteractor,
             Lazy<DeviceEntryUdfpsTouchOverlayViewModel> deviceEntryUdfpsTouchOverlayViewModel,
@@ -742,7 +739,6 @@
         mPowerInteractor = powerInteractor;
         mScope = scope;
         mInputManager = inputManager;
-        mUdfpsKeyguardAccessibilityDelegate = udfpsKeyguardAccessibilityDelegate;
         mSelectedUserInteractor = selectedUserInteractor;
         mKeyguardTransitionInteractor = keyguardTransitionInteractor;
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
index 702f237..bdf5827 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsControllerOverlay.kt
@@ -107,7 +107,6 @@
     private val primaryBouncerInteractor: PrimaryBouncerInteractor,
     private val alternateBouncerInteractor: AlternateBouncerInteractor,
     private val isDebuggable: Boolean = Build.IS_DEBUGGABLE,
-    private val udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate,
     private val transitionInteractor: KeyguardTransitionInteractor,
     private val selectedUserInteractor: SelectedUserInteractor,
     private val deviceEntryUdfpsTouchOverlayViewModel: Lazy<DeviceEntryUdfpsTouchOverlayViewModel>,
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegate.kt b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegate.kt
deleted file mode 100644
index 99da660..0000000
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsKeyguardAccessibilityDelegate.kt
+++ /dev/null
@@ -1,54 +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.biometrics
-
-import android.content.res.Resources
-import android.os.Bundle
-import android.view.View
-import android.view.accessibility.AccessibilityNodeInfo
-import com.android.systemui.res.R
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
-import javax.inject.Inject
-
-@SysUISingleton
-class UdfpsKeyguardAccessibilityDelegate
-@Inject
-constructor(
-    @Main private val resources: Resources,
-    private val keyguardViewManager: StatusBarKeyguardViewManager,
-) : View.AccessibilityDelegate() {
-    override fun onInitializeAccessibilityNodeInfo(host: View, info: AccessibilityNodeInfo) {
-        super.onInitializeAccessibilityNodeInfo(host, info)
-        val clickAction =
-            AccessibilityNodeInfo.AccessibilityAction(
-                AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id,
-                resources.getString(R.string.accessibility_bouncer)
-            )
-        info.addAction(clickAction)
-    }
-
-    override fun performAccessibilityAction(host: View, action: Int, args: Bundle?): Boolean {
-        // when an a11y service is enabled, double tapping on the fingerprint sensor should
-        // show the primary bouncer
-        return if (action == AccessibilityNodeInfo.AccessibilityAction.ACTION_CLICK.id) {
-            keyguardViewManager.showPrimaryBouncer(/* scrimmed */ true)
-            true
-        } else super.performAccessibilityAction(host, action, args)
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt
index e4c4540..6842c90 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/binder/CredentialPasswordViewBinder.kt
@@ -43,6 +43,9 @@
             // the header info never changes - do it early
             val header = viewModel.header.first()
             passwordField.setTextOperationUser(UserHandle.of(header.user.userIdForPasswordEntry))
+            viewModel.inputBoxContentDescription.firstOrNull()?.let { descriptionId ->
+                passwordField.contentDescription = view.context.getString(descriptionId)
+            }
             viewModel.inputFlags.firstOrNull()?.let { flags -> passwordField.inputType = flags }
             if (requestFocusForInput) {
                 passwordField.requestFocus()
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
index 0c5c723..37cfc33 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/ui/viewmodel/CredentialViewModel.kt
@@ -59,6 +59,17 @@
             }
         }
 
+    /** Input box accessibility description for text based credential views */
+    val inputBoxContentDescription: Flow<Int?> =
+        credentialInteractor.prompt.map {
+            when (it) {
+                is BiometricPromptRequest.Credential.Pin -> R.string.keyguard_accessibility_pin_area
+                is BiometricPromptRequest.Credential.Password ->
+                    R.string.keyguard_accessibility_password
+                else -> null
+            }
+        }
+
     /** If stealth mode is active (hide user credential input). */
     val stealthMode: Flow<Boolean> =
         credentialInteractor.prompt.map {
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorImpl.kt
index 94fca21..f8f692d 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorImpl.kt
@@ -124,10 +124,18 @@
             when (deviceItem.type) {
                 DeviceItemType.AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE -> {
                     uiEventLogger.log(BluetoothTileDialogUiEvent.CHECK_MARK_ACTION_BUTTON_CLICKED)
+                    logger.logAudioSharingButtonClick(
+                        AudioSharingButtonClick.CHECK_MARK,
+                        deviceItem,
+                    )
                     audioSharingInteractor.stopAudioSharing()
                 }
                 DeviceItemType.AVAILABLE_AUDIO_SHARING_MEDIA_BLUETOOTH_DEVICE -> {
                     uiEventLogger.log(BluetoothTileDialogUiEvent.PLUS_ACTION_BUTTON_CLICKED)
+                    logger.logAudioSharingButtonClick(
+                        AudioSharingButtonClick.PLUS_BUTTON,
+                        deviceItem,
+                    )
                     audioSharingInteractor.startAudioSharing()
                 }
                 else -> {
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt
index 832afb1..7a76eed 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractor.kt
@@ -40,6 +40,7 @@
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.mapNotNull
 import kotlinx.coroutines.flow.merge
+import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.flow.receiveAsFlow
 import kotlinx.coroutines.withContext
 
@@ -73,6 +74,7 @@
     private val context: Context,
     private val localBluetoothManager: LocalBluetoothManager?,
     private val audioSharingRepository: AudioSharingRepository,
+    private val logger: BluetoothTileDialogLogger,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
 ) : AudioSharingInteractor {
 
@@ -92,9 +94,12 @@
 
     override val audioSourceStateUpdate =
         isAudioSharingOn
+            .onEach { logger.logAudioSharingStateChanged(it) }
             .flatMapLatest {
                 if (it) {
-                    audioSharingRepository.audioSourceStateUpdate
+                    audioSharingRepository.audioSourceStateUpdate.onEach {
+                        logger.logAudioSourceStateUpdate()
+                    }
                 } else {
                     emptyFlow()
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepository.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepository.kt
index 44f9769..d84b34a 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/AudioSharingRepository.kt
@@ -53,6 +53,7 @@
 class AudioSharingRepositoryImpl(
     private val localBluetoothManager: LocalBluetoothManager,
     private val settingsLibAudioSharingRepository: SettingsLibAudioSharingRepository,
+    private val logger: BluetoothTileDialogLogger,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
 ) : AudioSharingRepository {
 
@@ -79,7 +80,11 @@
             }
             leAudioBroadcastProfile?.latestBluetoothLeBroadcastMetadata?.let { metadata ->
                 leAudioBroadcastAssistantProfile?.let {
-                    it.allConnectedDevices.forEach { sink -> it.addSource(sink, metadata, false) }
+                    it.allConnectedDevices.forEach { sink ->
+                        it.addSource(sink, metadata, false).also {
+                            logger.logAudioSharingRequest(AudioSharingRequest.ADD_SOURCE)
+                        }
+                    }
                 }
             }
         }
@@ -99,7 +104,9 @@
             if (!settingsLibAudioSharingRepository.audioSharingAvailable()) {
                 return@withContext
             }
-            leAudioBroadcastProfile?.startPrivateBroadcast()
+            leAudioBroadcastProfile?.startPrivateBroadcast().also {
+                logger.logAudioSharingRequest(AudioSharingRequest.START_BROADCAST)
+            }
         }
     }
 
@@ -108,7 +115,9 @@
             if (!settingsLibAudioSharingRepository.audioSharingAvailable()) {
                 return@withContext
             }
-            leAudioBroadcastProfile?.stopLatestBroadcast()
+            leAudioBroadcastProfile?.stopLatestBroadcast().also {
+                logger.logAudioSharingRequest(AudioSharingRequest.STOP_BROADCAST)
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt
index 576acd2..5a5a51e 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentManager.kt
@@ -218,7 +218,7 @@
                     scrollViewContent.layoutParams.height = WRAP_CONTENT
                     lastUiUpdateMs = systemClock.elapsedRealtime()
                     lastItemRow = itemRow
-                    logger.logDeviceUiUpdate(lastUiUpdateMs - start)
+                    logger.logDeviceUiUpdate(lastUiUpdateMs - start, deviceItem)
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt
index 7ecd276..c5349c8 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothDetailsContentViewModel.kt
@@ -99,7 +99,7 @@
      */
     fun bindDetailsView(view: View) {
         // If `QsDetailedView` is not enabled, it should show the dialog.
-        QsDetailedView.assertInNewMode()
+        QsDetailedView.unsafeAssertInNewMode()
 
         cancelJob()
 
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogLogger.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogLogger.kt
index 06116f0..5f866c5 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/BluetoothTileDialogLogger.kt
@@ -27,18 +27,29 @@
 enum class BluetoothStateStage {
     USER_TOGGLED,
     BLUETOOTH_STATE_VALUE_SET,
-    BLUETOOTH_STATE_CHANGE_RECEIVED
+    BLUETOOTH_STATE_CHANGE_RECEIVED,
 }
 
 enum class DeviceFetchTrigger {
     FIRST_LOAD,
     BLUETOOTH_STATE_CHANGE_RECEIVED,
-    BLUETOOTH_CALLBACK_RECEIVED
+    BLUETOOTH_CALLBACK_RECEIVED,
+}
+
+enum class AudioSharingButtonClick {
+    PLUS_BUTTON,
+    CHECK_MARK,
+}
+
+enum class AudioSharingRequest {
+    START_BROADCAST,
+    STOP_BROADCAST,
+    ADD_SOURCE,
 }
 
 enum class JobStatus {
     FINISHED,
-    CANCELLED
+    CANCELLED,
 }
 
 class BluetoothTileDialogLogger
@@ -53,7 +64,7 @@
                 str1 = stage.toString()
                 str2 = state
             },
-            { "BluetoothState. stage=$str1 state=$str2" }
+            { "BluetoothState. stage=$str1 state=$str2" },
         )
 
     fun logDeviceClick(address: String, type: DeviceItemType) =
@@ -64,7 +75,7 @@
                 str1 = address
                 str2 = type.toString()
             },
-            { "DeviceClick. address=$str1 type=$str2" }
+            { "DeviceClick. address=$str1 type=$str2" },
         )
 
     fun logActiveDeviceChanged(address: String?, profileId: Int) =
@@ -75,7 +86,7 @@
                 str1 = address
                 int1 = profileId
             },
-            { "ActiveDeviceChanged. address=$str1 profileId=$int1" }
+            { "ActiveDeviceChanged. address=$str1 profileId=$int1" },
         )
 
     fun logProfileConnectionStateChanged(address: String, state: String, profileId: Int) =
@@ -87,7 +98,7 @@
                 str2 = state
                 int1 = profileId
             },
-            { "ProfileConnectionStateChanged. address=$str1 state=$str2 profileId=$int1" }
+            { "ProfileConnectionStateChanged. address=$str1 state=$str2 profileId=$int1" },
         )
 
     fun logBatteryChanged(address: String, key: Int, value: ByteArray?) =
@@ -99,7 +110,7 @@
                 int1 = key
                 str2 = value?.toString() ?: ""
             },
-            { "BatteryChanged. address=$str1 key=$int1 value=$str2" }
+            { "BatteryChanged. address=$str1 key=$int1 value=$str2" },
         )
 
     fun logDeviceFetch(status: JobStatus, trigger: DeviceFetchTrigger, duration: Long) =
@@ -111,18 +122,26 @@
                 str2 = trigger.toString()
                 long1 = duration
             },
-            { "DeviceFetch. status=$str1 trigger=$str2 duration=$long1" }
+            { "DeviceFetch. status=$str1 trigger=$str2 duration=$long1" },
         )
 
-    fun logDeviceUiUpdate(duration: Long) =
-        logBuffer.log(TAG, DEBUG, { long1 = duration }, { "DeviceUiUpdate. duration=$long1" })
+    fun logDeviceUiUpdate(duration: Long, deviceItem: List<DeviceItem>) =
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                long1 = duration
+                str1 = deviceItem.toString()
+            },
+            { "DeviceUiUpdate. duration=$long1 deviceItem=$str1" },
+        )
 
     fun logDeviceClickInAudioSharingWhenEnabled(inAudioSharing: Boolean) {
         logBuffer.log(
             TAG,
             DEBUG,
             { str1 = inAudioSharing.toString() },
-            { "DeviceClick. in audio sharing=$str1" }
+            { "DeviceClick. in audio sharing=$str1" },
         )
     }
 
@@ -138,7 +157,36 @@
                 str1 = criteria
                 str2 = deviceItem.toString()
             },
-            { "$str1. deviceItem=$str2" }
+            { "$str1. deviceItem=$str2" },
         )
     }
+
+    fun logAudioSharingStateChanged(stateOn: Boolean) =
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { str1 = stateOn.toString() },
+            { "AudioSharingStateChanged. state=$str1" },
+        )
+
+    fun logAudioSourceStateUpdate() = logBuffer.log(TAG, DEBUG, {}, { "AudioSourceStateUpdate" })
+
+    fun logAudioSharingButtonClick(click: AudioSharingButtonClick, deviceItem: DeviceItem) =
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            {
+                str1 = click.toString()
+                str2 = deviceItem.toString()
+            },
+            { "AudioSharingButtonClick. click=$str1 deviceItem=$str2" },
+        )
+
+    fun logAudioSharingRequest(apiCall: AudioSharingRequest) =
+        logBuffer.log(
+            TAG,
+            DEBUG,
+            { str1 = apiCall.toString() },
+            { "AudioSharingRequest. apiCall=$str1" },
+        )
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
index bfbc27d..858cc00 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactory.kt
@@ -21,7 +21,6 @@
 import com.android.settingslib.bluetooth.BluetoothUtils
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.LocalBluetoothManager
-import com.android.settingslib.flags.Flags
 import com.android.systemui.res.R
 
 private val backgroundOn = R.drawable.settingslib_switch_bar_bg_on
@@ -222,12 +221,8 @@
         isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
-        return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
-            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) &&
-                BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, isOngoingCall)
-        } else {
+        return !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) &&
             BluetoothUtils.isConnectedBluetoothDevice(cachedDevice, isOngoingCall)
-        }
     }
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
@@ -250,13 +245,9 @@
         isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
-        return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
-            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) &&
-                cachedDevice.bondState == BluetoothDevice.BOND_BONDED &&
-                !cachedDevice.isConnected
-        } else {
-            cachedDevice.bondState == BluetoothDevice.BOND_BONDED && !cachedDevice.isConnected
-        }
+        return !BluetoothUtils.isExclusivelyManagedBluetoothDevice(context, cachedDevice.device) &&
+            cachedDevice.bondState == BluetoothDevice.BOND_BONDED &&
+            !cachedDevice.isConnected
     }
 
     override fun create(context: Context, cachedDevice: CachedBluetoothDevice): DeviceItem {
@@ -279,18 +270,12 @@
         isOngoingCall: Boolean,
         audioSharingAvailable: Boolean,
     ): Boolean {
-        return if (Flags.enableHideExclusivelyManagedBluetoothDevice()) {
-            !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
-                context,
-                cachedDevice.getDevice(),
-            ) &&
-                cachedDevice.isHearingAidDevice &&
-                cachedDevice.bondState == BluetoothDevice.BOND_BONDED &&
-                !cachedDevice.isConnected
-        } else {
+        return !BluetoothUtils.isExclusivelyManagedBluetoothDevice(
+            context,
+            cachedDevice.getDevice(),
+        ) &&
             cachedDevice.isHearingAidDevice &&
-                cachedDevice.bondState == BluetoothDevice.BOND_BONDED &&
-                !cachedDevice.isConnected
-        }
+            cachedDevice.bondState == BluetoothDevice.BOND_BONDED &&
+            !cachedDevice.isConnected
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/dagger/AudioSharingModule.kt b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/dagger/AudioSharingModule.kt
index afe9a1e..01c4b21 100644
--- a/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/dagger/AudioSharingModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/bluetooth/qsdialog/dagger/AudioSharingModule.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.bluetooth.qsdialog.AudioSharingRepositoryImpl
 import com.android.systemui.bluetooth.qsdialog.AvailableAudioSharingMediaDeviceItemFactory
 import com.android.systemui.bluetooth.qsdialog.AvailableMediaDeviceItemFactory
+import com.android.systemui.bluetooth.qsdialog.BluetoothTileDialogLogger
 import com.android.systemui.bluetooth.qsdialog.ConnectedDeviceItemFactory
 import com.android.systemui.bluetooth.qsdialog.DeviceItemActionInteractor
 import com.android.systemui.bluetooth.qsdialog.DeviceItemActionInteractorImpl
@@ -53,6 +54,7 @@
         fun provideAudioSharingRepository(
             localBluetoothManager: LocalBluetoothManager?,
             settingsLibAudioSharingRepository: SettingsLibAudioSharingRepository,
+            logger: BluetoothTileDialogLogger,
             @Background backgroundDispatcher: CoroutineDispatcher,
         ): AudioSharingRepository =
             if (
@@ -62,6 +64,7 @@
                 AudioSharingRepositoryImpl(
                     localBluetoothManager,
                     settingsLibAudioSharingRepository,
+                    logger,
                     backgroundDispatcher,
                 )
             } else {
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 b13f6df..52204b8 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
@@ -70,6 +70,7 @@
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.compose.modifiers.padding
 import com.android.compose.ui.graphics.drawInOverlay
 import com.android.systemui.Flags
 import com.android.systemui.biometrics.Utils.toBitmap
@@ -164,20 +165,15 @@
 
     val activeIconColor = colors.activeTickColor
     val inactiveIconColor = colors.inactiveTickColor
-    val trackIcon: DrawScope.(Offset, Color, Float) -> Unit =
-        remember(painter) {
-            { offset, color, alpha ->
-                translate(offset.x + IconPadding.toPx(), offset.y) {
-                    with(painter) {
-                        draw(
-                            IconSize.toSize(),
-                            colorFilter = ColorFilter.tint(color),
-                            alpha = alpha,
-                        )
-                    }
+    val trackIcon: DrawScope.(Offset, Color, Float) -> Unit = remember {
+        { offset, color, alpha ->
+            translate(offset.x + IconPadding.toPx(), offset.y) {
+                with(painter) {
+                    draw(IconSize.toSize(), colorFilter = ColorFilter.tint(color), alpha = alpha)
                 }
             }
         }
+    }
 
     Slider(
         value = animatedValue,
@@ -348,7 +344,13 @@
 
     DisposableEffect(Unit) { onDispose { viewModel.setIsDragging(false) } }
 
-    Box(modifier = modifier.fillMaxWidth().sysuiResTag("brightness_slider")) {
+    Box(
+        modifier =
+            modifier
+                .padding(vertical = { SliderBackgroundFrameSize.height.roundToPx() })
+                .fillMaxWidth()
+                .sysuiResTag("brightness_slider")
+    ) {
         BrightnessSlider(
             gammaValue = gamma,
             valueRange = viewModel.minBrightness.value..viewModel.maxBrightness.value,
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ActionIntentCreator.kt b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ActionIntentCreator.kt
new file mode 100644
index 0000000..df6c1b1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ActionIntentCreator.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.clipboardoverlay
+
+import android.content.ClipData
+import android.content.ClipDescription
+import android.content.ComponentName
+import android.content.Context
+import android.content.Intent
+import android.net.Uri
+import android.text.TextUtils
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.res.R
+import javax.inject.Inject
+
+@SysUISingleton
+class ActionIntentCreator @Inject constructor() : IntentCreator {
+    override fun getTextEditorIntent(context: Context?) =
+        Intent(context, EditTextActivity::class.java).apply {
+            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+        }
+
+    override fun getShareIntent(clipData: ClipData, context: Context?): Intent {
+        val shareIntent = Intent(Intent.ACTION_SEND)
+
+        // From the ACTION_SEND docs:
+        //   "If using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it should be the
+        //    MIME type of the data in EXTRA_STREAM"
+        val uri = clipData.getItemAt(0).uri
+        shareIntent.apply {
+            if (uri != null) {
+                // We don't use setData here because some apps interpret this as "to:".
+                setType(clipData.description.getMimeType(0))
+                // Include URI in ClipData also, so that grantPermission picks it up.
+                setClipData(
+                    ClipData(
+                        ClipDescription("content", arrayOf(clipData.description.getMimeType(0))),
+                        ClipData.Item(uri),
+                    )
+                )
+                putExtra(Intent.EXTRA_STREAM, uri)
+                addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+            } else {
+                putExtra(Intent.EXTRA_TEXT, clipData.getItemAt(0).coerceToText(context).toString())
+                setType("text/plain")
+            }
+        }
+
+        return Intent.createChooser(shareIntent, null)
+            .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK or Intent.FLAG_ACTIVITY_NEW_TASK)
+            .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+    }
+
+    override fun getImageEditIntent(uri: Uri?, context: Context): Intent {
+        val editorPackage = context.getString(R.string.config_screenshotEditor)
+        return Intent(Intent.ACTION_EDIT).apply {
+            if (!TextUtils.isEmpty(editorPackage)) {
+                setComponent(ComponentName.unflattenFromString(editorPackage))
+            }
+            setDataAndType(uri, "image/*")
+            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+            putExtra(EXTRA_EDIT_SOURCE, EDIT_SOURCE_CLIPBOARD)
+        }
+    }
+
+    override fun getRemoteCopyIntent(clipData: ClipData?, context: Context): Intent {
+        val remoteCopyPackage = context.getString(R.string.config_remoteCopyPackage)
+        return Intent(REMOTE_COPY_ACTION).apply {
+            if (!TextUtils.isEmpty(remoteCopyPackage)) {
+                setComponent(ComponentName.unflattenFromString(remoteCopyPackage))
+            }
+
+            setClipData(clipData)
+            addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
+            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_CLEAR_TASK)
+        }
+    }
+
+    companion object {
+        private const val EXTRA_EDIT_SOURCE: String = "edit_source"
+        private const val EDIT_SOURCE_CLIPBOARD: String = "clipboard"
+        private const val REMOTE_COPY_ACTION: String = "android.intent.action.REMOTE_COPY"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
index ac74784..314b6e7 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/ClipboardOverlayController.java
@@ -65,7 +65,6 @@
 import com.android.systemui.broadcast.BroadcastSender;
 import com.android.systemui.clipboardoverlay.dagger.ClipboardOverlayModule.OverlayWindowContext;
 import com.android.systemui.dagger.qualifiers.Background;
-import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.res.R;
 import com.android.systemui.screenshot.TimeoutHandler;
 
@@ -94,13 +93,13 @@
     private final ClipboardOverlayWindow mWindow;
     private final TimeoutHandler mTimeoutHandler;
     private final ClipboardOverlayUtils mClipboardUtils;
-    private final FeatureFlags mFeatureFlags;
     private final Executor mBgExecutor;
     private final ClipboardImageLoader mClipboardImageLoader;
     private final ClipboardTransitionExecutor mTransitionExecutor;
 
     private final ClipboardOverlayView mView;
     private final ClipboardIndicationProvider mClipboardIndicationProvider;
+    private final IntentCreator mIntentCreator;
 
     private Runnable mOnSessionCompleteListener;
     private Runnable mOnRemoteCopyTapped;
@@ -189,13 +188,13 @@
             BroadcastDispatcher broadcastDispatcher,
             BroadcastSender broadcastSender,
             TimeoutHandler timeoutHandler,
-            FeatureFlags featureFlags,
             ClipboardOverlayUtils clipboardUtils,
             @Background Executor bgExecutor,
             ClipboardImageLoader clipboardImageLoader,
             ClipboardTransitionExecutor transitionExecutor,
             ClipboardIndicationProvider clipboardIndicationProvider,
-            UiEventLogger uiEventLogger) {
+            UiEventLogger uiEventLogger,
+            IntentCreator intentCreator) {
         mContext = context;
         mBroadcastDispatcher = broadcastDispatcher;
         mClipboardImageLoader = clipboardImageLoader;
@@ -203,6 +202,7 @@
         mClipboardIndicationProvider = clipboardIndicationProvider;
 
         mClipboardLogger = new ClipboardLogger(uiEventLogger);
+        mIntentCreator = intentCreator;
 
         mView = clipboardOverlayView;
         mWindow = clipboardOverlayWindow;
@@ -211,7 +211,6 @@
             hideImmediate();
         });
 
-        mFeatureFlags = featureFlags;
         mTimeoutHandler = timeoutHandler;
         mTimeoutHandler.setDefaultTimeoutMillis(CLIPBOARD_DEFAULT_TIMEOUT_MILLIS);
 
@@ -508,7 +507,8 @@
     }
 
     private void maybeShowRemoteCopy(ClipData clipData) {
-        Intent remoteCopyIntent = IntentCreator.getRemoteCopyIntent(clipData, mContext);
+        Intent remoteCopyIntent = mIntentCreator.getRemoteCopyIntent(clipData, mContext);
+
         // Only show remote copy if it's available.
         PackageManager packageManager = mContext.getPackageManager();
         if (packageManager.resolveActivity(
@@ -558,19 +558,19 @@
 
     private void editImage(Uri uri) {
         mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_EDIT_TAPPED);
-        mContext.startActivity(IntentCreator.getImageEditIntent(uri, mContext));
+        mContext.startActivity(mIntentCreator.getImageEditIntent(uri, mContext));
         animateOut();
     }
 
     private void editText() {
         mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_EDIT_TAPPED);
-        mContext.startActivity(IntentCreator.getTextEditorIntent(mContext));
+        mContext.startActivity(mIntentCreator.getTextEditorIntent(mContext));
         animateOut();
     }
 
     private void shareContent(ClipData clip) {
         mClipboardLogger.logSessionComplete(CLIPBOARD_OVERLAY_SHARE_TAPPED);
-        mContext.startActivity(IntentCreator.getShareIntent(clip, mContext));
+        mContext.startActivity(mIntentCreator.getShareIntent(clip, mContext));
         animateOut();
     }
 
@@ -717,22 +717,22 @@
     public void onRemoteCopyButtonTapped() {
         if (clipboardSharedTransitions()) {
             finish(CLIPBOARD_OVERLAY_REMOTE_COPY_TAPPED,
-                    IntentCreator.getRemoteCopyIntent(mClipboardModel.getClipData(), mContext));
+                    mIntentCreator.getRemoteCopyIntent(mClipboardModel.getClipData(), mContext));
         }
     }
 
     @Override
     public void onShareButtonTapped() {
         if (clipboardSharedTransitions()) {
+            Intent shareIntent =
+                    mIntentCreator.getShareIntent(mClipboardModel.getClipData(), mContext);
             switch (mClipboardModel.getType()) {
                 case TEXT:
                 case URI:
-                    finish(CLIPBOARD_OVERLAY_SHARE_TAPPED,
-                            IntentCreator.getShareIntent(mClipboardModel.getClipData(), mContext));
+                    finish(CLIPBOARD_OVERLAY_SHARE_TAPPED, shareIntent);
                     break;
                 case IMAGE:
-                    finishWithSharedTransition(CLIPBOARD_OVERLAY_SHARE_TAPPED,
-                            IntentCreator.getShareIntent(mClipboardModel.getClipData(), mContext));
+                    finishWithSharedTransition(CLIPBOARD_OVERLAY_SHARE_TAPPED, shareIntent);
                     break;
             }
         }
@@ -744,11 +744,11 @@
             switch (mClipboardModel.getType()) {
                 case TEXT:
                     finish(CLIPBOARD_OVERLAY_EDIT_TAPPED,
-                            IntentCreator.getTextEditorIntent(mContext));
+                            mIntentCreator.getTextEditorIntent(mContext));
                     break;
                 case IMAGE:
                     finishWithSharedTransition(CLIPBOARD_OVERLAY_EDIT_TAPPED,
-                            IntentCreator.getImageEditIntent(mClipboardModel.getUri(), mContext));
+                            mIntentCreator.getImageEditIntent(mClipboardModel.getUri(), mContext));
                     break;
                 default:
                     Log.w(TAG, "Got preview tapped callback for non-editable type "
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DefaultIntentCreator.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DefaultIntentCreator.java
new file mode 100644
index 0000000..4b24536
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/DefaultIntentCreator.java
@@ -0,0 +1,102 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.clipboardoverlay;
+
+import android.content.ClipData;
+import android.content.ClipDescription;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.text.TextUtils;
+
+import com.android.systemui.dagger.SysUISingleton;
+import com.android.systemui.res.R;
+
+import javax.inject.Inject;
+
+@SysUISingleton
+public class DefaultIntentCreator implements IntentCreator {
+    private static final String EXTRA_EDIT_SOURCE = "edit_source";
+    private static final String EDIT_SOURCE_CLIPBOARD = "clipboard";
+    private static final String REMOTE_COPY_ACTION = "android.intent.action.REMOTE_COPY";
+
+    @Inject
+    public DefaultIntentCreator() {}
+
+    public Intent getTextEditorIntent(Context context) {
+        Intent intent = new Intent(context, EditTextActivity.class);
+        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        return intent;
+    }
+
+    public Intent getShareIntent(ClipData clipData, Context context) {
+        Intent shareIntent = new Intent(Intent.ACTION_SEND);
+
+        // From the ACTION_SEND docs:
+        //   "If using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it should be the
+        //    MIME type of the data in EXTRA_STREAM"
+        Uri uri = clipData.getItemAt(0).getUri();
+        if (uri != null) {
+            // We don't use setData here because some apps interpret this as "to:".
+            shareIntent.setType(clipData.getDescription().getMimeType(0));
+            // Include URI in ClipData also, so that grantPermission picks it up.
+            shareIntent.setClipData(new ClipData(
+                    new ClipDescription(
+                            "content", new String[]{clipData.getDescription().getMimeType(0)}),
+                    new ClipData.Item(uri)));
+            shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
+            shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        } else {
+            shareIntent.putExtra(
+                    Intent.EXTRA_TEXT, clipData.getItemAt(0).coerceToText(context).toString());
+            shareIntent.setType("text/plain");
+        }
+        Intent chooserIntent = Intent.createChooser(shareIntent, null)
+                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK)
+                .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+
+        return chooserIntent;
+    }
+
+    public Intent getImageEditIntent(Uri uri, Context context) {
+        String editorPackage = context.getString(R.string.config_screenshotEditor);
+        Intent editIntent = new Intent(Intent.ACTION_EDIT);
+        if (!TextUtils.isEmpty(editorPackage)) {
+            editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
+        }
+        editIntent.setDataAndType(uri, "image/*");
+        editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        editIntent.putExtra(EXTRA_EDIT_SOURCE, EDIT_SOURCE_CLIPBOARD);
+        return editIntent;
+    }
+
+    public Intent getRemoteCopyIntent(ClipData clipData, Context context) {
+        Intent nearbyIntent = new Intent(REMOTE_COPY_ACTION);
+
+        String remoteCopyPackage = context.getString(R.string.config_remoteCopyPackage);
+        if (!TextUtils.isEmpty(remoteCopyPackage)) {
+            nearbyIntent.setComponent(ComponentName.unflattenFromString(remoteCopyPackage));
+        }
+
+        nearbyIntent.setClipData(clipData);
+        nearbyIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
+        nearbyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
+        return nearbyIntent;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
index a18b4c8..c8a6b05 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/IntentCreator.java
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2022 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -17,79 +17,13 @@
 package com.android.systemui.clipboardoverlay;
 
 import android.content.ClipData;
-import android.content.ClipDescription;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.net.Uri;
-import android.text.TextUtils;
 
-import com.android.systemui.res.R;
-
-class IntentCreator {
-    private static final String EXTRA_EDIT_SOURCE = "edit_source";
-    private static final String EDIT_SOURCE_CLIPBOARD = "clipboard";
-    private static final String REMOTE_COPY_ACTION = "android.intent.action.REMOTE_COPY";
-
-    static Intent getTextEditorIntent(Context context) {
-        Intent intent = new Intent(context, EditTextActivity.class);
-        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        return intent;
-    }
-
-    static Intent getShareIntent(ClipData clipData, Context context) {
-        Intent shareIntent = new Intent(Intent.ACTION_SEND);
-
-        // From the ACTION_SEND docs:
-        //   "If using EXTRA_TEXT, the MIME type should be "text/plain"; otherwise it should be the
-        //    MIME type of the data in EXTRA_STREAM"
-        Uri uri = clipData.getItemAt(0).getUri();
-        if (uri != null) {
-            // We don't use setData here because some apps interpret this as "to:".
-            shareIntent.setType(clipData.getDescription().getMimeType(0));
-            // Include URI in ClipData also, so that grantPermission picks it up.
-            shareIntent.setClipData(new ClipData(
-                    new ClipDescription(
-                            "content", new String[]{clipData.getDescription().getMimeType(0)}),
-                    new ClipData.Item(uri)));
-            shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
-            shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        } else {
-            shareIntent.putExtra(
-                    Intent.EXTRA_TEXT, clipData.getItemAt(0).coerceToText(context).toString());
-            shareIntent.setType("text/plain");
-        }
-        Intent chooserIntent = Intent.createChooser(shareIntent, null)
-                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK)
-                .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-
-        return chooserIntent;
-    }
-
-    static Intent getImageEditIntent(Uri uri, Context context) {
-        String editorPackage = context.getString(R.string.config_screenshotEditor);
-        Intent editIntent = new Intent(Intent.ACTION_EDIT);
-        if (!TextUtils.isEmpty(editorPackage)) {
-            editIntent.setComponent(ComponentName.unflattenFromString(editorPackage));
-        }
-        editIntent.setDataAndType(uri, "image/*");
-        editIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        editIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        editIntent.putExtra(EXTRA_EDIT_SOURCE, EDIT_SOURCE_CLIPBOARD);
-        return editIntent;
-    }
-
-    static Intent getRemoteCopyIntent(ClipData clipData, Context context) {
-        Intent nearbyIntent = new Intent(REMOTE_COPY_ACTION);
-
-        String remoteCopyPackage = context.getString(R.string.config_remoteCopyPackage);
-        if (!TextUtils.isEmpty(remoteCopyPackage)) {
-            nearbyIntent.setComponent(ComponentName.unflattenFromString(remoteCopyPackage));
-        }
-
-        nearbyIntent.setClipData(clipData);
-        nearbyIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
-        nearbyIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK);
-        return nearbyIntent;
-    }
+public interface IntentCreator {
+    Intent getTextEditorIntent(Context context);
+    Intent getShareIntent(ClipData clipData, Context context);
+    Intent getImageEditIntent(Uri uri, Context context);
+    Intent getRemoteCopyIntent(ClipData clipData, Context context);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
index 6c10eea..c86a84b 100644
--- a/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
+++ b/packages/SystemUI/src/com/android/systemui/clipboardoverlay/dagger/ClipboardOverlayModule.java
@@ -20,6 +20,7 @@
 
 import static com.android.systemui.Flags.clipboardOverlayMultiuser;
 import static com.android.systemui.Flags.enableViewCaptureTracing;
+import static com.android.systemui.shared.Flags.usePreferredImageEditor;
 import static com.android.systemui.util.ConvenienceExtensionsKt.toKotlinLazy;
 
 import static java.lang.annotation.RetentionPolicy.RUNTIME;
@@ -32,7 +33,10 @@
 
 import com.android.app.viewcapture.ViewCapture;
 import com.android.app.viewcapture.ViewCaptureAwareWindowManager;
+import com.android.systemui.clipboardoverlay.ActionIntentCreator;
 import com.android.systemui.clipboardoverlay.ClipboardOverlayView;
+import com.android.systemui.clipboardoverlay.DefaultIntentCreator;
+import com.android.systemui.clipboardoverlay.IntentCreator;
 import com.android.systemui.res.R;
 import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.settings.UserTracker;
@@ -102,6 +106,17 @@
                 /* isViewCaptureEnabled= */ enableViewCaptureTracing());
     }
 
+    @Provides
+    static IntentCreator provideIntentCreator(
+            Lazy<DefaultIntentCreator> defaultIntentCreator,
+            Lazy<ActionIntentCreator> actionIntentCreator) {
+        if (usePreferredImageEditor()) {
+            return actionIntentCreator.get();
+        } else {
+            return defaultIntentCreator.get();
+        }
+    }
+
     @Qualifier
     @Documented
     @Retention(RUNTIME)
diff --git a/packages/SystemUI/src/com/android/systemui/common/domain/interactor/SysUIStateDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/common/domain/interactor/SysUIStateDisplaysInteractor.kt
new file mode 100644
index 0000000..9db7b50
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/common/domain/interactor/SysUIStateDisplaysInteractor.kt
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.common.domain.interactor
+
+import android.util.Log
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.data.repository.PerDisplayRepository
+import com.android.systemui.model.StateChange
+import com.android.systemui.model.SysUiState
+import javax.inject.Inject
+
+/** Handles [SysUiState] changes between displays. */
+@SysUISingleton
+class SysUIStateDisplaysInteractor
+@Inject
+constructor(
+    private val sysUIStateRepository: PerDisplayRepository<SysUiState>,
+    private val displayRepository: DisplayRepository,
+) {
+
+    /**
+     * Sets the flags on the given [targetDisplayId] based on the [stateChanges], while making sure
+     * that those flags are not set in any other display.
+     */
+    fun setFlagsExclusivelyToDisplay(targetDisplayId: Int, stateChanges: StateChange) {
+        if (SysUiState.DEBUG) {
+            Log.d(TAG, "Setting flags $stateChanges only for display $targetDisplayId")
+        }
+        displayRepository.displays.value
+            .mapNotNull { sysUIStateRepository[it.displayId] }
+            .apply {
+                // Let's first modify all states, without committing changes ...
+                forEach { displaySysUIState ->
+                    if (displaySysUIState.displayId == targetDisplayId) {
+                        stateChanges.applyTo(displaySysUIState)
+                    } else {
+                        stateChanges.clearFrom(displaySysUIState)
+                    }
+                }
+                // ... And commit changes at the end
+                forEach { sysuiState -> sysuiState.commitUpdate() }
+            }
+    }
+
+    private companion object {
+        const val TAG = "SysUIStateInteractor"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/Color.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/Color.kt
index d53a737..7215925 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/model/Color.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Color.kt
@@ -19,11 +19,13 @@
 import android.annotation.AttrRes
 import android.annotation.ColorInt
 import android.annotation.ColorRes
+import androidx.compose.runtime.Stable
 
 /**
  * Models a color that can be either a specific [Color.Loaded] value or a resolvable theme
  * [Color.Attribute]
  */
+@Stable
 sealed interface Color {
 
     data class Loaded(@ColorInt val color: Int) : Color
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/ContentDescription.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/ContentDescription.kt
index d628aca..b7d8ae6 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/model/ContentDescription.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/ContentDescription.kt
@@ -18,11 +18,13 @@
 
 import android.annotation.StringRes
 import android.content.Context
+import androidx.compose.runtime.Stable
 
 /**
  * Models a content description, that can either be already [loaded][ContentDescription.Loaded] or
  * be a [reference][ContentDescription.Resource] to a resource.
  */
+@Stable
 sealed class ContentDescription {
     data class Loaded(val description: String?) : ContentDescription()
 
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
index e6f0245..2adaec2 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
@@ -18,11 +18,13 @@
 
 import android.annotation.DrawableRes
 import android.graphics.drawable.Drawable
+import androidx.compose.runtime.Stable
 
 /**
  * Models an icon, that can either be already [loaded][Icon.Loaded] or be a [reference]
  * [Icon.Resource] to a resource. In case of [Loaded], the resource ID [res] is optional.
  */
+@Stable
 sealed class Icon {
     abstract val contentDescription: ContentDescription?
 
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
index 13f6bba..07cc136 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/ConfigurationState.kt
@@ -147,7 +147,7 @@
          */
         fun create(
             context: Context,
-            configurationController: ConfigurationController
+            configurationController: ConfigurationController,
         ): ConfigurationStateImpl
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/communal/DeviceInactiveCondition.java b/packages/SystemUI/src/com/android/systemui/communal/DeviceInactiveCondition.java
index e456310..4be9601 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/DeviceInactiveCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/communal/DeviceInactiveCondition.java
@@ -102,7 +102,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
index d7859c9..140db7b 100644
--- a/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/communal/ui/viewmodel/CommunalViewModel.kt
@@ -367,12 +367,22 @@
     /** See [CommunalSettingsInteractor.isV2FlagEnabled] */
     fun v2FlagEnabled(): Boolean = communalSettingsInteractor.isV2FlagEnabled()
 
-    val swipeToHubEnabled: StateFlow<Boolean> by lazy {
-        if (v2FlagEnabled()) {
-            communalInteractor.shouldShowCommunal
-        } else {
-            MutableStateFlow(swipeToHub)
-        }
+    val swipeToHubEnabled: Flow<Boolean> by lazy {
+        val inAllowedDeviceState =
+            if (swipeToHub) {
+                MutableStateFlow(true)
+            } else if (v2FlagEnabled()) {
+                communalInteractor.shouldShowCommunal
+            } else {
+                MutableStateFlow(false)
+            }
+
+        val inAllowedKeyguardState =
+            keyguardTransitionInteractor.startedKeyguardTransitionStep.map {
+                it.to == KeyguardState.LOCKSCREEN || it.to == KeyguardState.GLANCEABLE_HUB
+            }
+
+        allOf(inAllowedDeviceState, inAllowedKeyguardState)
     }
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/PerDisplayRepositoriesModule.kt b/packages/SystemUI/src/com/android/systemui/dagger/PerDisplayRepositoriesModule.kt
new file mode 100644
index 0000000..39708a7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/dagger/PerDisplayRepositoriesModule.kt
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.dagger
+
+import com.android.systemui.display.data.repository.DefaultDisplayOnlyInstanceRepositoryImpl
+import com.android.systemui.display.data.repository.PerDisplayInstanceRepositoryImpl
+import com.android.systemui.display.data.repository.PerDisplayRepository
+import com.android.systemui.model.SysUIStateInstanceProvider
+import com.android.systemui.model.SysUiState
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
+import dagger.Module
+import dagger.Provides
+
+/** This module is meant to contain all the code to create the various [PerDisplayRepository<>]. */
+@Module
+class PerDisplayRepositoriesModule {
+
+    @SysUISingleton
+    @Provides
+    fun provideSysUiStateRepository(
+        repositoryFactory: PerDisplayInstanceRepositoryImpl.Factory<SysUiState>,
+        instanceProvider: SysUIStateInstanceProvider,
+    ): PerDisplayRepository<SysUiState> {
+        val debugName = "SysUiStatePerDisplayRepo"
+        return if (ShadeWindowGoesAround.isEnabled) {
+            repositoryFactory.create(debugName, instanceProvider)
+        } else {
+            DefaultDisplayOnlyInstanceRepositoryImpl(debugName, instanceProvider)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
index f8cf6b0..f08126a 100644
--- a/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
+++ b/packages/SystemUI/src/com/android/systemui/dagger/SystemUIModule.java
@@ -21,6 +21,7 @@
 import android.app.backup.BackupManager;
 import android.content.Context;
 import android.service.dreams.IDreamManager;
+import android.view.Display;
 
 import androidx.annotation.Nullable;
 
@@ -64,9 +65,9 @@
 import com.android.systemui.demomode.dagger.DemoModeModule;
 import com.android.systemui.deviceentry.DeviceEntryModule;
 import com.android.systemui.display.DisplayModule;
+import com.android.systemui.display.data.repository.PerDisplayRepository;
 import com.android.systemui.doze.dagger.DozeComponent;
 import com.android.systemui.dreams.dagger.DreamModule;
-import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.flags.FlagDependenciesModule;
 import com.android.systemui.flags.FlagsModule;
@@ -86,7 +87,6 @@
 import com.android.systemui.mediaprojection.appselector.MediaProjectionActivitiesModule;
 import com.android.systemui.mediaprojection.taskswitcher.MediaProjectionTaskSwitcherModule;
 import com.android.systemui.mediarouter.MediaRouterModule;
-import com.android.systemui.model.SceneContainerPlugin;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.motiontool.MotionToolModule;
 import com.android.systemui.navigationbar.NavigationBarComponent;
@@ -113,7 +113,6 @@
 import com.android.systemui.screenrecord.ScreenRecordModule;
 import com.android.systemui.screenshot.dagger.ScreenshotModule;
 import com.android.systemui.security.data.repository.SecurityRepositoryModule;
-import com.android.systemui.settings.DisplayTracker;
 import com.android.systemui.settings.UserTracker;
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.shade.ShadeDisplayAwareModule;
@@ -289,7 +288,8 @@
         UtilModule.class,
         NoteTaskModule.class,
         WalletModule.class,
-        LowLightModule.class
+        LowLightModule.class,
+        PerDisplayRepositoriesModule.class
 },
         subcomponents = {
                 ComplicationComponent.class,
@@ -326,12 +326,8 @@
     @SysUISingleton
     @Provides
     static SysUiState provideSysUiState(
-            DisplayTracker displayTracker,
-            DumpManager dumpManager,
-            SceneContainerPlugin sceneContainerPlugin) {
-        final SysUiState state = new SysUiState(displayTracker, sceneContainerPlugin);
-        dumpManager.registerDumpable(state);
-        return state;
+            PerDisplayRepository<SysUiState> repository) {
+        return repository.get(Display.DEFAULT_DISPLAY);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/development/domain/interactor/BuildNumberInteractor.kt b/packages/SystemUI/src/com/android/systemui/development/domain/interactor/BuildNumberInteractor.kt
index fa5556d..cedd516 100644
--- a/packages/SystemUI/src/com/android/systemui/development/domain/interactor/BuildNumberInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/development/domain/interactor/BuildNumberInteractor.kt
@@ -23,6 +23,7 @@
 import android.os.UserHandle
 import com.android.internal.R as InternalR
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.development.data.repository.DevelopmentSettingRepository
@@ -32,9 +33,12 @@
 import com.android.systemui.user.utils.UserScopedService
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.SharingStarted.Companion.WhileSubscribed
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.flatMapConcat
 import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
 import kotlinx.coroutines.withContext
 
 @SysUISingleton
@@ -46,6 +50,7 @@
     private val userRepository: UserRepository,
     private val clipboardManagerProvider: UserScopedService<ClipboardManager>,
     @Background private val backgroundDispatcher: CoroutineDispatcher,
+    @Application private val applicationScope: CoroutineScope,
 ) {
 
     /**
@@ -53,10 +58,11 @@
      *
      * @see DevelopmentSettingRepository.isDevelopmentSettingEnabled
      */
-    val buildNumber: Flow<BuildNumber?> =
+    val buildNumber: StateFlow<BuildNumber?> =
         userRepository.selectedUserInfo
             .flatMapConcat { userInfo -> repository.isDevelopmentSettingEnabled(userInfo) }
             .map { enabled -> buildText.takeIf { enabled } }
+            .stateIn(applicationScope, WhileSubscribed(), null)
 
     private val buildText =
         BuildNumber(
diff --git a/packages/SystemUI/src/com/android/systemui/development/ui/viewmodel/BuildNumberViewModel.kt b/packages/SystemUI/src/com/android/systemui/development/ui/viewmodel/BuildNumberViewModel.kt
index 68c51ea..31d0471 100644
--- a/packages/SystemUI/src/com/android/systemui/development/ui/viewmodel/BuildNumberViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/development/ui/viewmodel/BuildNumberViewModel.kt
@@ -41,7 +41,6 @@
     val buildNumber: BuildNumber? by
         hydrator.hydratedStateOf(
             traceName = "buildNumber",
-            initialValue = null,
             source = buildNumberInteractor.buildNumber,
         )
 
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
index f4d256a5..d912b6a 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayScopeRepository.kt
@@ -53,7 +53,7 @@
     }
 
     override fun start() {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
         backgroundApplicationScope.launch {
             displayRepository.displayRemovalEvent.collect { displayId ->
                 val scope = perDisplayScopes.remove(displayId)
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/FakePerDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/FakePerDisplayRepository.kt
new file mode 100644
index 0000000..083191c
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/FakePerDisplayRepository.kt
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+class FakePerDisplayRepository<T> : PerDisplayRepository<T> {
+
+    private val instances = mutableMapOf<Int, T>()
+
+    fun add(displayId: Int, instance: T) {
+        instances[displayId] = instance
+    }
+
+    fun remove(displayId: Int) {
+        instances.remove(displayId)
+    }
+
+    override fun get(displayId: Int): T? {
+        return instances[displayId]
+    }
+
+    override val displayIds: Set<Int>
+        get() = instances.keys
+
+    override val debugName: String
+        get() = "FakePerDisplayRepository"
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayRepository.kt
new file mode 100644
index 0000000..d27e33e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayRepository.kt
@@ -0,0 +1,220 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.display.data.repository
+
+import android.util.Log
+import android.view.Display
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.app.tracing.traceSection
+import com.android.systemui.Dumpable
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dump.DumpManager
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import java.io.PrintWriter
+import java.util.concurrent.ConcurrentHashMap
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.collectLatest
+
+/**
+ * Used to create instances of type `T` for a specific display.
+ *
+ * This is useful for resources or objects that need to be managed independently for each connected
+ * display (e.g., UI state, rendering contexts, or display-specific configurations).
+ *
+ * Note that in most cases this can be implemented by a simple `@AssistedFactory` with `displayId`
+ * parameter
+ *
+ * ```kotlin
+ * class SomeType @AssistedInject constructor(@Assisted displayId: Int,..)
+ *      @AssistedFactory
+ *      interface Factory {
+ *         fun create(displayId: Int): SomeType
+ *      }
+ *  }
+ * ```
+ *
+ * Then it can be used to create a [PerDisplayRepository] as follows:
+ * ```kotlin
+ * // Injected:
+ * val repositoryFactory: PerDisplayRepositoryImpl.Factory
+ * val instanceFactory: PerDisplayRepositoryImpl.Factory
+ * // repository creation:
+ * repositoryFactory.create(instanceFactory::create)
+ * ```
+ *
+ * @see PerDisplayRepository For how to retrieve and manage instances created by this factory.
+ */
+fun interface PerDisplayInstanceProvider<T> {
+    /** Creates an instance for a display. */
+    fun createInstance(displayId: Int): T?
+}
+
+/**
+ * Extends [PerDisplayInstanceProvider], adding support for destroying the instance.
+ *
+ * This is useful for releasing resources associated with a display when it is disconnected or when
+ * the per-display instance is no longer needed.
+ */
+interface PerDisplayInstanceProviderWithTeardown<T> : PerDisplayInstanceProvider<T> {
+    /** Destroys a previously created instance of `T` forever. */
+    fun destroyInstance(instance: T)
+}
+
+/**
+ * Provides access to per-display instances of type `T`.
+ *
+ * Acts as a repository, managing the caching and retrieval of instances created by a
+ * [PerDisplayInstanceProvider]. It ensures that only one instance of `T` exists per display ID.
+ */
+interface PerDisplayRepository<T> {
+    /** Gets the cached instance or create a new one for a given display. */
+    operator fun get(displayId: Int): T?
+
+    /** List of display ids for which this repository has an instance. */
+    val displayIds: Set<Int>
+
+    /** Debug name for this repository, mainly for tracing and logging. */
+    val debugName: String
+}
+
+/**
+ * Default implementation of [PerDisplayRepository].
+ *
+ * This class manages a cache of per-display instances of type `T`, creating them using a provided
+ * [PerDisplayInstanceProvider] and optionally tearing them down using a
+ * [PerDisplayInstanceProviderWithTeardown] when displays are disconnected.
+ *
+ * It listens to the [DisplayRepository] to detect when displays are added or removed, and
+ * automatically manages the lifecycle of the per-display instances.
+ *
+ * Note that this is a [PerDisplayStoreImpl] 2.0 that doesn't require [CoreStartable] bindings,
+ * providing all args in the constructor.
+ */
+class PerDisplayInstanceRepositoryImpl<T>
+@AssistedInject
+constructor(
+    @Assisted override val debugName: String,
+    @Assisted private val instanceProvider: PerDisplayInstanceProvider<T>,
+    @Background private val backgroundApplicationScope: CoroutineScope,
+    private val displayRepository: DisplayRepository,
+    private val dumpManager: DumpManager,
+) : PerDisplayRepository<T>, Dumpable {
+
+    private val perDisplayInstances = ConcurrentHashMap<Int, T?>()
+
+    init {
+        backgroundApplicationScope.launch("$debugName#start") { start() }
+    }
+
+    override val displayIds: Set<Int>
+        get() = perDisplayInstances.keys
+
+    private suspend fun start() {
+        dumpManager.registerNormalDumpable("PerDisplayRepository-${debugName}", this)
+        displayRepository.displayIds.collectLatest { displayIds ->
+            val toRemove = perDisplayInstances.keys - displayIds
+            toRemove.forEach { displayId ->
+                Log.d(TAG, "<$debugName> destroying instance for displayId=$displayId.")
+                perDisplayInstances.remove(displayId)?.let { instance ->
+                    (instanceProvider as? PerDisplayInstanceProviderWithTeardown)?.destroyInstance(
+                        instance
+                    )
+                }
+            }
+        }
+    }
+
+    override fun get(displayId: Int): T? {
+        if (displayRepository.getDisplay(displayId) == null) {
+            Log.e(TAG, "<$debugName: Display with id $displayId doesn't exist.")
+            return null
+        }
+
+        // If it doesn't exist, create it and put it in the map.
+        return perDisplayInstances.computeIfAbsent(displayId) { key ->
+            Log.d(TAG, "<$debugName> creating instance for displayId=$key, as it wasn't available.")
+            val instance =
+                traceSection({ "creating instance of $debugName for displayId=$key" }) {
+                    instanceProvider.createInstance(key)
+                }
+            if (instance == null) {
+                Log.e(
+                    TAG,
+                    "<$debugName> returning null because createInstance($key) returned null.",
+                )
+            }
+            instance
+        }
+    }
+
+    @AssistedFactory
+    interface Factory<T> {
+        fun create(
+            debugName: String,
+            instanceProvider: PerDisplayInstanceProvider<T>,
+        ): PerDisplayInstanceRepositoryImpl<T>
+    }
+
+    companion object {
+        private const val TAG = "PerDisplayInstanceRepo"
+    }
+
+    override fun dump(pw: PrintWriter, args: Array<out String>) {
+        pw.println(perDisplayInstances)
+    }
+}
+
+/**
+ * Provides an instance of a given class **only** for the default display, even if asked for another
+ * display.
+ *
+ * This is useful in case of **flag refactors**: it can be provided instead of an instance of
+ * [PerDisplayInstanceRepositoryImpl] when a flag related to multi display refactoring is off.
+ *
+ * Note that this still requires all instances to be provided by a [PerDisplayInstanceProvider]. If
+ * you want to provide an existing instance instead for the default display, either implement it in
+ * a custom [PerDisplayInstanceProvider] (e.g. inject it in the constructor and return it if the
+ * displayId is zero), or use [SingleInstanceRepositoryImpl].
+ */
+class DefaultDisplayOnlyInstanceRepositoryImpl<T>(
+    override val debugName: String,
+    private val instanceProvider: PerDisplayInstanceProvider<T>,
+) : PerDisplayRepository<T> {
+    private val lazyDefaultDisplayInstance by lazy {
+        instanceProvider.createInstance(Display.DEFAULT_DISPLAY)
+    }
+    override val displayIds: Set<Int> = setOf(Display.DEFAULT_DISPLAY)
+
+    override fun get(displayId: Int): T? = lazyDefaultDisplayInstance
+}
+
+/**
+ * Always returns [instance] for any display.
+ *
+ * This can be used to provide a single instance based on a flag value during a refactor. Similar to
+ * [DefaultDisplayOnlyInstanceRepositoryImpl], but also avoids creating the
+ * [PerDisplayInstanceProvider]. This is useful when you want to provide an existing instance only,
+ * without even instantiating a [PerDisplayInstanceProvider].
+ */
+class SingleInstanceRepositoryImpl<T>(override val debugName: String, private val instance: T) :
+    PerDisplayRepository<T> {
+    override val displayIds: Set<Int> = setOf(Display.DEFAULT_DISPLAY)
+
+    override fun get(displayId: Int): T? = instance
+}
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
index 564588c..4604886 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/PerDisplayStore.kt
@@ -26,6 +26,7 @@
 import kotlinx.coroutines.CoroutineScope
 
 /** Provides per display instances of [T]. */
+@Deprecated("Use PerDisplayInstanceProvider<T> instead")
 interface PerDisplayStore<T> {
 
     /**
@@ -43,12 +44,13 @@
     fun forDisplay(displayId: Int): T?
 }
 
+@Deprecated("Use PerDisplayRepository<T> instead")
 abstract class PerDisplayStoreImpl<T>(
     @Background private val backgroundApplicationScope: CoroutineScope,
     private val displayRepository: DisplayRepository,
 ) : PerDisplayStore<T>, CoreStartable {
 
-    private val perDisplayInstances = ConcurrentHashMap<Int, T>()
+    protected val perDisplayInstances = ConcurrentHashMap<Int, T>()
 
     /**
      * The instance for the default/main display of the device. For example, on a phone or a tablet,
@@ -106,6 +108,11 @@
      * Will be called when the display associated with [instance] was removed. It allows to perform
      * any clean up if needed.
      */
+    @Deprecated(
+        "Use PerDisplayInstanceProviderWithTeardown instead, and let " +
+            "PerDisplayInstanceRepositoryImpl decide when to destroy the instance (e.g. on " +
+            "display removal or other conditions."
+    )
     open suspend fun onDisplayRemovalAction(instance: T) {}
 
     override fun dump(pw: PrintWriter, args: Array<out String>) {
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
index 12718e8b..9edd9dc 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeSensors.java
@@ -94,6 +94,7 @@
 public class DozeSensors {
     private static final String TAG = "DozeSensors";
     private static final UiEventLogger UI_EVENT_LOGGER = new UiEventLoggerImpl();
+    private static final String KEY_DOZE_PULSE_ON_AUTH = "doze_pulse_on_auth";
 
     private final AsyncSensorManager mSensorManager;
     private final AmbientDisplayConfiguration mConfig;
@@ -241,7 +242,7 @@
                 ),
                 new TriggerSensor(
                         findSensor(config.udfpsLongPressSensorType()),
-                        "doze_pulse_on_auth",
+                        KEY_DOZE_PULSE_ON_AUTH,
                         true /* settingDef */,
                         udfpsLongPressConfigured(),
                         DozeLog.REASON_SENSOR_UDFPS_LONG_PRESS,
@@ -421,6 +422,18 @@
                     && (!s.mRequiresTouchscreen || mListeningTouchScreenSensors)
                     && (!s.mRequiresProx || mListeningProxSensors)
                     && (!s.mRequiresAod || mListeningAodOnlySensors);
+
+            //AOD might be turned off in visual because of BetterySaver or isAlwaysOnSuppressed(),
+            //but AOD isn't really turned off, in these cases, udfpsLongPressSensor should be
+            //unregistered.
+            if (!mListeningAodOnlySensors && KEY_DOZE_PULSE_ON_AUTH.equals(s.mSetting)) {
+                if (mConfig.alwaysOnEnabled(mSelectedUserInteractor.getSelectedUserId())
+                        && !mConfig.screenOffUdfpsEnabled(
+                        mSelectedUserInteractor.getSelectedUserId())) {
+                    listen = false;
+                }
+            }
+
             s.setListening(listen);
             if (listen) {
                 anyListening = true;
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
index d81949d..c17094b 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/AssistantAttentionCondition.java
@@ -63,7 +63,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
index c7fe1e1..fb4ed14 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/conditions/DreamCondition.java
@@ -63,7 +63,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt b/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
index 4d89a82..293461d 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
+++ b/packages/SystemUI/src/com/android/systemui/flags/RefactorFlagUtils.kt
@@ -86,12 +86,13 @@
      * Example usage:
      * ```
      * public void setSomeNewController(SomeController someController) {
-     *     SomeRefactor.assertInNewMode();
+     *     SomeRefactor.unsafeAssertInNewMode();
      *     mSomeController = someController;
      * }
      * ````
      */
-    inline fun assertInNewMode(isEnabled: Boolean, flagName: Any) =
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode(isEnabled: Boolean, flagName: Any) =
         check(isEnabled) { "New code path not supported when $flagName is disabled." }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
index 54e27a6..04a0630 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/ShortcutCustomizationDialogStarter.kt
@@ -88,10 +88,7 @@
     private fun createDialog(): Dialog {
         return dialogFactory.create(dialogDelegate = ShortcutCustomizationDialogDelegate()) { dialog
             ->
-            val uiState by
-                viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle(
-                    initialValue = ShortcutCustomizationUiState.Inactive
-                )
+            val uiState by viewModel.shortcutCustomizationUiState.collectAsStateWithLifecycle()
             val coroutineScope = rememberCoroutineScope()
             ShortcutCustomizationDialog(
                 uiState = uiState,
diff --git a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
index 7e0fa2f..c601e6e 100644
--- a/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyboard/shortcut/ui/composable/ShortcutCustomizer.kt
@@ -409,6 +409,7 @@
         color = MaterialTheme.colorScheme.onSurface,
         lineHeight = 32.sp,
         fontWeight = FontWeight.W400,
+        textAlign = TextAlign.Center,
     )
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt
index 1febc79..bc65ad4 100644
--- a/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandler.kt
@@ -42,7 +42,7 @@
 
         when (event.keyCode) {
             KeyEvent.KEYCODE_BACK -> {
-                if (event.handleAction()) {
+                if (!backActionInteractor.isBackCallbackRegistered() && event.handleAction()) {
                     backActionInteractor.onBackRequested()
                 }
                 return true
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index b4b3053..d8fc21a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -1847,6 +1847,7 @@
         // explicitly DO NOT want to call
         // mKeyguardViewControllerLazy.get().setKeyguardGoingAwayState(false)
         // here, since that will mess with the device lock state.
+        mKeyguardStateController.notifyKeyguardGoingAway(false);
         mUpdateMonitor.dispatchKeyguardGoingAway(false);
 
         notifyStartedGoingToSleep();
@@ -2994,7 +2995,6 @@
                 startKeyguardTransition(showing, aodShowing);
             } else {
                 try {
-
                     mActivityTaskManagerService.setLockScreenShown(showing, aodShowing);
                 } catch (RemoteException ignored) {
                 }
@@ -3650,30 +3650,33 @@
             return;
         }
 
-        try {
-            int flags = KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS
-                    | KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
+        int flags = KEYGUARD_GOING_AWAY_FLAG_NO_WINDOW_ANIMATIONS
+                | KEYGUARD_GOING_AWAY_FLAG_WITH_WALLPAPER;
 
-            // If we are unlocking to the launcher, clear the snapshot so that any changes as part
-            // of the in-window animations are reflected. This is needed even if we're not actually
-            // playing in-window animations for this particular unlock since a previous unlock might
-            // have changed the Launcher state.
-            if (mKeyguardUnlockAnimationControllerLazy.get().isSupportedLauncherUnderneath()) {
-                flags |= KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
-            }
+        // If we are unlocking to the launcher, clear the snapshot so that any changes as part
+        // of the in-window animations are reflected. This is needed even if we're not actually
+        // playing in-window animations for this particular unlock since a previous unlock might
+        // have changed the Launcher state.
+        if (mKeyguardUnlockAnimationControllerLazy.get().isSupportedLauncherUnderneath()) {
+            flags |= KEYGUARD_GOING_AWAY_FLAG_TO_LAUNCHER_CLEAR_SNAPSHOT;
+        }
 
-            mKeyguardStateController.notifyKeyguardGoingAway(true);
+        mKeyguardStateController.notifyKeyguardGoingAway(true);
 
-            if (!KeyguardWmStateRefactor.isEnabled()) {
-                // Handled in WmLockscreenVisibilityManager.
-                mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId();
+        if (!KeyguardWmStateRefactor.isEnabled()) {
+            // Handled in WmLockscreenVisibilityManager.
+            mGoingAwayRequestedForUserId = mSelectedUserInteractor.getSelectedUserId();
+            final int goingAwayFlags = flags;
+            mUiBgExecutor.execute(() -> {
                 Log.d(TAG, "keyguardGoingAway requested for userId: "
                         + mGoingAwayRequestedForUserId);
-                mActivityTaskManagerService.keyguardGoingAway(flags);
-            }
-        } catch (RemoteException e) {
-            mSurfaceBehindRemoteAnimationRequested = false;
-            Log.e(TAG, "Failed to report keyguardGoingAway", e);
+                try {
+                    mActivityTaskManagerService.keyguardGoingAway(goingAwayFlags);
+                } catch (RemoteException e) {
+                    mSurfaceBehindRemoteAnimationRequested = false;
+                    Log.e(TAG, "Failed to report keyguardGoingAway", e);
+                }
+            });
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
index 2c5bacb..70e2413 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivity.java
@@ -196,6 +196,9 @@
             confirmCredentialIntent.putExtra(Intent.EXTRA_INTENT, target.getIntentSender());
         }
 
+        String packageName = getIntent().getStringExtra(Intent.EXTRA_PACKAGE_NAME);
+        confirmCredentialIntent.putExtra(Intent.EXTRA_PACKAGE_NAME, packageName);
+
         // WorkLockActivity is started as a task overlay, so unless credential confirmation is also
         // started as an overlay, it won't be visible.
         final ActivityOptions launchOptions = ActivityOptions.makeBasic();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt
index f11ebee..07ed194 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/quickaffordance/DoNotDisturbQuickAffordanceConfig.kt
@@ -98,7 +98,7 @@
     private var settingsValue: Int = 0
 
     private val isAvailable: StateFlow<Boolean> by lazy {
-        ModesUi.assertInNewMode()
+        ModesUi.unsafeAssertInNewMode()
         interactor.isZenAvailable.stateIn(
             scope = backgroundScope,
             started = SharingStarted.Eagerly,
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index acb98ed..affcd33 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -662,12 +662,12 @@
     }
 
     override fun setShowKeyguardWhenReenabled(isShowKeyguardWhenReenabled: Boolean) {
-        SceneContainerFlag.assertInNewMode()
+        SceneContainerFlag.unsafeAssertInNewMode()
         this.isShowKeyguardWhenReenabled = isShowKeyguardWhenReenabled
     }
 
     override fun isShowKeyguardWhenReenabled(): Boolean {
-        SceneContainerFlag.assertInNewMode()
+        SceneContainerFlag.unsafeAssertInNewMode()
         return isShowKeyguardWhenReenabled
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt
index 0b587ae..c031b53 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerUdfpsViewBinder.kt
@@ -38,9 +38,15 @@
         view.repeatWhenAttached {
             repeatOnLifecycle(Lifecycle.State.STARTED) {
                 view.alpha = 0f
+
                 launch("$TAG#viewModel.accessibilityDelegateHint") {
                     viewModel.accessibilityDelegateHint.collect { hint ->
                         view.accessibilityHintType = hint
+                        if (hint != DeviceEntryIconView.AccessibilityHintType.NONE) {
+                            view.setOnClickListener { viewModel.onTapped() }
+                        } else {
+                            view.setOnClickListener(null)
+                        }
                     }
                 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt
index acd381e..9038922 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerUdfpsIconViewModel.kt
@@ -18,6 +18,7 @@
 
 import android.content.Context
 import com.android.settingslib.Utils
+import com.android.systemui.accessibility.domain.interactor.AccessibilityInteractor
 import com.android.systemui.biometrics.domain.interactor.FingerprintPropertyInteractor
 import com.android.systemui.biometrics.domain.interactor.UdfpsOverlayInteractor
 import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
@@ -26,6 +27,7 @@
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.shared.recents.utilities.Utilities.clamp
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
@@ -46,6 +48,8 @@
     fingerprintPropertyInteractor: FingerprintPropertyInteractor,
     udfpsOverlayInteractor: UdfpsOverlayInteractor,
     alternateBouncerViewModel: AlternateBouncerViewModel,
+    private val statusBarKeyguardViewManager: StatusBarKeyguardViewManager,
+    private val accessibilityInteractor: AccessibilityInteractor,
 ) {
     private val isSupported: Flow<Boolean> = deviceEntryUdfpsInteractor.isUdfpsSupported
     val alpha: Flow<Float> =
@@ -74,7 +78,15 @@
             }
         }
     val accessibilityDelegateHint: Flow<DeviceEntryIconView.AccessibilityHintType> =
-        flowOf(DeviceEntryIconView.AccessibilityHintType.ENTER)
+        accessibilityInteractor.isEnabled.flatMapLatest { touchExplorationEnabled ->
+            flowOf(
+                if (touchExplorationEnabled) {
+                    DeviceEntryIconView.AccessibilityHintType.BOUNCER
+                } else {
+                    DeviceEntryIconView.AccessibilityHintType.NONE
+                }
+            )
+        }
 
     private val fgIconColor: Flow<Int> =
         configurationInteractor.onAnyConfigurationChange
@@ -93,6 +105,10 @@
             )
         }
 
+    fun onTapped() {
+        statusBarKeyguardViewManager.showPrimaryBouncer(/* scrimmed */ true)
+    }
+
     val bgColor: Flow<Int> = deviceEntryBackgroundViewModel.color
     val bgAlpha: Flow<Float> = flowOf(1f)
 
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
index 1ca08fe..cff6511 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AlternateBouncerViewModel.kt
@@ -47,7 +47,7 @@
 
     /** Reports the alternate bouncer visible state if the scene container flag is enabled. */
     val isVisible: Flow<Boolean> =
-        alternateBouncerInteractor.get().isVisible.onEach { SceneContainerFlag.assertInNewMode() }
+        alternateBouncerInteractor.get().isVisible.onEach { SceneContainerFlag.unsafeAssertInNewMode() }
 
     /** Progress to a fully transitioned alternate bouncer. 1f represents fully transitioned. */
     val transitionToAlternateBouncerProgress: Flow<Float> =
diff --git a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
index 9fddbfb..a154694 100644
--- a/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
+++ b/packages/SystemUI/src/com/android/systemui/log/table/Diffable.kt
@@ -16,6 +16,11 @@
 
 package com.android.systemui.log.table
 
+import com.android.systemui.kairos.BuildScope
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.changes
+import com.android.systemui.kairos.effect
 import com.android.systemui.util.kotlin.pairwiseBy
 import kotlinx.coroutines.flow.Flow
 
@@ -184,3 +189,94 @@
         newVal
     }
 }
+
+/** See [logDiffsForTable(TableLogBuffer, String, T)]. */
+@ExperimentalKairosApi
+@JvmName("logIntDiffsForTable")
+fun BuildScope.logDiffsForTable(
+    intState: State<Int?>,
+    tableLogBuffer: TableLogBuffer,
+    columnPrefix: String = "",
+    columnName: String,
+) {
+    var isInitial = true
+    intState.observe { new ->
+        tableLogBuffer.logChange(columnPrefix, columnName, new, isInitial = isInitial)
+        isInitial = false
+    }
+}
+
+/**
+ * Each time the flow is updated with a new value, logs the differences between the previous value
+ * and the new value to the given [tableLogBuffer].
+ *
+ * The new value's [Diffable.logDiffs] method will be used to log the differences to the table.
+ *
+ * @param columnPrefix a prefix that will be applied to every column name that gets logged.
+ */
+@ExperimentalKairosApi
+fun <T : Diffable<T>> BuildScope.logDiffsForTable(
+    diffableState: State<T>,
+    tableLogBuffer: TableLogBuffer,
+    columnPrefix: String = "",
+) {
+    val initialValue = diffableState.sampleDeferred()
+    effect {
+        // Fully log the initial value to the table.
+        tableLogBuffer.logChange(columnPrefix, isInitial = true) { row ->
+            initialValue.value.logFull(row)
+        }
+    }
+    diffableState.changes.observe { newState ->
+        val prevState = diffableState.sample()
+        tableLogBuffer.logDiffs(columnPrefix, prevVal = prevState, newVal = newState)
+    }
+}
+
+/** See [logDiffsForTable(TableLogBuffer, String, T)]. */
+@ExperimentalKairosApi
+@JvmName("logBooleanDiffsForTable")
+fun BuildScope.logDiffsForTable(
+    booleanState: State<Boolean>,
+    tableLogBuffer: TableLogBuffer,
+    columnPrefix: String = "",
+    columnName: String,
+) {
+    var isInitial = true
+    booleanState.observe { new ->
+        tableLogBuffer.logChange(columnPrefix, columnName, new, isInitial = isInitial)
+        isInitial = false
+    }
+}
+
+/** See [logDiffsForTable(TableLogBuffer, String, T)]. */
+@ExperimentalKairosApi
+@JvmName("logStringDiffsForTable")
+fun BuildScope.logDiffsForTable(
+    stringState: State<String?>,
+    tableLogBuffer: TableLogBuffer,
+    columnPrefix: String = "",
+    columnName: String,
+) {
+    var isInitial = true
+    stringState.observe { new ->
+        tableLogBuffer.logChange(columnPrefix, columnName, new, isInitial = isInitial)
+        isInitial = false
+    }
+}
+
+/** See [logDiffsForTable(TableLogBuffer, String, T)]. */
+@ExperimentalKairosApi
+@JvmName("logListDiffsForTable")
+fun <T> BuildScope.logDiffsForTable(
+    listState: State<List<T>>,
+    tableLogBuffer: TableLogBuffer,
+    columnPrefix: String = "",
+    columnName: String,
+) {
+    var isInitial = true
+    listState.observe { new ->
+        tableLogBuffer.logChange(columnPrefix, columnName, new.toString(), isInitial = isInitial)
+        isInitial = false
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/DirectBootCondition.kt b/packages/SystemUI/src/com/android/systemui/lowlightclock/DirectBootCondition.kt
index 4c1da01..57d7098 100644
--- a/packages/SystemUI/src/com/android/systemui/lowlightclock/DirectBootCondition.kt
+++ b/packages/SystemUI/src/com/android/systemui/lowlightclock/DirectBootCondition.kt
@@ -54,7 +54,6 @@
         job?.cancel()
     }
 
-    override fun getStartStrategy(): Int {
-        return START_EAGERLY
-    }
+    override val startStrategy: Int
+        get() = START_EAGERLY
 }
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/ForceLowLightCondition.java b/packages/SystemUI/src/com/android/systemui/lowlightclock/ForceLowLightCondition.java
index 7f21d07..5ec81a9 100644
--- a/packages/SystemUI/src/com/android/systemui/lowlightclock/ForceLowLightCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/lowlightclock/ForceLowLightCondition.java
@@ -131,7 +131,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightCondition.java b/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightCondition.java
index e91be50..c1a24e7 100644
--- a/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/lowlightclock/LowLightCondition.java
@@ -54,7 +54,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         // As this condition keeps the lowlight sensor active, it should only run when needed.
         return START_WHEN_NEEDED;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/lowlightclock/ScreenSaverEnabledCondition.java b/packages/SystemUI/src/com/android/systemui/lowlightclock/ScreenSaverEnabledCondition.java
index fd6ce17..8157255 100644
--- a/packages/SystemUI/src/com/android/systemui/lowlightclock/ScreenSaverEnabledCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/lowlightclock/ScreenSaverEnabledCondition.java
@@ -70,7 +70,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaRecommendationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaRecommendationsInteractor.kt
deleted file mode 100644
index 0cb36ed..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaRecommendationsInteractor.kt
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.controls.domain.pipeline.interactor
-
-import android.content.Context
-import android.content.Intent
-import android.provider.Settings
-import android.util.Log
-import androidx.annotation.VisibleForTesting
-import com.android.internal.jank.InteractionJankMonitor
-import com.android.systemui.animation.Expandable
-import com.android.systemui.broadcast.BroadcastSender
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.media.controls.data.repository.MediaFilterRepository
-import com.android.systemui.media.controls.domain.pipeline.MediaDataProcessor
-import com.android.systemui.media.controls.shared.model.MediaRecModel
-import com.android.systemui.media.controls.shared.model.MediaRecommendationsModel
-import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
-import com.android.systemui.plugins.ActivityStarter
-import java.net.URISyntaxException
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-
-/** Encapsulates business logic for media recommendation */
-@SysUISingleton
-class MediaRecommendationsInteractor
-@Inject
-constructor(
-    @Application applicationScope: CoroutineScope,
-    @Application private val applicationContext: Context,
-    private val repository: MediaFilterRepository,
-    private val mediaDataProcessor: MediaDataProcessor,
-    private val broadcastSender: BroadcastSender,
-    private val activityStarter: ActivityStarter,
-) {
-
-    val recommendations: Flow<MediaRecommendationsModel> =
-        repository.smartspaceMediaData.map { toRecommendationsModel(it) }.distinctUntilChanged()
-
-    /** Indicates whether the recommendations card is active. */
-    val isActive: StateFlow<Boolean> =
-        repository.smartspaceMediaData
-            .map { it.isActive }
-            .distinctUntilChanged()
-            .stateIn(applicationScope, SharingStarted.WhileSubscribed(), false)
-
-    fun removeMediaRecommendations(key: String, dismissIntent: Intent?, delayMs: Long) {
-        mediaDataProcessor.dismissSmartspaceRecommendation(key, delayMs)
-        if (dismissIntent == null) {
-            Log.w(TAG, "Cannot create dismiss action click action: extras missing dismiss_intent.")
-            return
-        }
-
-        val className = dismissIntent.component?.className
-        if (className == EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME) {
-            // Dismiss the card Smartspace data through Smartspace trampoline activity.
-            applicationContext.startActivity(dismissIntent)
-        } else {
-            broadcastSender.sendBroadcast(dismissIntent)
-        }
-    }
-
-    fun startSettings() {
-        activityStarter.startActivity(SETTINGS_INTENT, /* dismissShade= */ true)
-    }
-
-    fun startClickIntent(expandable: Expandable, intent: Intent) {
-        if (shouldActivityOpenInForeground(intent)) {
-            // Request to unlock the device if the activity needs to be opened in foreground.
-            activityStarter.postStartActivityDismissingKeyguard(
-                intent,
-                0 /* delay */,
-                expandable.activityTransitionController(
-                    InteractionJankMonitor.CUJ_SHADE_APP_LAUNCH_FROM_MEDIA_PLAYER
-                ),
-            )
-        } else {
-            // Otherwise, open the activity in background directly.
-            applicationContext.startActivity(intent)
-        }
-    }
-
-    /** Returns if the action will open the activity in foreground. */
-    private fun shouldActivityOpenInForeground(intent: Intent): Boolean {
-        val intentString = intent.extras?.getString(EXTRAS_SMARTSPACE_INTENT) ?: return false
-        try {
-            val wrapperIntent = Intent.parseUri(intentString, Intent.URI_INTENT_SCHEME)
-            return wrapperIntent.getBooleanExtra(KEY_SMARTSPACE_OPEN_IN_FOREGROUND, false)
-        } catch (e: URISyntaxException) {
-            Log.wtf(TAG, "Failed to create intent from URI: $intentString")
-            e.printStackTrace()
-        }
-        return false
-    }
-
-    private fun toRecommendationsModel(data: SmartspaceMediaData): MediaRecommendationsModel {
-        val mediaRecs = ArrayList<MediaRecModel>()
-        data.recommendations.forEach {
-            with(it) { mediaRecs.add(MediaRecModel(intent, title, subtitle, icon, extras)) }
-        }
-        return with(data) {
-            MediaRecommendationsModel(
-                key = targetId,
-                uid = getUid(applicationContext),
-                packageName = packageName,
-                instanceId = instanceId,
-                appName = getAppName(applicationContext),
-                dismissIntent = dismissIntent,
-                areRecommendationsValid = isValid(),
-                mediaRecs = mediaRecs,
-            )
-        }
-    }
-
-    fun switchToMediaControl(packageName: String) {
-        repository.setMediaFromRecPackageName(packageName)
-    }
-
-    companion object {
-
-        private const val TAG = "MediaRecommendationsInteractor"
-
-        // TODO (b/237284176) : move AGSA reference out.
-        private const val EXTRAS_SMARTSPACE_INTENT =
-            "com.google.android.apps.gsa.smartspace.extra.SMARTSPACE_INTENT"
-        @VisibleForTesting
-        const val EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME =
-            "com.google.android.apps.gsa.staticplugins.opa.smartspace." +
-                "ExportedSmartspaceTrampolineActivity"
-
-        private const val KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND"
-
-        private val SETTINGS_INTENT = Intent(Settings.ACTION_MEDIA_CONTROLS_SETTINGS)
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaRecommendationsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaRecommendationsViewBinder.kt
deleted file mode 100644
index 4877d18..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/binder/MediaRecommendationsViewBinder.kt
+++ /dev/null
@@ -1,469 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.controls.ui.binder
-
-import android.app.WallpaperColors
-import android.content.Context
-import android.content.res.ColorStateList
-import android.content.res.Configuration
-import android.graphics.Bitmap
-import android.graphics.Color
-import android.graphics.Matrix
-import android.graphics.drawable.BitmapDrawable
-import android.graphics.drawable.ColorDrawable
-import android.graphics.drawable.Drawable
-import android.graphics.drawable.GradientDrawable
-import android.graphics.drawable.Icon
-import android.graphics.drawable.LayerDrawable
-import android.os.Trace
-import android.util.TypedValue
-import android.view.View
-import android.view.ViewGroup
-import androidx.appcompat.content.res.AppCompatResources
-import androidx.constraintlayout.widget.ConstraintSet
-import androidx.lifecycle.Lifecycle
-import androidx.lifecycle.lifecycleScope
-import androidx.lifecycle.repeatOnLifecycle
-import com.android.systemui.animation.Expandable
-import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.media.controls.shared.model.NUM_REQUIRED_RECOMMENDATIONS
-import com.android.systemui.media.controls.ui.animation.surfaceFromScheme
-import com.android.systemui.media.controls.ui.animation.textPrimaryFromScheme
-import com.android.systemui.media.controls.ui.animation.textSecondaryFromScheme
-import com.android.systemui.media.controls.ui.controller.MediaViewController
-import com.android.systemui.media.controls.ui.util.MediaArtworkHelper
-import com.android.systemui.media.controls.ui.view.RecommendationViewHolder
-import com.android.systemui.media.controls.ui.viewmodel.MediaRecViewModel
-import com.android.systemui.media.controls.ui.viewmodel.MediaRecommendationsViewModel
-import com.android.systemui.media.controls.ui.viewmodel.MediaRecsCardViewModel
-import com.android.systemui.monet.ColorScheme
-import com.android.systemui.monet.Style
-import com.android.systemui.plugins.FalsingManager
-import com.android.systemui.res.R
-import com.android.systemui.util.animation.TransitionLayout
-import kotlin.math.min
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.flow.collectLatest
-import com.android.app.tracing.coroutines.launchTraced as launch
-import kotlinx.coroutines.withContext
-
-private const val TAG = "MediaRecommendationsViewBinder"
-private const val MEDIA_REC_SCRIM_START_ALPHA = 0.15f
-private const val MEDIA_REC_SCRIM_END_ALPHA = 1.0f
-
-object MediaRecommendationsViewBinder {
-
-    /** Binds recommendations view holder to the given view-model */
-    fun bind(
-        viewHolder: RecommendationViewHolder,
-        viewModel: MediaRecommendationsViewModel,
-        mediaViewController: MediaViewController,
-        falsingManager: FalsingManager,
-        backgroundDispatcher: CoroutineDispatcher,
-        mainDispatcher: CoroutineDispatcher,
-    ) {
-        mediaViewController.recsConfigurationChangeListener = this::updateRecommendationsVisibility
-        val cardView = viewHolder.recommendations
-        cardView.repeatWhenAttached {
-            lifecycleScope.launch {
-                repeatOnLifecycle(Lifecycle.State.STARTED) {
-                    launch {
-                        viewModel.mediaRecsCard.collectLatest { viewModel ->
-                            viewModel?.let {
-                                bindRecsCard(
-                                    viewHolder,
-                                    it,
-                                    mediaViewController,
-                                    falsingManager,
-                                    backgroundDispatcher,
-                                    mainDispatcher,
-                                )
-                            }
-                        }
-                    }
-                }
-            }
-        }
-    }
-
-    suspend fun bindRecsCard(
-        viewHolder: RecommendationViewHolder,
-        viewModel: MediaRecsCardViewModel,
-        viewController: MediaViewController,
-        falsingManager: FalsingManager,
-        backgroundDispatcher: CoroutineDispatcher,
-        mainDispatcher: CoroutineDispatcher,
-    ) {
-        // Set up media control location and its listener.
-        viewModel.onLocationChanged(viewController.currentEndLocation)
-        viewController.locationChangeListener = viewModel.onLocationChanged
-
-        // Bind main card.
-        viewHolder.recommendations.contentDescription =
-            viewModel.contentDescription.invoke(viewController.isGutsVisible)
-
-        viewHolder.recommendations.setOnClickListener {
-            if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return@setOnClickListener
-            viewModel.onClicked(Expandable.fromView(it))
-        }
-
-        viewHolder.recommendations.setOnLongClickListener {
-            if (falsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY))
-                return@setOnLongClickListener true
-            if (!viewController.isGutsVisible) {
-                openGuts(viewHolder, viewModel, viewController)
-            } else {
-                closeGuts(viewHolder, viewModel, viewController)
-            }
-            return@setOnLongClickListener true
-        }
-
-        // Bind colors
-        val appIcon = viewModel.mediaRecs.first().appIcon
-        fetchAndUpdateColors(viewHolder, appIcon, backgroundDispatcher, mainDispatcher)
-        // Bind all recommendations.
-        bindRecommendationsList(
-            viewHolder,
-            viewModel.mediaRecs,
-            falsingManager,
-            backgroundDispatcher,
-            mainDispatcher,
-        )
-        updateRecommendationsVisibility(viewController, viewHolder.recommendations)
-
-        // Set visibility of recommendations.
-        val expandedSet: ConstraintSet = viewController.expandedLayout
-        val collapsedSet: ConstraintSet = viewController.collapsedLayout
-        viewHolder.mediaTitles.forEach {
-            setVisibleAndAlpha(expandedSet, it.id, viewModel.areTitlesVisible)
-            setVisibleAndAlpha(collapsedSet, it.id, viewModel.areTitlesVisible)
-        }
-        viewHolder.mediaSubtitles.forEach {
-            setVisibleAndAlpha(expandedSet, it.id, viewModel.areSubtitlesVisible)
-            setVisibleAndAlpha(collapsedSet, it.id, viewModel.areSubtitlesVisible)
-        }
-
-        bindRecommendationsGuts(viewHolder, viewModel, viewController, falsingManager)
-
-        viewController.refreshState()
-    }
-
-    private fun bindRecommendationsGuts(
-        viewHolder: RecommendationViewHolder,
-        viewModel: MediaRecsCardViewModel,
-        viewController: MediaViewController,
-        falsingManager: FalsingManager,
-    ) {
-        val gutsViewHolder = viewHolder.gutsViewHolder
-        val gutsViewModel = viewModel.gutsMenu
-
-        gutsViewHolder.gutsText.text = gutsViewModel.gutsText
-        gutsViewHolder.dismissText.visibility = View.VISIBLE
-        gutsViewHolder.dismiss.isEnabled = true
-        gutsViewHolder.dismiss.setOnClickListener {
-            if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return@setOnClickListener
-            closeGuts(viewHolder, viewModel, viewController)
-            gutsViewModel.onDismissClicked()
-        }
-
-        gutsViewHolder.cancelText.background = gutsViewModel.cancelTextBackground
-        gutsViewHolder.cancel.setOnClickListener {
-            if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-                closeGuts(viewHolder, viewModel, viewController)
-            }
-        }
-
-        gutsViewHolder.settings.setOnClickListener {
-            if (!falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-                gutsViewModel.onSettingsClicked.invoke()
-            }
-        }
-
-        gutsViewHolder.setDismissible(gutsViewModel.isDismissEnabled)
-    }
-
-    private suspend fun bindRecommendationsList(
-        viewHolder: RecommendationViewHolder,
-        mediaRecs: List<MediaRecViewModel>,
-        falsingManager: FalsingManager,
-        backgroundDispatcher: CoroutineDispatcher,
-        mainDispatcher: CoroutineDispatcher,
-    ) {
-        mediaRecs.forEachIndexed { index, mediaRecViewModel ->
-            if (index >= NUM_REQUIRED_RECOMMENDATIONS) return@forEachIndexed
-
-            val appIconView = viewHolder.mediaAppIcons[index]
-            appIconView.clearColorFilter()
-            appIconView.setImageDrawable(mediaRecViewModel.appIcon)
-
-            val mediaCoverContainer = viewHolder.mediaCoverContainers[index]
-            mediaCoverContainer.setOnClickListener {
-                if (falsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return@setOnClickListener
-                mediaRecViewModel.onClicked(Expandable.fromView(it), index)
-            }
-            mediaCoverContainer.setOnLongClickListener {
-                if (falsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY))
-                    return@setOnLongClickListener true
-                (it.parent as View).performLongClick()
-                return@setOnLongClickListener true
-            }
-
-            val mediaCover = viewHolder.mediaCoverItems[index]
-            bindRecommendationArtwork(
-                mediaCover.context,
-                viewHolder,
-                mediaRecViewModel,
-                index,
-                backgroundDispatcher,
-                mainDispatcher,
-            )
-            mediaCover.contentDescription = mediaRecViewModel.contentDescription
-
-            val title = viewHolder.mediaTitles[index]
-            title.text = mediaRecViewModel.title
-
-            val subtitle = viewHolder.mediaSubtitles[index]
-            subtitle.text = mediaRecViewModel.subtitle
-
-            val progressBar = viewHolder.mediaProgressBars[index]
-            progressBar.progress = mediaRecViewModel.progress
-            if (mediaRecViewModel.progress == 0) {
-                progressBar.visibility = View.GONE
-            }
-        }
-    }
-
-    private fun openGuts(
-        viewHolder: RecommendationViewHolder,
-        viewModel: MediaRecsCardViewModel,
-        mediaViewController: MediaViewController,
-    ) {
-        viewHolder.marquee(true, MediaViewController.GUTS_ANIMATION_DURATION)
-        mediaViewController.openGuts()
-        viewHolder.recommendations.contentDescription = viewModel.contentDescription.invoke(true)
-        viewModel.onLongClicked.invoke()
-    }
-
-    private fun closeGuts(
-        viewHolder: RecommendationViewHolder,
-        mediaRecsCardViewModel: MediaRecsCardViewModel,
-        mediaViewController: MediaViewController,
-    ) {
-        viewHolder.marquee(false, MediaViewController.GUTS_ANIMATION_DURATION)
-        mediaViewController.closeGuts(false)
-        viewHolder.recommendations.contentDescription =
-            mediaRecsCardViewModel.contentDescription.invoke(false)
-    }
-
-    private fun setVisibleAndAlpha(set: ConstraintSet, resId: Int, visible: Boolean) {
-        set.setVisibility(resId, if (visible) ConstraintSet.VISIBLE else ConstraintSet.GONE)
-        set.setAlpha(resId, if (visible) 1.0f else 0.0f)
-    }
-
-    fun updateRecommendationsVisibility(
-        mediaViewController: MediaViewController,
-        cardView: TransitionLayout,
-    ) {
-        val fittedRecsNum = getNumberOfFittedRecommendations(cardView.context)
-        val expandedSet = mediaViewController.expandedLayout
-        val collapsedSet = mediaViewController.collapsedLayout
-        val mediaCoverContainers = getMediaCoverContainers(cardView)
-        // Hide media cover that cannot fit in the recommendation card.
-        mediaCoverContainers.forEachIndexed { index, container ->
-            setVisibleAndAlpha(expandedSet, container.id, index < fittedRecsNum)
-            setVisibleAndAlpha(collapsedSet, container.id, index < fittedRecsNum)
-        }
-    }
-
-    private fun getMediaCoverContainers(cardView: TransitionLayout): List<ViewGroup> {
-        return listOf<ViewGroup>(
-            cardView.requireViewById(R.id.media_cover1_container),
-            cardView.requireViewById(R.id.media_cover2_container),
-            cardView.requireViewById(R.id.media_cover3_container),
-        )
-    }
-
-    private fun getNumberOfFittedRecommendations(context: Context): Int {
-        val res = context.resources
-        val config = res.configuration
-        val defaultDpWidth = res.getInteger(R.integer.default_qs_media_rec_width_dp)
-        val recCoverWidth =
-            (res.getDimensionPixelSize(R.dimen.qs_media_rec_album_width) +
-                res.getDimensionPixelSize(R.dimen.qs_media_info_spacing) * 2)
-
-        // On landscape, media controls should take half of the screen width.
-        val displayAvailableDpWidth =
-            if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
-                config.screenWidthDp / 2
-            } else {
-                config.screenWidthDp
-            }
-        val fittedNum =
-            if (displayAvailableDpWidth > defaultDpWidth) {
-                val recCoverDefaultWidth =
-                    res.getDimensionPixelSize(R.dimen.qs_media_rec_default_width)
-                recCoverDefaultWidth / recCoverWidth
-            } else {
-                val displayAvailableWidth =
-                    TypedValue.applyDimension(
-                            TypedValue.COMPLEX_UNIT_DIP,
-                            displayAvailableDpWidth.toFloat(),
-                            res.displayMetrics,
-                        )
-                        .toInt()
-                displayAvailableWidth / recCoverWidth
-            }
-        return min(fittedNum.toDouble(), NUM_REQUIRED_RECOMMENDATIONS.toDouble()).toInt()
-    }
-
-    private suspend fun bindRecommendationArtwork(
-        context: Context,
-        viewHolder: RecommendationViewHolder,
-        viewModel: MediaRecViewModel,
-        index: Int,
-        backgroundDispatcher: CoroutineDispatcher,
-        mainDispatcher: CoroutineDispatcher,
-    ) {
-        val traceCookie = viewHolder.hashCode()
-        val traceName = "MediaRecommendationsViewBinder#bindRecommendationArtwork"
-        Trace.beginAsyncSection(traceName, traceCookie)
-
-        // Capture width & height from views in foreground for artwork scaling in background
-        val width = context.resources.getDimensionPixelSize(R.dimen.qs_media_rec_album_width)
-        val height =
-            context.resources.getDimensionPixelSize(R.dimen.qs_media_rec_album_height_expanded)
-
-        withContext(backgroundDispatcher) {
-            val artwork =
-                getRecCoverBackground(
-                    context,
-                    viewModel.albumIcon,
-                    width,
-                    height,
-                    backgroundDispatcher,
-                )
-            withContext(mainDispatcher) {
-                val mediaCover = viewHolder.mediaCoverItems[index]
-                val coverMatrix = Matrix(mediaCover.imageMatrix)
-                coverMatrix.postScale(1.25f, 1.25f, 0.5f * width, 0.5f * height)
-                mediaCover.imageMatrix = coverMatrix
-                mediaCover.setImageDrawable(artwork)
-            }
-        }
-    }
-
-    /** Returns the recommendation album cover of [width]x[height] size. */
-    private suspend fun getRecCoverBackground(
-        context: Context,
-        icon: Icon?,
-        width: Int,
-        height: Int,
-        backgroundDispatcher: CoroutineDispatcher,
-    ): Drawable =
-        withContext(backgroundDispatcher) {
-            return@withContext MediaArtworkHelper.getWallpaperColor(
-                    context,
-                    backgroundDispatcher,
-                    icon,
-                    TAG,
-                )
-                ?.let { wallpaperColors ->
-                    addGradientToRecommendationAlbum(
-                        context,
-                        icon!!,
-                        ColorScheme(wallpaperColors, true, Style.CONTENT),
-                        width,
-                        height,
-                    )
-                } ?: ColorDrawable(Color.TRANSPARENT)
-        }
-
-    private fun addGradientToRecommendationAlbum(
-        context: Context,
-        artworkIcon: Icon,
-        mutableColorScheme: ColorScheme,
-        width: Int,
-        height: Int,
-    ): LayerDrawable {
-        // First try scaling rec card using bitmap drawable.
-        // If returns null, set drawable bounds.
-        val albumArt =
-            getScaledRecommendationCover(context, artworkIcon, width, height)
-                ?: MediaArtworkHelper.getScaledBackground(context, artworkIcon, width, height)
-        val gradient =
-            AppCompatResources.getDrawable(context, R.drawable.qs_media_rec_scrim)?.mutate()
-                as GradientDrawable
-        return MediaArtworkHelper.setUpGradientColorOnDrawable(
-            albumArt,
-            gradient,
-            mutableColorScheme,
-            MEDIA_REC_SCRIM_START_ALPHA,
-            MEDIA_REC_SCRIM_END_ALPHA,
-        )
-    }
-
-    /** Returns a [Drawable] of a given [artworkIcon] scaled to [width]x[height] size, . */
-    private fun getScaledRecommendationCover(
-        context: Context,
-        artworkIcon: Icon,
-        width: Int,
-        height: Int,
-    ): Drawable? {
-        check(width > 0) { "Width must be a positive number but was $width" }
-        check(height > 0) { "Height must be a positive number but was $height" }
-
-        return if (
-            artworkIcon.type == Icon.TYPE_BITMAP || artworkIcon.type == Icon.TYPE_ADAPTIVE_BITMAP
-        ) {
-            artworkIcon.bitmap?.let {
-                val bitmap = Bitmap.createScaledBitmap(it, width, height, false)
-                BitmapDrawable(context.resources, bitmap)
-            }
-        } else {
-            null
-        }
-    }
-
-    private suspend fun fetchAndUpdateColors(
-        viewHolder: RecommendationViewHolder,
-        appIcon: Drawable,
-        backgroundDispatcher: CoroutineDispatcher,
-        mainDispatcher: CoroutineDispatcher,
-    ) =
-        withContext(backgroundDispatcher) {
-            val colorScheme =
-                ColorScheme(WallpaperColors.fromDrawable(appIcon), /* darkTheme= */ true)
-            withContext(mainDispatcher) {
-                val backgroundColor = surfaceFromScheme(colorScheme)
-                val textPrimaryColor = textPrimaryFromScheme(colorScheme)
-                val textSecondaryColor = textSecondaryFromScheme(colorScheme)
-
-                viewHolder.cardTitle.setTextColor(textPrimaryColor)
-                viewHolder.recommendations.setBackgroundTintList(
-                    ColorStateList.valueOf(backgroundColor)
-                )
-
-                viewHolder.mediaTitles.forEach { it.setTextColor(textPrimaryColor) }
-                viewHolder.mediaSubtitles.forEach { it.setTextColor(textSecondaryColor) }
-                viewHolder.mediaProgressBars.forEach {
-                    it.progressTintList = ColorStateList.valueOf(textPrimaryColor)
-                }
-
-                viewHolder.gutsViewHolder.setColors(colorScheme)
-            }
-        }
-}
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 7b1ae57e..ac6343c 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
@@ -61,14 +61,12 @@
 import com.android.systemui.media.controls.shared.model.MediaData
 import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
 import com.android.systemui.media.controls.ui.binder.MediaControlViewBinder
-import com.android.systemui.media.controls.ui.binder.MediaRecommendationsViewBinder
 import com.android.systemui.media.controls.ui.util.MediaViewModelCallback
 import com.android.systemui.media.controls.ui.util.MediaViewModelListUpdateCallback
 import com.android.systemui.media.controls.ui.view.MediaCarouselScrollHandler
 import com.android.systemui.media.controls.ui.view.MediaHostState
 import com.android.systemui.media.controls.ui.view.MediaScrollView
 import com.android.systemui.media.controls.ui.view.MediaViewHolder
-import com.android.systemui.media.controls.ui.view.RecommendationViewHolder
 import com.android.systemui.media.controls.ui.viewmodel.MediaCarouselViewModel
 import com.android.systemui.media.controls.ui.viewmodel.MediaCommonViewModel
 import com.android.systemui.media.controls.util.MediaUiEventLogger
@@ -478,41 +476,10 @@
                     MediaPlayerData.isSwipedAway = false
                 }
 
-                override fun onSmartspaceMediaDataLoaded(
-                    key: String,
-                    data: SmartspaceMediaData,
-                    shouldPrioritize: Boolean,
-                ) {
-                    debugLogger.logRecommendationLoaded(key, data.isActive)
-                    // Log the case where the hidden media carousel with the existed inactive resume
-                    // media is shown by the Smartspace signal.
-                    if (data.isActive) {
-                        addSmartspaceMediaRecommendations(key, data, shouldPrioritize)
-                    } else {
-                        // Handle update to inactive as a removal
-                        onSmartspaceMediaDataRemoved(data.targetId, immediately = true)
-                    }
-                    MediaPlayerData.isSwipedAway = false
-                }
-
                 override fun onMediaDataRemoved(key: String, userInitiated: Boolean) {
                     debugLogger.logMediaRemoved(key, userInitiated)
                     removePlayer(key, userInitiated = userInitiated)
                 }
-
-                override fun onSmartspaceMediaDataRemoved(key: String, immediately: Boolean) {
-                    debugLogger.logRecommendationRemoved(key, immediately)
-                    if (immediately || isReorderingAllowed) {
-                        removePlayer(key)
-                        if (!immediately) {
-                            // Although it wasn't requested, we were able to process the removal
-                            // immediately since reordering is allowed. So, notify hosts to update
-                            updateHostVisibility()
-                        }
-                    } else {
-                        keysNeedRemoval.add(key)
-                    }
-                }
             }
         )
     }
@@ -655,22 +622,6 @@
                 mediaContent.addView(viewHolder.player, position)
                 controllerById[commonViewModel.instanceId.toString()] = viewController
             }
-            is MediaCommonViewModel.MediaRecommendations -> {
-                val viewHolder =
-                    RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent)
-                viewController.attachRecommendations(viewHolder)
-                viewController.recommendationViewHolder?.recommendations?.layoutParams = lp
-                MediaRecommendationsViewBinder.bind(
-                    viewHolder,
-                    commonViewModel.recsViewModel,
-                    viewController,
-                    falsingManager,
-                    backgroundDispatcher,
-                    mainDispatcher,
-                )
-                mediaContent.addView(viewHolder.recommendations, position)
-                controllerById[commonViewModel.key] = viewController
-            }
         }
         viewController.setListening(mediaCarouselScrollHandler.visibleToUser && currentlyExpanded)
         updateViewControllerToState(viewController, noAnimation = true)
@@ -695,21 +646,10 @@
     }
 
     private fun onRemoved(commonViewModel: MediaCommonViewModel) {
-        val id =
-            when (commonViewModel) {
-                is MediaCommonViewModel.MediaControl -> commonViewModel.instanceId.toString()
-                is MediaCommonViewModel.MediaRecommendations -> commonViewModel.key
-            }
+        val id = (commonViewModel as MediaCommonViewModel.MediaControl).instanceId.toString()
         controllerById.remove(id)?.let {
-            when (commonViewModel) {
-                is MediaCommonViewModel.MediaControl -> {
-                    mediaCarouselScrollHandler.onPrePlayerRemoved(it.mediaViewHolder!!.player)
-                    mediaContent.removeView(it.mediaViewHolder!!.player)
-                }
-                is MediaCommonViewModel.MediaRecommendations -> {
-                    mediaContent.removeView(it.recommendationViewHolder!!.recommendations)
-                }
-            }
+            mediaCarouselScrollHandler.onPrePlayerRemoved(it.mediaViewHolder!!.player)
+            mediaContent.removeView(it.mediaViewHolder!!.player)
             it.onDestroy()
             mediaCarouselScrollHandler.onPlayersChanged()
             updatePageIndicator()
@@ -718,21 +658,10 @@
     }
 
     private fun onMoved(commonViewModel: MediaCommonViewModel, from: Int, to: Int) {
-        val id =
-            when (commonViewModel) {
-                is MediaCommonViewModel.MediaControl -> commonViewModel.instanceId.toString()
-                is MediaCommonViewModel.MediaRecommendations -> commonViewModel.key
-            }
+        val id = (commonViewModel as MediaCommonViewModel.MediaControl).instanceId.toString()
         controllerById[id]?.let {
             mediaContent.removeViewAt(from)
-            when (commonViewModel) {
-                is MediaCommonViewModel.MediaControl -> {
-                    mediaContent.addView(it.mediaViewHolder!!.player, to)
-                }
-                is MediaCommonViewModel.MediaRecommendations -> {
-                    mediaContent.addView(it.recommendationViewHolder!!.recommendations, to)
-                }
-            }
+            mediaContent.addView(it.mediaViewHolder!!.player, to)
         }
         updatePageIndicator()
         mediaCarouselScrollHandler.onPlayersChanged()
@@ -746,11 +675,9 @@
         val viewIds =
             viewModels
                 .map { mediaCommonViewModel ->
-                    when (mediaCommonViewModel) {
-                        is MediaCommonViewModel.MediaControl ->
-                            mediaCommonViewModel.instanceId.toString()
-                        is MediaCommonViewModel.MediaRecommendations -> mediaCommonViewModel.key
-                    }
+                    (mediaCommonViewModel as MediaCommonViewModel.MediaControl)
+                        .instanceId
+                        .toString()
                 }
                 .toHashSet()
         controllerById
@@ -758,7 +685,6 @@
             .forEach {
                 mediaCarouselScrollHandler.onPrePlayerRemoved(it.value.mediaViewHolder?.player)
                 mediaContent.removeView(it.value.mediaViewHolder?.player)
-                mediaContent.removeView(it.value.recommendationViewHolder?.recommendations)
                 it.value.onDestroy()
                 mediaCarouselScrollHandler.onPlayersChanged()
                 updatePageIndicator()
@@ -808,9 +734,6 @@
         mediaContent.removeAllViews()
         for (mediaPlayer in MediaPlayerData.players()) {
             mediaPlayer.mediaViewHolder?.let { mediaContent.addView(it.player) }
-                ?: mediaPlayer.recommendationViewHolder?.let {
-                    mediaContent.addView(it.recommendations)
-                }
         }
         mediaCarouselScrollHandler.onPlayersChanged()
         mediaControlChipInteractor.updateMediaControlChipModelLegacy(
@@ -980,67 +903,6 @@
         return MediaViewHolder.create(LayoutInflater.from(context), mediaContent)
     }
 
-    private fun addSmartspaceMediaRecommendations(
-        key: String,
-        data: SmartspaceMediaData,
-        shouldPrioritize: Boolean,
-    ) =
-        traceSection("MediaCarouselController#addSmartspaceMediaRecommendations") {
-            if (DEBUG) Log.d(TAG, "Updating smartspace target in carousel")
-            MediaPlayerData.getMediaPlayer(key)?.let {
-                Log.w(TAG, "Skip adding smartspace target in carousel")
-                return
-            }
-
-            val existingSmartspaceMediaKey = MediaPlayerData.smartspaceMediaKey()
-            existingSmartspaceMediaKey?.let {
-                val removedPlayer =
-                    removePlayer(existingSmartspaceMediaKey, dismissMediaData = false)
-                removedPlayer?.run {
-                    debugLogger.logPotentialMemoryLeak(existingSmartspaceMediaKey)
-                    onDestroy()
-                }
-            }
-
-            val newRecs = mediaControlPanelFactory.get()
-            newRecs.attachRecommendation(
-                RecommendationViewHolder.create(LayoutInflater.from(context), mediaContent)
-            )
-            newRecs.mediaViewController.sizeChangedListener = this::updateCarouselDimensions
-            val lp =
-                LinearLayout.LayoutParams(
-                    ViewGroup.LayoutParams.MATCH_PARENT,
-                    ViewGroup.LayoutParams.WRAP_CONTENT,
-                )
-            newRecs.recommendationViewHolder?.recommendations?.setLayoutParams(lp)
-            newRecs.bindRecommendation(data)
-            val curVisibleMediaKey =
-                MediaPlayerData.visiblePlayerKeys()
-                    .elementAtOrNull(mediaCarouselScrollHandler.visibleMediaIndex)
-            MediaPlayerData.addMediaRecommendation(
-                key,
-                data,
-                newRecs,
-                shouldPrioritize,
-                systemClock,
-                debugLogger,
-            )
-            updateViewControllerToState(newRecs.mediaViewController, noAnimation = true)
-            reorderAllPlayers(curVisibleMediaKey)
-            updatePageIndicator()
-            mediaFrame.requiresRemeasuring = true
-            // Check postcondition: mediaContent should have the same number of children as there
-            // are elements in mediaPlayers.
-            if (MediaPlayerData.players().size != mediaContent.childCount) {
-                Log.e(
-                    TAG,
-                    "Size of players list and number of views in carousel are out of sync. " +
-                        "Players size is ${MediaPlayerData.players().size}. " +
-                        "View count is ${mediaContent.childCount}.",
-                )
-            }
-        }
-
     fun removePlayer(
         key: String,
         dismissMediaData: Boolean = true,
@@ -1057,7 +919,6 @@
         return removed?.apply {
             mediaCarouselScrollHandler.onPrePlayerRemoved(removed.mediaViewHolder?.player)
             mediaContent.removeView(removed.mediaViewHolder?.player)
-            mediaContent.removeView(removed.recommendationViewHolder?.recommendations)
             removed.onDestroy()
             mediaCarouselScrollHandler.onPlayersChanged()
             mediaControlChipInteractor.updateMediaControlChipModelLegacy(
@@ -1095,31 +956,18 @@
         val mediaDataList = MediaPlayerData.mediaData()
         // Do not loop through the original list of media data because the re-addition of media data
         // is being executed in background thread.
-        mediaDataList.forEach { (key, data, isSsMediaRec) ->
-            if (isSsMediaRec) {
-                val smartspaceMediaData = MediaPlayerData.smartspaceMediaData
+        mediaDataList.forEach { (key, data, _) ->
+            val isSsReactivated = MediaPlayerData.isSsReactivated(key)
+            if (recreateMedia) {
                 removePlayer(key, dismissMediaData = false, dismissRecommendation = false)
-                smartspaceMediaData?.let {
-                    addSmartspaceMediaRecommendations(
-                        it.targetId,
-                        it,
-                        MediaPlayerData.shouldPrioritizeSs,
-                    )
-                }
-                onUiExecutionEnd.run()
-            } else {
-                val isSsReactivated = MediaPlayerData.isSsReactivated(key)
-                if (recreateMedia) {
-                    removePlayer(key, dismissMediaData = false, dismissRecommendation = false)
-                }
-                addOrUpdatePlayer(
-                    key = key,
-                    oldKey = null,
-                    data = data,
-                    isSsReactivated = isSsReactivated,
-                    onUiExecutionEnd = onUiExecutionEnd,
-                )
             }
+            addOrUpdatePlayer(
+                key = key,
+                oldKey = null,
+                data = data,
+                isSsReactivated = isSsReactivated,
+                onUiExecutionEnd = onUiExecutionEnd,
+            )
         }
     }
 
@@ -1129,12 +977,8 @@
         if (recreateMedia) {
             mediaContent.removeAllViews()
             commonViewModels.forEachIndexed { index, viewModel ->
-                when (viewModel) {
-                    is MediaCommonViewModel.MediaControl ->
-                        controllerById[viewModel.instanceId.toString()]?.onDestroy()
-                    is MediaCommonViewModel.MediaRecommendations ->
-                        controllerById[viewModel.key]?.onDestroy()
-                }
+                val mediaControlViewModel = (viewModel as MediaCommonViewModel.MediaControl)
+                controllerById[mediaControlViewModel.instanceId.toString()]?.onDestroy()
                 onAdded(viewModel, index, configChanged = true)
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt
index 5d62c02..3653891 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerLogger.kt
@@ -64,28 +64,6 @@
             { "removing player $str1, by user $bool1" },
         )
 
-    fun logRecommendationLoaded(key: String, isActive: Boolean) =
-        buffer.log(
-            TAG,
-            LogLevel.DEBUG,
-            {
-                str1 = key
-                bool1 = isActive
-            },
-            { "add recommendation $str1, active $bool1" },
-        )
-
-    fun logRecommendationRemoved(key: String, immediately: Boolean) =
-        buffer.log(
-            TAG,
-            LogLevel.DEBUG,
-            {
-                str1 = key
-                bool1 = immediately
-            },
-            { "removing recommendation $str1, immediate=$bool1" },
-        )
-
     fun logCarouselHidden() = buffer.log(TAG, LogLevel.DEBUG, {}, { "hiding carousel" })
 
     fun logCarouselVisible() = buffer.log(TAG, LogLevel.DEBUG, {}, { "showing carousel" })
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
index a6bf5f4..006eb20 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaControlPanel.java
@@ -22,7 +22,6 @@
 import static com.android.systemui.Flags.communalHub;
 import static com.android.systemui.Flags.mediaLockscreenLaunchAnimation;
 import static com.android.systemui.media.controls.domain.pipeline.MediaActionsKt.getNotificationActions;
-import static com.android.systemui.media.controls.shared.model.SmartspaceMediaDataKt.NUM_REQUIRED_RECOMMENDATIONS;
 import static com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.MEDIA_PLAYER_SCRIM_END_ALPHA;
 import static com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.MEDIA_PLAYER_SCRIM_END_ALPHA_LEGACY;
 import static com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel.MEDIA_PLAYER_SCRIM_START_ALPHA;
@@ -35,24 +34,17 @@
 import android.app.BroadcastOptions;
 import android.app.PendingIntent;
 import android.app.WallpaperColors;
-import android.app.smartspace.SmartspaceAction;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.content.res.Resources;
 import android.graphics.Bitmap;
 import android.graphics.BlendMode;
 import android.graphics.Color;
 import android.graphics.ColorMatrix;
 import android.graphics.ColorMatrixColorFilter;
-import android.graphics.Matrix;
 import android.graphics.Paint;
 import android.graphics.Rect;
 import android.graphics.drawable.Animatable;
-import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
@@ -69,14 +61,12 @@
 import android.text.TextUtils;
 import android.util.Log;
 import android.util.Pair;
-import android.util.TypedValue;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.animation.Interpolator;
 import android.widget.ImageButton;
 import android.widget.ImageView;
-import android.widget.SeekBar;
 import android.widget.TextView;
 
 import androidx.annotation.NonNull;
@@ -105,7 +95,6 @@
 import com.android.systemui.media.controls.shared.model.MediaButton;
 import com.android.systemui.media.controls.shared.model.MediaData;
 import com.android.systemui.media.controls.shared.model.MediaDeviceData;
-import com.android.systemui.media.controls.shared.model.SmartspaceMediaData;
 import com.android.systemui.media.controls.ui.animation.AnimationBindHandler;
 import com.android.systemui.media.controls.ui.animation.ColorSchemeTransition;
 import com.android.systemui.media.controls.ui.animation.MediaColorSchemesKt;
@@ -113,7 +102,6 @@
 import com.android.systemui.media.controls.ui.binder.SeekBarObserver;
 import com.android.systemui.media.controls.ui.view.GutsViewHolder;
 import com.android.systemui.media.controls.ui.view.MediaViewHolder;
-import com.android.systemui.media.controls.ui.view.RecommendationViewHolder;
 import com.android.systemui.media.controls.ui.viewmodel.SeekBarViewModel;
 import com.android.systemui.media.controls.util.MediaDataUtils;
 import com.android.systemui.media.controls.util.MediaUiEventLogger;
@@ -143,14 +131,12 @@
 import com.android.systemui.util.animation.TransitionLayout;
 import com.android.systemui.util.concurrency.DelayableExecutor;
 import com.android.systemui.util.settings.GlobalSettings;
-import com.android.systemui.util.time.SystemClock;
 
 import dagger.Lazy;
 
 import kotlin.Triple;
 import kotlin.Unit;
 
-import java.net.URISyntaxException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Random;
@@ -165,17 +151,6 @@
     protected static final String TAG = "MediaControlPanel";
 
     private static final float DISABLED_ALPHA = 0.38f;
-    private static final String EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME = "com.google"
-            + ".android.apps.gsa.staticplugins.opa.smartspace.ExportedSmartspaceTrampolineActivity";
-    private static final String EXTRAS_SMARTSPACE_INTENT =
-            "com.google.android.apps.gsa.smartspace.extra.SMARTSPACE_INTENT";
-    private static final String KEY_SMARTSPACE_ARTIST_NAME = "artist_name";
-    private static final String KEY_SMARTSPACE_OPEN_IN_FOREGROUND = "KEY_OPEN_IN_FOREGROUND";
-
-    private static final float REC_MEDIA_COVER_SCALE_FACTOR = 1.25f;
-    private static final float MEDIA_REC_SCRIM_START_ALPHA = 0.15f;
-    private static final float MEDIA_REC_SCRIM_END_ALPHA = 1.0f;
-
     private static final Intent SETTINGS_INTENT = new Intent(ACTION_MEDIA_CONTROLS_SETTINGS);
 
     // Buttons to show in small player when using semantic actions
@@ -215,17 +190,14 @@
 
     private Context mContext;
     private MediaViewHolder mMediaViewHolder;
-    private RecommendationViewHolder mRecommendationViewHolder;
     private String mKey;
     private MediaData mMediaData;
-    private SmartspaceMediaData mRecommendationData;
     private MediaViewController mMediaViewController;
     private MediaSession.Token mToken;
     private MediaController mController;
     private Lazy<MediaDataManager> mMediaDataManagerLazy;
     // Uid for the media app.
     protected int mUid = Process.INVALID_UID;
-    private int mSmartspaceMediaItemsCount;
     private MediaCarouselController mMediaCarouselController;
     private final MediaOutputDialogManager mMediaOutputDialogManager;
     private final FalsingManager mFalsingManager;
@@ -241,7 +213,6 @@
     private final NotificationLockscreenUserManager mLockscreenUserManager;
 
     // Used for logging.
-    private SystemClock mSystemClock;
     private MediaUiEventLogger mLogger;
     private InstanceId mInstanceId;
     private String mPackageName;
@@ -310,7 +281,6 @@
             MediaOutputDialogManager mediaOutputDialogManager,
             MediaCarouselController mediaCarouselController,
             FalsingManager falsingManager,
-            SystemClock systemClock,
             MediaUiEventLogger logger,
             KeyguardStateController keyguardStateController,
             ActivityIntentHelper activityIntentHelper,
@@ -330,7 +300,6 @@
         mMediaOutputDialogManager = mediaOutputDialogManager;
         mMediaCarouselController = mediaCarouselController;
         mFalsingManager = falsingManager;
-        mSystemClock = systemClock;
         mLogger = logger;
         mKeyguardStateController = keyguardStateController;
         mActivityIntentHelper = activityIntentHelper;
@@ -373,16 +342,6 @@
     }
 
     /**
-     * Get the recommendation view holder used to display Smartspace media recs.
-     *
-     * @return the recommendation view holder
-     */
-    @Nullable
-    public RecommendationViewHolder getRecommendationViewHolder() {
-        return mRecommendationViewHolder;
-    }
-
-    /**
      * Get the view controller used to display media controls
      *
      * @return the media view controller
@@ -465,7 +424,7 @@
         mSeekBarViewModel.attachTouchHandlers(vh.getSeekBar());
         mSeekBarViewModel.setScrubbingChangeListener(mScrubbingChangeListener);
         mSeekBarViewModel.setEnabledChangeListener(mEnabledChangeListener);
-        mMediaViewController.attach(player, MediaViewController.TYPE.PLAYER);
+        mMediaViewController.attach(player);
 
         vh.getPlayer().setOnLongClickListener(v -> {
             if (mFalsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)) return true;
@@ -522,26 +481,6 @@
         return result;
     }
 
-    /** Attaches the recommendations to the recommendation view holder. */
-    public void attachRecommendation(RecommendationViewHolder vh) {
-        mRecommendationViewHolder = vh;
-        TransitionLayout recommendations = vh.getRecommendations();
-
-        mMediaViewController.attach(recommendations, MediaViewController.TYPE.RECOMMENDATION);
-        mMediaViewController.configurationChangeListener = this::updateRecommendationsVisibility;
-
-        mRecommendationViewHolder.getRecommendations().setOnLongClickListener(v -> {
-            if (mFalsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)) return true;
-            if (!mMediaViewController.isGutsVisible()) {
-                openGuts();
-                return true;
-            } else {
-                closeGuts();
-                return true;
-            }
-        });
-    }
-
     /** Bind this player view based on the data given. */
     public void bindPlayer(@NonNull MediaData data, String key) {
         SceneContainerFlag.assertInLegacyMode();
@@ -868,24 +807,6 @@
         mMediaViewHolder.getPlayer().setContentDescription(contentDescription);
     }
 
-    private void bindRecommendationContentDescription(SmartspaceMediaData data) {
-        if (mRecommendationViewHolder == null) {
-            return;
-        }
-
-        CharSequence contentDescription;
-        if (mMediaViewController.isGutsVisible()) {
-            contentDescription =
-                    mRecommendationViewHolder.getGutsViewHolder().getGutsText().getText();
-        } else if (data != null) {
-            contentDescription = mContext.getString(R.string.controls_media_smartspace_rec_header);
-        } else {
-            contentDescription = null;
-        }
-
-        mRecommendationViewHolder.getRecommendations().setContentDescription(contentDescription);
-    }
-
     private void bindArtworkAndColors(MediaData data, String key, boolean updateBackground) {
         final int traceCookie = data.hashCode();
         final String traceName = "MediaControlPanel#bindArtworkAndColors<" + key + ">";
@@ -993,62 +914,6 @@
         });
     }
 
-    private void bindRecommendationArtwork(
-            SmartspaceAction recommendation,
-            String packageName,
-            int itemIndex
-    ) {
-        final int traceCookie = recommendation.hashCode();
-        final String traceName =
-                "MediaControlPanel#bindRecommendationArtwork<" + packageName + ">";
-        Trace.beginAsyncSection(traceName, traceCookie);
-
-        // Capture width & height from views in foreground for artwork scaling in background
-        int width = mContext.getResources().getDimensionPixelSize(R.dimen.qs_media_rec_album_width);
-        int height = mContext.getResources().getDimensionPixelSize(
-                R.dimen.qs_media_rec_album_height_expanded);
-
-        mBackgroundExecutor.execute(() -> {
-            // Album art
-            ColorScheme mutableColorScheme = null;
-            Drawable artwork;
-            Icon artworkIcon = recommendation.getIcon();
-            WallpaperColors wallpaperColors = getWallpaperColor(artworkIcon);
-            if (wallpaperColors != null) {
-                mutableColorScheme = new ColorScheme(wallpaperColors, true, Style.CONTENT);
-                artwork = addGradientToRecommendationAlbum(artworkIcon, mutableColorScheme, width,
-                        height);
-            } else {
-                artwork = new ColorDrawable(Color.TRANSPARENT);
-            }
-
-            mMainExecutor.execute(() -> {
-                // Bind the artwork drawable to media cover.
-                ImageView mediaCover =
-                        mRecommendationViewHolder.getMediaCoverItems().get(itemIndex);
-                // Rescale media cover
-                Matrix coverMatrix = new Matrix(mediaCover.getImageMatrix());
-                coverMatrix.postScale(REC_MEDIA_COVER_SCALE_FACTOR, REC_MEDIA_COVER_SCALE_FACTOR,
-                        0.5f * width, 0.5f * height);
-                mediaCover.setImageMatrix(coverMatrix);
-                mediaCover.setImageDrawable(artwork);
-
-                // Set up the app icon.
-                ImageView appIconView = mRecommendationViewHolder.getMediaAppIcons().get(itemIndex);
-                appIconView.clearColorFilter();
-                try {
-                    Drawable icon = mContext.getPackageManager()
-                            .getApplicationIcon(packageName);
-                    appIconView.setImageDrawable(icon);
-                } catch (PackageManager.NameNotFoundException e) {
-                    Log.w(TAG, "Cannot find icon for package " + packageName, e);
-                    appIconView.setImageResource(R.drawable.ic_music_note);
-                }
-                Trace.endAsyncSection(traceName, traceCookie);
-            });
-        });
-    }
-
     // This method should be called from a background thread. WallpaperColors.fromBitmap takes a
     // good amount of time. We do that work on the background executor to avoid stalling animations
     // on the UI Thread.
@@ -1088,21 +953,6 @@
                 MEDIA_PLAYER_SCRIM_START_ALPHA_LEGACY, MEDIA_PLAYER_SCRIM_END_ALPHA_LEGACY);
     }
 
-    @VisibleForTesting
-    protected LayerDrawable addGradientToRecommendationAlbum(Icon artworkIcon,
-            ColorScheme mutableColorScheme, int width, int height) {
-        // First try scaling rec card using bitmap drawable.
-        // If returns null, set drawable bounds.
-        Drawable albumArt = getScaledRecommendationCover(artworkIcon, width, height);
-        if (albumArt == null) {
-            albumArt = getScaledBackground(artworkIcon, width, height);
-        }
-        GradientDrawable gradient = (GradientDrawable) mContext.getDrawable(
-                R.drawable.qs_media_rec_scrim).mutate();
-        return setupGradientColorOnDrawable(albumArt, gradient, mutableColorScheme,
-                MEDIA_REC_SCRIM_START_ALPHA, MEDIA_REC_SCRIM_END_ALPHA);
-    }
-
     private LayerDrawable setupGradientColorOnDrawable(Drawable albumArt, GradientDrawable gradient,
             ColorScheme mutableColorScheme, float startAlpha, float endAlpha) {
         int startColor;
@@ -1465,258 +1315,6 @@
         return controller;
     }
 
-    /** Bind this recommendation view based on the given data. */
-    public void bindRecommendation(@NonNull SmartspaceMediaData data) {
-        if (mRecommendationViewHolder == null) {
-            return;
-        }
-
-        if (!data.isValid()) {
-            Log.e(TAG, "Received an invalid recommendation list; returning");
-            return;
-        }
-
-        if (Trace.isEnabled()) {
-            Trace.traceBegin(Trace.TRACE_TAG_APP,
-                    "MediaControlPanel#bindRecommendation<" + data.getPackageName() + ">");
-        }
-
-        mRecommendationData = data;
-        mPackageName = data.getPackageName();
-        mInstanceId = data.getInstanceId();
-
-        // Set up recommendation card's header.
-        ApplicationInfo applicationInfo;
-        try {
-            applicationInfo = mContext.getPackageManager()
-                    .getApplicationInfo(data.getPackageName(), 0 /* flags */);
-            mUid = applicationInfo.uid;
-        } catch (PackageManager.NameNotFoundException e) {
-            Log.w(TAG, "Fail to get media recommendation's app info", e);
-            Trace.endSection();
-            return;
-        }
-
-        CharSequence appName = data.getAppName(mContext);
-        if (appName == null) {
-            Log.w(TAG, "Fail to get media recommendation's app name");
-            Trace.endSection();
-            return;
-        }
-
-        PackageManager packageManager = mContext.getPackageManager();
-        // Set up media source app's logo.
-        Drawable icon = packageManager.getApplicationIcon(applicationInfo);
-        fetchAndUpdateRecommendationColors(icon);
-
-        // Set up media rec card's tap action if applicable.
-        TransitionLayout recommendationCard = mRecommendationViewHolder.getRecommendations();
-        setSmartspaceRecItemOnClickListener(recommendationCard, data.getCardAction(),
-                /* interactedSubcardRank */ -1);
-        bindRecommendationContentDescription(data);
-
-        List<ImageView> mediaCoverItems = mRecommendationViewHolder.getMediaCoverItems();
-        List<ViewGroup> mediaCoverContainers = mRecommendationViewHolder.getMediaCoverContainers();
-        List<SmartspaceAction> recommendations = data.getValidRecommendations();
-
-        boolean hasTitle = false;
-        boolean hasSubtitle = false;
-        int fittedRecsNum = getNumberOfFittedRecommendations();
-        for (int itemIndex = 0; itemIndex < NUM_REQUIRED_RECOMMENDATIONS; itemIndex++) {
-            SmartspaceAction recommendation = recommendations.get(itemIndex);
-
-            // Set up media item cover.
-            ImageView mediaCoverImageView = mediaCoverItems.get(itemIndex);
-            bindRecommendationArtwork(recommendation, data.getPackageName(), itemIndex);
-
-            // Set up the media item's click listener if applicable.
-            ViewGroup mediaCoverContainer = mediaCoverContainers.get(itemIndex);
-            setSmartspaceRecItemOnClickListener(mediaCoverContainer, recommendation, itemIndex);
-            // Bubble up the long-click event to the card.
-            mediaCoverContainer.setOnLongClickListener(v -> {
-                if (mFalsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)) return true;
-                View parent = (View) v.getParent();
-                if (parent != null) {
-                    parent.performLongClick();
-                }
-                return true;
-            });
-
-            // Set up the accessibility label for the media item.
-            String artistName = recommendation.getExtras()
-                    .getString(KEY_SMARTSPACE_ARTIST_NAME, "");
-            if (artistName.isEmpty()) {
-                mediaCoverImageView.setContentDescription(
-                        mContext.getString(
-                                R.string.controls_media_smartspace_rec_item_no_artist_description,
-                                recommendation.getTitle(), appName));
-            } else {
-                mediaCoverImageView.setContentDescription(
-                        mContext.getString(
-                                R.string.controls_media_smartspace_rec_item_description,
-                                recommendation.getTitle(), artistName, appName));
-            }
-
-            // Set up title
-            CharSequence title = recommendation.getTitle();
-            hasTitle |= !TextUtils.isEmpty(title);
-            TextView titleView = mRecommendationViewHolder.getMediaTitles().get(itemIndex);
-            titleView.setText(title);
-
-            // Set up subtitle
-            // It would look awkward to show a subtitle if we don't have a title.
-            boolean shouldShowSubtitleText = !TextUtils.isEmpty(title);
-            CharSequence subtitle = shouldShowSubtitleText ? recommendation.getSubtitle() : "";
-            hasSubtitle |= !TextUtils.isEmpty(subtitle);
-            TextView subtitleView = mRecommendationViewHolder.getMediaSubtitles().get(itemIndex);
-            subtitleView.setText(subtitle);
-
-            // Set up progress bar
-            SeekBar mediaProgressBar =
-                    mRecommendationViewHolder.getMediaProgressBars().get(itemIndex);
-            TextView mediaSubtitle = mRecommendationViewHolder.getMediaSubtitles().get(itemIndex);
-            // show progress bar if the recommended album is played.
-            Double progress = MediaDataUtils.getDescriptionProgress(recommendation.getExtras());
-            if (progress == null || progress <= 0.0) {
-                mediaProgressBar.setVisibility(View.GONE);
-                mediaSubtitle.setVisibility(View.VISIBLE);
-            } else {
-                mediaProgressBar.setProgress((int) (progress * 100));
-                mediaProgressBar.setVisibility(View.VISIBLE);
-                mediaSubtitle.setVisibility(View.GONE);
-            }
-        }
-        mSmartspaceMediaItemsCount = NUM_REQUIRED_RECOMMENDATIONS;
-
-        // If there's no subtitles and/or titles for any of the albums, hide those views.
-        ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
-        ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
-        final boolean titlesVisible = hasTitle;
-        final boolean subtitlesVisible = hasSubtitle;
-        mRecommendationViewHolder.getMediaTitles().forEach((titleView) -> {
-            setVisibleAndAlpha(expandedSet, titleView.getId(), titlesVisible);
-            setVisibleAndAlpha(collapsedSet, titleView.getId(), titlesVisible);
-        });
-        mRecommendationViewHolder.getMediaSubtitles().forEach((subtitleView) -> {
-            setVisibleAndAlpha(expandedSet, subtitleView.getId(), subtitlesVisible);
-            setVisibleAndAlpha(collapsedSet, subtitleView.getId(), subtitlesVisible);
-        });
-
-        // Media covers visibility.
-        setMediaCoversVisibility(fittedRecsNum);
-
-        // Guts
-        Runnable onDismissClickedRunnable = () -> {
-            closeGuts();
-            mMediaDataManagerLazy.get().dismissSmartspaceRecommendation(
-                    data.getTargetId(), MediaViewController.GUTS_ANIMATION_DURATION + 100L);
-
-            Intent dismissIntent = data.getDismissIntent();
-            if (dismissIntent == null) {
-                Log.w(TAG, "Cannot create dismiss action click action: "
-                        + "extras missing dismiss_intent.");
-                return;
-            }
-
-            if (dismissIntent.getComponent() != null
-                    && dismissIntent.getComponent().getClassName()
-                    .equals(EXPORTED_SMARTSPACE_TRAMPOLINE_ACTIVITY_NAME)) {
-                // Dismiss the card Smartspace data through Smartspace trampoline activity.
-                mContext.startActivity(dismissIntent);
-            } else {
-                mBroadcastSender.sendBroadcast(dismissIntent);
-            }
-        };
-        bindGutsMenuCommon(
-                /* isDismissible= */ true,
-                appName.toString(),
-                mRecommendationViewHolder.getGutsViewHolder(),
-                onDismissClickedRunnable);
-
-        mController = null;
-        if (mMetadataAnimationHandler == null || !mMetadataAnimationHandler.isRunning()) {
-            mMediaViewController.refreshState();
-        }
-        Trace.endSection();
-    }
-
-    private Unit updateRecommendationsVisibility() {
-        int fittedRecsNum = getNumberOfFittedRecommendations();
-        setMediaCoversVisibility(fittedRecsNum);
-        return Unit.INSTANCE;
-    }
-
-    private void setMediaCoversVisibility(int fittedRecsNum) {
-        ConstraintSet expandedSet = mMediaViewController.getExpandedLayout();
-        ConstraintSet collapsedSet = mMediaViewController.getCollapsedLayout();
-        List<ViewGroup> mediaCoverContainers = mRecommendationViewHolder.getMediaCoverContainers();
-        // Hide media cover that cannot fit in the recommendation card.
-        for (int itemIndex = 0; itemIndex < NUM_REQUIRED_RECOMMENDATIONS; itemIndex++) {
-            setVisibleAndAlpha(expandedSet, mediaCoverContainers.get(itemIndex).getId(),
-                    itemIndex < fittedRecsNum);
-            setVisibleAndAlpha(collapsedSet, mediaCoverContainers.get(itemIndex).getId(),
-                    itemIndex < fittedRecsNum);
-        }
-    }
-
-    @VisibleForTesting
-    protected int getNumberOfFittedRecommendations() {
-        Resources res = mContext.getResources();
-        Configuration config = res.getConfiguration();
-        int defaultDpWidth = res.getInteger(R.integer.default_qs_media_rec_width_dp);
-        int recCoverWidth = res.getDimensionPixelSize(R.dimen.qs_media_rec_album_width)
-                + res.getDimensionPixelSize(R.dimen.qs_media_info_spacing) * 2;
-
-        // On landscape, media controls should take half of the screen width.
-        int displayAvailableDpWidth = config.screenWidthDp;
-        if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) {
-            displayAvailableDpWidth = displayAvailableDpWidth / 2;
-        }
-        int fittedNum;
-        if (displayAvailableDpWidth > defaultDpWidth) {
-            int recCoverDefaultWidth = res.getDimensionPixelSize(
-                    R.dimen.qs_media_rec_default_width);
-            fittedNum = recCoverDefaultWidth / recCoverWidth;
-        } else {
-            int displayAvailableWidth = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
-                    displayAvailableDpWidth, res.getDisplayMetrics());
-            fittedNum = displayAvailableWidth / recCoverWidth;
-        }
-        return Math.min(fittedNum, NUM_REQUIRED_RECOMMENDATIONS);
-    }
-
-    private void fetchAndUpdateRecommendationColors(Drawable appIcon) {
-        mBackgroundExecutor.execute(() -> {
-            ColorScheme colorScheme = new ColorScheme(
-                    WallpaperColors.fromDrawable(appIcon), /* darkTheme= */ true);
-            mMainExecutor.execute(() -> setRecommendationColors(colorScheme));
-        });
-    }
-
-    private void setRecommendationColors(ColorScheme colorScheme) {
-        if (mRecommendationViewHolder == null) {
-            return;
-        }
-
-        int backgroundColor = MediaColorSchemesKt.surfaceFromScheme(colorScheme);
-        int textPrimaryColor = MediaColorSchemesKt.textPrimaryFromScheme(colorScheme);
-        int textSecondaryColor = MediaColorSchemesKt.textSecondaryFromScheme(colorScheme);
-
-        mRecommendationViewHolder.getCardTitle().setTextColor(textPrimaryColor);
-
-        mRecommendationViewHolder.getRecommendations()
-                .setBackgroundTintList(ColorStateList.valueOf(backgroundColor));
-        mRecommendationViewHolder.getMediaTitles().forEach(
-                (title) -> title.setTextColor(textPrimaryColor));
-        mRecommendationViewHolder.getMediaSubtitles().forEach(
-                (subtitle) -> subtitle.setTextColor(textSecondaryColor));
-        mRecommendationViewHolder.getMediaProgressBars().forEach(
-                (progressBar) -> progressBar.setProgressTintList(
-                        ColorStateList.valueOf(textPrimaryColor)));
-
-        mRecommendationViewHolder.getGutsViewHolder().setColors(colorScheme);
-    }
-
     private void bindGutsMenuCommon(
             boolean isDismissible,
             String appName,
@@ -1772,14 +1370,10 @@
     public void closeGuts(boolean immediate) {
         if (mMediaViewHolder != null) {
             mMediaViewHolder.marquee(false, mMediaViewController.GUTS_ANIMATION_DURATION);
-        } else if (mRecommendationViewHolder != null) {
-            mRecommendationViewHolder.marquee(false, mMediaViewController.GUTS_ANIMATION_DURATION);
         }
         mMediaViewController.closeGuts(immediate);
         if (mMediaViewHolder != null) {
             bindPlayerContentDescription(mMediaData);
-        } else if (mRecommendationViewHolder != null) {
-            bindRecommendationContentDescription(mRecommendationData);
         }
     }
 
@@ -1790,14 +1384,10 @@
     private void openGuts() {
         if (mMediaViewHolder != null) {
             mMediaViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
-        } else if (mRecommendationViewHolder != null) {
-            mRecommendationViewHolder.marquee(true, mMediaViewController.GUTS_ANIMATION_DURATION);
         }
         mMediaViewController.openGuts();
         if (mMediaViewHolder != null) {
             bindPlayerContentDescription(mMediaData);
-        } else if (mRecommendationViewHolder != null) {
-            bindRecommendationContentDescription(mRecommendationData);
         }
         mLogger.logLongPressOpen(mUid, mPackageName, mInstanceId);
     }
@@ -1822,29 +1412,6 @@
     }
 
     /**
-     * Scale artwork to fill the background of media covers in recommendation card.
-     */
-    @UiThread
-    private Drawable getScaledRecommendationCover(Icon artworkIcon, int width, int height) {
-        if (width == 0 || height == 0) {
-            return null;
-        }
-        if (artworkIcon != null) {
-            Bitmap bitmap;
-            if (artworkIcon.getType() == Icon.TYPE_BITMAP
-                    || artworkIcon.getType() == Icon.TYPE_ADAPTIVE_BITMAP) {
-                Bitmap artworkBitmap = artworkIcon.getBitmap();
-                if (artworkBitmap != null) {
-                    bitmap = Bitmap.createScaledBitmap(artworkIcon.getBitmap(), width,
-                            height, false);
-                    return new BitmapDrawable(mContext.getResources(), bitmap);
-                }
-            }
-        }
-        return null;
-    }
-
-    /**
      * Get the current media controller
      *
      * @return the controller
@@ -1896,64 +1463,5 @@
         set.setVisibility(actionId, visible ? ConstraintSet.VISIBLE : notVisibleValue);
         set.setAlpha(actionId, visible ? 1.0f : 0.0f);
     }
-
-    private void setSmartspaceRecItemOnClickListener(
-            @NonNull View view,
-            @NonNull SmartspaceAction action,
-            int interactedSubcardRank) {
-        if (view == null || action == null || action.getIntent() == null
-                || action.getIntent().getExtras() == null) {
-            Log.e(TAG, "No tap action can be set up");
-            return;
-        }
-
-        view.setOnClickListener(v -> {
-            if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) return;
-
-            if (interactedSubcardRank == -1) {
-                mLogger.logRecommendationCardTap(mPackageName, mInstanceId);
-            } else {
-                mLogger.logRecommendationItemTap(mPackageName, mInstanceId, interactedSubcardRank);
-            }
-
-            if (shouldSmartspaceRecItemOpenInForeground(action)) {
-                // Request to unlock the device if the activity needs to be opened in foreground.
-                mActivityStarter.postStartActivityDismissingKeyguard(
-                        action.getIntent(),
-                        0 /* delay */,
-                        buildLaunchAnimatorController(
-                                mRecommendationViewHolder.getRecommendations()));
-            } else {
-                // Otherwise, open the activity in background directly.
-                view.getContext().startActivity(action.getIntent());
-            }
-
-            // Automatically scroll to the active player once the media is loaded.
-            mMediaCarouselController.setShouldScrollToKey(true);
-        });
-    }
-
-    /** Returns if the Smartspace action will open the activity in foreground. */
-    private boolean shouldSmartspaceRecItemOpenInForeground(SmartspaceAction action) {
-        if (action == null || action.getIntent() == null
-                || action.getIntent().getExtras() == null) {
-            return false;
-        }
-
-        String intentString = action.getIntent().getExtras().getString(EXTRAS_SMARTSPACE_INTENT);
-        if (intentString == null) {
-            return false;
-        }
-
-        try {
-            Intent wrapperIntent = Intent.parseUri(intentString, Intent.URI_INTENT_SCHEME);
-            return wrapperIntent.getBooleanExtra(KEY_SMARTSPACE_OPEN_IN_FOREGROUND, false);
-        } catch (URISyntaxException e) {
-            Log.wtf(TAG, "Failed to create intent from URI: " + intentString);
-            e.printStackTrace();
-        }
-
-        return false;
-    }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
index 69006c6..ec7d332 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaHierarchyManager.kt
@@ -51,6 +51,7 @@
 import com.android.systemui.media.controls.ui.view.MediaHost
 import com.android.systemui.media.dream.MediaDreamComplication
 import com.android.systemui.plugins.statusbar.StatusBarStateController
+import com.android.systemui.qs.flags.QSComposeFragment
 import com.android.systemui.res.R
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.shade.ShadeDisplayAware
@@ -289,6 +290,9 @@
             updateUserVisibility()
         }
 
+    /** The expansion fraction of notification shade. */
+    var shadeExpandedFraction: Float = 0.0f
+
     /**
      * distance that the full shade transition takes in order for media to fully transition to the
      * shade
@@ -868,7 +872,13 @@
         if (isCurrentlyInGuidedTransformation()) {
             return false
         }
-        if (skipQqsOnExpansion) {
+        if (
+            skipQqsOnExpansion ||
+                (QSComposeFragment.isEnabled &&
+                    desiredLocation == LOCATION_QQS &&
+                    previousLocation == LOCATION_QS &&
+                    shadeExpandedFraction == 0.0f)
+        ) {
             return false
         }
         if (isHubTransition) {
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt
index b687dce..dba1900 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/controller/MediaViewController.kt
@@ -38,7 +38,6 @@
 import com.android.systemui.media.controls.ui.animation.ColorSchemeTransition
 import com.android.systemui.media.controls.ui.animation.MetadataAnimationHandler
 import com.android.systemui.media.controls.ui.binder.MediaControlViewBinder
-import com.android.systemui.media.controls.ui.binder.MediaRecommendationsViewBinder
 import com.android.systemui.media.controls.ui.binder.SeekBarObserver
 import com.android.systemui.media.controls.ui.controller.MediaCarouselController.Companion.calculateAlpha
 import com.android.systemui.media.controls.ui.view.GutsViewHolder
@@ -48,7 +47,6 @@
 import com.android.systemui.media.controls.ui.view.MediaViewHolder.Companion.labelLargeTF
 import com.android.systemui.media.controls.ui.view.MediaViewHolder.Companion.labelMediumTF
 import com.android.systemui.media.controls.ui.view.MediaViewHolder.Companion.titleMediumTF
-import com.android.systemui.media.controls.ui.view.RecommendationViewHolder
 import com.android.systemui.media.controls.ui.viewmodel.MediaControlViewModel
 import com.android.systemui.media.controls.ui.viewmodel.SeekBarViewModel
 import com.android.systemui.res.R
@@ -90,15 +88,6 @@
     private val globalSettings: GlobalSettings,
 ) {
 
-    /**
-     * Indicating that the media view controller is for a notification-based player, session-based
-     * player, or recommendation
-     */
-    enum class TYPE {
-        PLAYER,
-        RECOMMENDATION,
-    }
-
     companion object {
         @JvmField val GUTS_ANIMATION_DURATION = 234L
     }
@@ -115,7 +104,6 @@
     private var animationDuration: Long = 0
     private var animateNextStateChange: Boolean = false
     private val measurement = MeasurementOutput(0, 0)
-    private var type: TYPE = TYPE.PLAYER
 
     /** A map containing all viewStates for all locations of this mediaState */
     private val viewStates: MutableMap<CacheKey, TransitionViewState?> = mutableMapOf()
@@ -203,7 +191,6 @@
     private var isNextButtonAvailable = false
 
     /** View holders for controller */
-    var recommendationViewHolder: RecommendationViewHolder? = null
     var mediaViewHolder: MediaViewHolder? = null
 
     private lateinit var seekBarObserver: SeekBarObserver
@@ -417,13 +404,9 @@
 
     /** Set the height of UMO background constraints. */
     private fun setBackgroundHeights(height: Int) {
-        val backgroundIds =
-            if (type == TYPE.PLAYER) {
-                MediaViewHolder.backgroundIds
-            } else {
-                setOf(RecommendationViewHolder.backgroundId)
-            }
-        backgroundIds.forEach { id -> expandedLayout.getConstraint(id).layout.mHeight = height }
+        MediaViewHolder.backgroundIds.forEach { id ->
+            expandedLayout.getConstraint(id).layout.mHeight = height
+        }
     }
 
     /**
@@ -431,11 +414,7 @@
      * [TransitionViewState].
      */
     private fun setGutsViewState(viewState: TransitionViewState) {
-        val controlsIds =
-            when (type) {
-                TYPE.PLAYER -> MediaViewHolder.controlsIds
-                TYPE.RECOMMENDATION -> RecommendationViewHolder.controlsIds
-            }
+        val controlsIds = MediaViewHolder.controlsIds
         val gutsIds = GutsViewHolder.ids
         controlsIds.forEach { id ->
             viewState.widgetStates.get(id)?.let { state ->
@@ -467,7 +446,6 @@
             squishedViewState.widgetStates.get(id)?.let { state -> state.height = squishedHeight }
         }
 
-        // media player
         calculateWidgetGroupAlphaForSquishiness(
             MediaViewHolder.expandedBottomActionIds,
             squishedViewState.measureHeight.toFloat(),
@@ -480,20 +458,6 @@
             squishedViewState,
             squishFraction,
         )
-        // recommendation card
-        val titlesTop =
-            calculateWidgetGroupAlphaForSquishiness(
-                RecommendationViewHolder.mediaTitlesAndSubtitlesIds,
-                squishedViewState.measureHeight.toFloat(),
-                squishedViewState,
-                squishFraction,
-            )
-        calculateWidgetGroupAlphaForSquishiness(
-            RecommendationViewHolder.mediaContainersIds,
-            titlesTop,
-            squishedViewState,
-            squishFraction,
-        )
         return squishedViewState
     }
 
@@ -661,10 +625,10 @@
      * Attach a view to this controller. This may perform measurements if it's not available yet and
      * should therefore be done carefully.
      */
-    fun attach(transitionLayout: TransitionLayout, type: TYPE) =
+    fun attach(transitionLayout: TransitionLayout) =
         traceSection("MediaViewController#attach") {
-            loadLayoutForType(type)
-            logger.logMediaLocation("attach $type", currentStartLocation, currentEndLocation)
+            loadLayoutConstraints()
+            logger.logMediaLocation("attach", currentStartLocation, currentEndLocation)
             this.transitionLayout = transitionLayout
             layoutController.attach(transitionLayout)
             if (currentEndLocation == MediaHierarchyManager.LOCATION_UNKNOWN) {
@@ -691,7 +655,7 @@
         seekBarViewModel.setEnabledChangeListener(enabledChangeListener)
 
         val mediaCard = mediaViewHolder.player
-        attach(mediaViewHolder.player, TYPE.PLAYER)
+        attach(mediaViewHolder.player)
 
         val turbulenceNoiseView = mediaViewHolder.turbulenceNoiseView
         turbulenceNoiseController = TurbulenceNoiseController(turbulenceNoiseView)
@@ -813,15 +777,6 @@
         }
     }
 
-    fun attachRecommendations(recommendationViewHolder: RecommendationViewHolder) {
-        if (!SceneContainerFlag.isEnabled) return
-        this.recommendationViewHolder = recommendationViewHolder
-
-        attach(recommendationViewHolder.recommendations, TYPE.RECOMMENDATION)
-        recsConfigurationChangeListener =
-            MediaRecommendationsViewBinder::updateRecommendationsVisibility
-    }
-
     fun bindSeekBar(onSeek: () -> Unit, onBindSeekBar: (SeekBarViewModel) -> Unit) {
         if (!SceneContainerFlag.isEnabled) return
         seekBarViewModel.logSeek = onSeek
@@ -1026,20 +981,10 @@
         return result
     }
 
-    private fun loadLayoutForType(type: TYPE) {
-        this.type = type
-
-        // These XML resources contain ConstraintSets that will apply to this player type's layout
-        when (type) {
-            TYPE.PLAYER -> {
-                collapsedLayout.load(context, R.xml.media_session_collapsed)
-                expandedLayout.load(context, R.xml.media_session_expanded)
-            }
-            TYPE.RECOMMENDATION -> {
-                collapsedLayout.load(context, R.xml.media_recommendations_collapsed)
-                expandedLayout.load(context, R.xml.media_recommendations_expanded)
-            }
-        }
+    private fun loadLayoutConstraints() {
+        // These XML resources contain ConstraintSets that will apply to this player's layout
+        collapsedLayout.load(context, R.xml.media_session_collapsed)
+        expandedLayout.load(context, R.xml.media_session_expanded)
         readjustUIUpdateConstraints()
         refreshState()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelCallback.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelCallback.kt
index f28edd6..2fc44ad 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelCallback.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/util/MediaViewModelCallback.kt
@@ -42,8 +42,7 @@
         ) {
             oldItem.instanceId == newItem.instanceId
         } else {
-            oldItem is MediaCommonViewModel.MediaRecommendations &&
-                newItem is MediaCommonViewModel.MediaRecommendations
+            false
         }
     }
 
@@ -56,11 +55,6 @@
         ) {
             oldItem.immediatelyUpdateUi == newItem.immediatelyUpdateUi &&
                 oldItem.updateTime == newItem.updateTime
-        } else if (
-            oldItem is MediaCommonViewModel.MediaRecommendations &&
-                newItem is MediaCommonViewModel.MediaRecommendations
-        ) {
-            oldItem.key == newItem.key && oldItem.loadingEnabled == newItem.loadingEnabled
         } else {
             false
         }
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/RecommendationViewHolder.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/RecommendationViewHolder.kt
deleted file mode 100644
index 2d028d0213..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/view/RecommendationViewHolder.kt
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
- * Copyright (C) 2020 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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.media.controls.ui.view
-
-import android.view.LayoutInflater
-import android.view.View
-import android.view.ViewGroup
-import android.widget.ImageView
-import android.widget.SeekBar
-import android.widget.TextView
-import com.android.internal.widget.CachingIconView
-import com.android.systemui.media.controls.ui.drawable.IlluminationDrawable
-import com.android.systemui.res.R
-import com.android.systemui.util.animation.TransitionLayout
-
-private const val TAG = "RecommendationViewHolder"
-
-/** ViewHolder for a Smartspace media recommendation. */
-class RecommendationViewHolder private constructor(itemView: View) {
-
-    val recommendations = itemView as TransitionLayout
-
-    // Recommendation screen
-    val cardTitle: TextView = itemView.requireViewById(R.id.media_rec_title)
-
-    val mediaCoverContainers =
-        listOf<ViewGroup>(
-            itemView.requireViewById(R.id.media_cover1_container),
-            itemView.requireViewById(R.id.media_cover2_container),
-            itemView.requireViewById(R.id.media_cover3_container)
-        )
-    val mediaAppIcons: List<CachingIconView> =
-        mediaCoverContainers.map { it.requireViewById(R.id.media_rec_app_icon) }
-    val mediaTitles: List<TextView> =
-        mediaCoverContainers.map { it.requireViewById(R.id.media_title) }
-    val mediaSubtitles: List<TextView> =
-        mediaCoverContainers.map { it.requireViewById(R.id.media_subtitle) }
-    val mediaProgressBars: List<SeekBar> =
-        mediaCoverContainers.map {
-            it.requireViewById<SeekBar?>(R.id.media_progress_bar).apply {
-                // Media playback is in the direction of tape, not time, so it stays LTR
-                layoutDirection = View.LAYOUT_DIRECTION_LTR
-            }
-        }
-
-    val mediaCoverItems: List<ImageView> =
-        mediaCoverContainers.map { it.requireViewById(R.id.media_cover) }
-    val gutsViewHolder = GutsViewHolder(itemView)
-
-    init {
-        (recommendations.background as IlluminationDrawable).let { background ->
-            mediaCoverContainers.forEach { background.registerLightSource(it) }
-            background.registerLightSource(gutsViewHolder.cancel)
-            background.registerLightSource(gutsViewHolder.dismiss)
-            background.registerLightSource(gutsViewHolder.settings)
-        }
-    }
-
-    fun marquee(start: Boolean, delay: Long) {
-        gutsViewHolder.marquee(start, delay, TAG)
-    }
-
-    companion object {
-        /**
-         * Creates a RecommendationViewHolder.
-         *
-         * @param inflater LayoutInflater to use to inflate the layout.
-         * @param parent Parent of inflated view.
-         */
-        @JvmStatic
-        fun create(inflater: LayoutInflater, parent: ViewGroup): RecommendationViewHolder {
-            val itemView =
-                inflater.inflate(R.layout.media_recommendations, parent, false /* attachToRoot */)
-            // Because this media view (a TransitionLayout) is used to measure and layout the views
-            // in various states before being attached to its parent, we can't depend on the default
-            // LAYOUT_DIRECTION_INHERIT to correctly resolve the ltr direction.
-            itemView.layoutDirection = View.LAYOUT_DIRECTION_LOCALE
-            return RecommendationViewHolder(itemView)
-        }
-
-        // Res Ids for the control components on the recommendation view.
-        val controlsIds =
-            setOf(
-                R.id.media_rec_title,
-                R.id.media_cover,
-                R.id.media_cover1_container,
-                R.id.media_cover2_container,
-                R.id.media_cover3_container,
-                R.id.media_title,
-                R.id.media_subtitle,
-            )
-
-        val mediaTitlesAndSubtitlesIds =
-            setOf(
-                R.id.media_title,
-                R.id.media_subtitle,
-            )
-
-        val mediaContainersIds =
-            setOf(
-                R.id.media_cover1_container,
-                R.id.media_cover2_container,
-                R.id.media_cover3_container
-            )
-
-        val backgroundId = R.id.sizing_view
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
index e5f1766..dfaee44 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModel.kt
@@ -49,7 +49,6 @@
     private val visualStabilityProvider: VisualStabilityProvider,
     private val interactor: MediaCarouselInteractor,
     private val controlInteractorFactory: MediaControlInteractorFactory,
-    private val recommendationsViewModel: MediaRecommendationsViewModel,
     private val logger: MediaUiEventLogger,
     private val mediaLogger: MediaLogger,
 ) {
@@ -69,7 +68,7 @@
                             when (commonModel) {
                                 is MediaCommonModel.MediaControl -> add(toViewModel(commonModel))
                                 is MediaCommonModel.MediaRecommendations ->
-                                    add(toViewModel(commonModel))
+                                    return@forEach // TODO(b/382680767): remove
                             }
                         }
                     }
@@ -95,8 +94,6 @@
     private val mediaControlByInstanceId =
         mutableMapOf<InstanceId, MediaCommonViewModel.MediaControl>()
 
-    private var mediaRecs: MediaCommonViewModel.MediaRecommendations? = null
-
     private var modelsPendingRemoval: MutableSet<MediaCommonModel> = mutableSetOf()
 
     private var allowReorder = false
@@ -149,37 +146,6 @@
         )
     }
 
-    private fun toViewModel(
-        commonModel: MediaCommonModel.MediaRecommendations
-    ): MediaCommonViewModel.MediaRecommendations {
-        return mediaRecs?.copy(
-            key = commonModel.recsLoadingModel.key,
-            loadingEnabled = interactor.isRecommendationActive(),
-        )
-            ?: MediaCommonViewModel.MediaRecommendations(
-                    key = commonModel.recsLoadingModel.key,
-                    loadingEnabled = interactor.isRecommendationActive(),
-                    recsViewModel = recommendationsViewModel,
-                    onAdded = { commonViewModel ->
-                        mediaLogger.logMediaRecommendationCardAdded(
-                            commonModel.recsLoadingModel.key
-                        )
-                        onMediaRecommendationAddedOrUpdated(
-                            commonViewModel as MediaCommonViewModel.MediaRecommendations
-                        )
-                    },
-                    onRemoved = { immediatelyRemove ->
-                        onMediaRecommendationRemoved(commonModel, immediatelyRemove)
-                    },
-                    onUpdated = { commonViewModel ->
-                        onMediaRecommendationAddedOrUpdated(
-                            commonViewModel as MediaCommonViewModel.MediaRecommendations
-                        )
-                    },
-                )
-                .also { mediaRecs = it }
-    }
-
     private fun onMediaControlAddedOrUpdated(
         commonViewModel: MediaCommonViewModel,
         commonModel: MediaCommonModel.MediaControl,
@@ -197,32 +163,6 @@
         }
     }
 
-    private fun onMediaRecommendationAddedOrUpdated(
-        commonViewModel: MediaCommonViewModel.MediaRecommendations
-    ) {
-        if (!interactor.isRecommendationActive()) {
-            commonViewModel.onRemoved(true)
-        }
-    }
-
-    private fun onMediaRecommendationRemoved(
-        commonModel: MediaCommonModel.MediaRecommendations,
-        immediatelyRemove: Boolean,
-    ) {
-        mediaLogger.logMediaRecommendationCardRemoved(commonModel.recsLoadingModel.key)
-        if (immediatelyRemove || isReorderingAllowed()) {
-            interactor.dismissSmartspaceRecommendation(commonModel.recsLoadingModel.key, 0L)
-            mediaRecs = null
-            if (!immediatelyRemove) {
-                // Although it wasn't requested, we were able to process the removal
-                // immediately since reordering is allowed. So, notify hosts to update
-                updateHostVisibility()
-            }
-        } else {
-            modelsPendingRemoval.add(commonModel)
-        }
-    }
-
     private fun isReorderingAllowed(): Boolean {
         return visualStabilityProvider.isReorderingAllowed
     }
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCommonViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCommonViewModel.kt
index 52cb173..d493d57 100644
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCommonViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaCommonViewModel.kt
@@ -35,13 +35,4 @@
         val isMediaFromRec: Boolean = false,
         val updateTime: Long = 0,
     ) : MediaCommonViewModel()
-
-    data class MediaRecommendations(
-        val key: String,
-        val loadingEnabled: Boolean,
-        val recsViewModel: MediaRecommendationsViewModel,
-        override val onAdded: (MediaCommonViewModel) -> Unit,
-        override val onRemoved: (Boolean) -> Unit,
-        override val onUpdated: (MediaCommonViewModel) -> Unit,
-    ) : MediaCommonViewModel()
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecViewModel.kt
deleted file mode 100644
index 77add40..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecViewModel.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.controls.ui.viewmodel
-
-import android.graphics.drawable.Drawable
-import android.graphics.drawable.Icon
-import com.android.systemui.animation.Expandable
-
-/** Models UI state for media recommendation item */
-data class MediaRecViewModel(
-    val contentDescription: CharSequence,
-    val title: CharSequence = "",
-    val subtitle: CharSequence = "",
-    /** track progress [0 - 100] for the recommendation album. */
-    val progress: Int = 0,
-    val albumIcon: Icon? = null,
-    val appIcon: Drawable,
-    val onClicked: ((Expandable, Int) -> Unit),
-)
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt
deleted file mode 100644
index 90313dd..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModel.kt
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.controls.ui.viewmodel
-
-import android.content.Context
-import android.content.Intent
-import android.content.pm.PackageManager
-import android.graphics.drawable.Drawable
-import android.os.Process
-import android.util.Log
-import com.android.internal.logging.InstanceId
-import com.android.systemui.animation.Expandable
-import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.Background
-import com.android.systemui.media.controls.domain.pipeline.interactor.MediaRecommendationsInteractor
-import com.android.systemui.media.controls.shared.model.MediaRecModel
-import com.android.systemui.media.controls.shared.model.MediaRecommendationsModel
-import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager
-import com.android.systemui.media.controls.ui.controller.MediaLocation
-import com.android.systemui.media.controls.ui.controller.MediaViewController.Companion.GUTS_ANIMATION_DURATION
-import com.android.systemui.media.controls.util.MediaDataUtils
-import com.android.systemui.media.controls.util.MediaUiEventLogger
-import com.android.systemui.res.R
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.flowOn
-import kotlinx.coroutines.flow.map
-
-/** Models UI state and handles user input for media recommendations */
-@SysUISingleton
-class MediaRecommendationsViewModel
-@Inject
-constructor(
-    @Application private val applicationContext: Context,
-    @Background private val backgroundDispatcher: CoroutineDispatcher,
-    private val interactor: MediaRecommendationsInteractor,
-    private val logger: MediaUiEventLogger,
-) {
-
-    val mediaRecsCard: Flow<MediaRecsCardViewModel?> =
-        interactor.recommendations
-            .map { recsCard -> toRecsViewModel(recsCard) }
-            .distinctUntilChanged()
-            .flowOn(backgroundDispatcher)
-
-    @MediaLocation private var location = MediaHierarchyManager.LOCATION_UNKNOWN
-
-    /**
-     * Called whenever the recommendation has been expired or removed by the user. This method
-     * removes the recommendation card entirely from the carousel.
-     */
-    private fun onMediaRecommendationsDismissed(
-        key: String,
-        uid: Int,
-        packageName: String,
-        dismissIntent: Intent?,
-        instanceId: InstanceId?,
-    ) {
-        logger.logLongPressDismiss(uid, packageName, instanceId)
-        interactor.removeMediaRecommendations(key, dismissIntent, GUTS_DISMISS_DELAY_MS_DURATION)
-    }
-
-    private fun onClicked(
-        expandable: Expandable,
-        intent: Intent?,
-        packageName: String,
-        instanceId: InstanceId?,
-        index: Int,
-    ) {
-        if (intent == null || intent.extras == null) {
-            Log.e(TAG, "No tap action can be set up")
-            return
-        }
-
-        if (index == -1) {
-            logger.logRecommendationCardTap(packageName, instanceId)
-        } else {
-            logger.logRecommendationItemTap(packageName, instanceId, index)
-        }
-
-        // set the package name of the player added by recommendation once the media is loaded.
-        interactor.switchToMediaControl(packageName)
-
-        interactor.startClickIntent(expandable, intent)
-    }
-
-    private suspend fun toRecsViewModel(model: MediaRecommendationsModel): MediaRecsCardViewModel? {
-        if (!model.areRecommendationsValid) {
-            Log.e(TAG, "Received an invalid recommendation list")
-            return null
-        }
-        if (model.appName == null || model.uid == Process.INVALID_UID) {
-            Log.w(TAG, "Fail to get media recommendation's app info")
-            return null
-        }
-
-        val appIcon = getIconFromApp(model.packageName) ?: return null
-
-        var areTitlesVisible = false
-        var areSubtitlesVisible = false
-        val mediaRecs =
-            model.mediaRecs.map { mediaRecModel ->
-                areTitlesVisible = areTitlesVisible || !mediaRecModel.title.isNullOrEmpty()
-                areSubtitlesVisible = areSubtitlesVisible || !mediaRecModel.subtitle.isNullOrEmpty()
-                val progress = MediaDataUtils.getDescriptionProgress(mediaRecModel.extras) ?: 0.0
-                MediaRecViewModel(
-                    contentDescription =
-                        setUpMediaRecContentDescription(mediaRecModel, model.appName),
-                    title = mediaRecModel.title ?: "",
-                    subtitle = mediaRecModel.subtitle ?: "",
-                    progress = (progress * 100).toInt(),
-                    albumIcon = mediaRecModel.icon,
-                    appIcon = appIcon,
-                    onClicked = { expandable, index ->
-                        onClicked(
-                            expandable,
-                            mediaRecModel.intent,
-                            model.packageName,
-                            model.instanceId,
-                            index,
-                        )
-                    },
-                )
-            }
-        // Subtitles should only be visible if titles are visible.
-        areSubtitlesVisible = areTitlesVisible && areSubtitlesVisible
-
-        return MediaRecsCardViewModel(
-            contentDescription = { gutsVisible ->
-                if (gutsVisible) {
-                    applicationContext.getString(
-                        R.string.controls_media_close_session,
-                        model.appName,
-                    )
-                } else {
-                    applicationContext.getString(R.string.controls_media_smartspace_rec_header)
-                }
-            },
-            onClicked = { expandable ->
-                onClicked(
-                    expandable,
-                    model.dismissIntent,
-                    model.packageName,
-                    model.instanceId,
-                    index = -1,
-                )
-            },
-            onLongClicked = {
-                logger.logLongPressOpen(model.uid, model.packageName, model.instanceId)
-            },
-            mediaRecs = mediaRecs,
-            areTitlesVisible = areTitlesVisible,
-            areSubtitlesVisible = areSubtitlesVisible,
-            gutsMenu = toGutsViewModel(model),
-            onLocationChanged = { location = it },
-        )
-    }
-
-    private fun toGutsViewModel(model: MediaRecommendationsModel): GutsViewModel {
-        return GutsViewModel(
-            gutsText =
-                applicationContext.getString(R.string.controls_media_close_session, model.appName),
-            onDismissClicked = {
-                onMediaRecommendationsDismissed(
-                    model.key,
-                    model.uid,
-                    model.packageName,
-                    model.dismissIntent,
-                    model.instanceId,
-                )
-            },
-            cancelTextBackground =
-                applicationContext.getDrawable(R.drawable.qs_media_outline_button),
-            onSettingsClicked = {
-                logger.logLongPressSettings(model.uid, model.packageName, model.instanceId)
-                interactor.startSettings()
-            },
-        )
-    }
-
-    private fun setUpMediaRecContentDescription(
-        mediaRec: MediaRecModel,
-        appName: CharSequence?,
-    ): CharSequence {
-        // Set up the accessibility label for the media item.
-        val artistName = mediaRec.extras?.getString(KEY_SMARTSPACE_ARTIST_NAME, "")
-        return if (artistName.isNullOrEmpty()) {
-            applicationContext.getString(
-                R.string.controls_media_smartspace_rec_item_no_artist_description,
-                mediaRec.title,
-                appName,
-            )
-        } else {
-            applicationContext.getString(
-                R.string.controls_media_smartspace_rec_item_description,
-                mediaRec.title,
-                artistName,
-                appName,
-            )
-        }
-    }
-
-    private fun getIconFromApp(packageName: String): Drawable? {
-        return try {
-            applicationContext.packageManager.getApplicationIcon(packageName)
-        } catch (e: PackageManager.NameNotFoundException) {
-            Log.w(TAG, "Cannot find icon for package $packageName", e)
-            null
-        }
-    }
-
-    companion object {
-        private const val TAG = "MediaRecommendationsViewModel"
-        private const val KEY_SMARTSPACE_ARTIST_NAME = "artist_name"
-        /**
-         * Delay duration is based on [GUTS_ANIMATION_DURATION], it should have 100 ms increase in
-         * order to let the animation end.
-         */
-        private const val GUTS_DISMISS_DELAY_MS_DURATION = 334L
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecsCardViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecsCardViewModel.kt
deleted file mode 100644
index f1f7dc2..0000000
--- a/packages/SystemUI/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecsCardViewModel.kt
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.controls.ui.viewmodel
-
-import com.android.systemui.animation.Expandable
-
-/** Models UI state for media recommendations card. */
-data class MediaRecsCardViewModel(
-    val contentDescription: (Boolean) -> CharSequence,
-    val onClicked: (Expandable) -> Unit,
-    val onLongClicked: () -> Unit,
-    val mediaRecs: List<MediaRecViewModel>,
-    val areTitlesVisible: Boolean,
-    val areSubtitlesVisible: Boolean,
-    val gutsMenu: GutsViewModel,
-    val onLocationChanged: (Int) -> Unit,
-)
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java
index f8e57ef..300a357 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaOutputAdapterLegacy.java
@@ -186,8 +186,7 @@
             mVolumeValueText.setTextColor(mController.getColorItemContent());
             mIconAreaLayout.setBackground(null);
             updateIconAreaClickListener(null);
-            mSeekBar.setProgressTintList(
-                    ColorStateList.valueOf(mController.getColorSeekbarProgress()));
+            updateSeekBarProgressColor();
             updateContainerContentA11yImportance(true  /* isImportant */);
             renderItem(mediaItem, position);
         }
@@ -332,6 +331,16 @@
             }
         }
 
+        private void updateSeekBarProgressColor() {
+            mSeekBar.setProgressTintList(
+                    ColorStateList.valueOf(mController.getColorSeekbarProgress()));
+            final Drawable contrastDotDrawable =
+                    ((LayerDrawable) mSeekBar.getProgressDrawable()).findDrawableByLayerId(
+                            R.id.contrast_dot);
+            contrastDotDrawable.setTintList(
+                    ColorStateList.valueOf(mController.getColorItemContent()));
+        }
+
         void updateSeekbarProgressBackground() {
             final ClipDrawable clipDrawable =
                     (ClipDrawable) ((LayerDrawable) mSeekBar.getProgressDrawable())
diff --git a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
index 1f2f571..9d37580 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dialog/MediaSwitchingController.java
@@ -648,10 +648,6 @@
             final MediaDevice connectedMediaDevice =
                     needToHandleMutingExpectedDevice ? null
                             : getCurrentConnectedMediaDevice();
-
-            Set<String> selectedDevicesIds = getSelectedMediaDevice().stream()
-                    .map(MediaDevice::getId)
-                    .collect(Collectors.toSet());
             if (oldMediaItems.isEmpty()) {
                 if (connectedMediaDevice == null) {
                     if (DEBUG) {
@@ -660,14 +656,12 @@
                     return categorizeMediaItemsLocked(
                             /* connectedMediaDevice */ null,
                             devices,
-                            selectedDevicesIds,
                             needToHandleMutingExpectedDevice);
                 } else {
                     // selected device exist
                     return categorizeMediaItemsLocked(
                             connectedMediaDevice,
                             devices,
-                            selectedDevicesIds,
                             /* needToHandleMutingExpectedDevice */ false);
                 }
             }
@@ -701,20 +695,9 @@
                 devices.removeAll(targetMediaDevices);
                 targetMediaDevices.addAll(devices);
             }
-            List<MediaItem> finalMediaItems = new ArrayList<>();
-            boolean shouldAddFirstSeenSelectedDevice =
-                    com.android.media.flags.Flags.enableOutputSwitcherDeviceGrouping();
-            for (MediaDevice targetMediaDevice : targetMediaDevices) {
-                if (shouldAddFirstSeenSelectedDevice
-                        && selectedDevicesIds.contains(targetMediaDevice.getId())) {
-                    finalMediaItems.add(MediaItem.createDeviceMediaItem(
-                            targetMediaDevice, /* isFirstDeviceInGroup */ true));
-                    shouldAddFirstSeenSelectedDevice = false;
-                } else {
-                    finalMediaItems.add(MediaItem.createDeviceMediaItem(
-                            targetMediaDevice, /* isFirstDeviceInGroup */ false));
-                }
-            }
+            List<MediaItem> finalMediaItems = targetMediaDevices.stream()
+                    .map(MediaItem::createDeviceMediaItem)
+                    .collect(Collectors.toList());
             dividerItems.forEach(finalMediaItems::add);
             attachConnectNewDeviceItemIfNeeded(finalMediaItems);
             return finalMediaItems;
@@ -741,9 +724,11 @@
     @GuardedBy("mMediaDevicesLock")
     private List<MediaItem> categorizeMediaItemsLocked(MediaDevice connectedMediaDevice,
             List<MediaDevice> devices,
-            Set<String> selectedDevicesIds,
             boolean needToHandleMutingExpectedDevice) {
         List<MediaItem> finalMediaItems = new ArrayList<>();
+        Set<String> selectedDevicesIds = getSelectedMediaDevice().stream()
+                .map(MediaDevice::getId)
+                .collect(Collectors.toSet());
         if (connectedMediaDevice != null) {
             selectedDevicesIds.add(connectedMediaDevice.getId());
         }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/shared/model/MediaSessionState.kt
similarity index 66%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/src/com/android/systemui/media/remedia/shared/model/MediaSessionState.kt
index 9b7cd70..40d55af 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/shared/model/MediaSessionState.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,8 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.media.remedia.shared.model
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+sealed interface MediaSessionState {
+    data object Playing : MediaSessionState
+
+    data object Paused : MediaSessionState
+
+    data object Buffering : MediaSessionState
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt
new file mode 100644
index 0000000..c9fb8e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/compose/Media.kt
@@ -0,0 +1,926 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+@file:OptIn(ExperimentalMaterial3Api::class)
+
+package com.android.systemui.media.remedia.ui.compose
+
+import androidx.compose.animation.AnimatedVisibility
+import androidx.compose.animation.Crossfade
+import androidx.compose.animation.core.Animatable
+import androidx.compose.animation.core.LinearEasing
+import androidx.compose.animation.core.RepeatMode
+import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.animation.core.infiniteRepeatable
+import androidx.compose.animation.core.tween
+import androidx.compose.animation.graphics.res.animatedVectorResource
+import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
+import androidx.compose.animation.graphics.vector.AnimatedImageVector
+import androidx.compose.foundation.BorderStroke
+import androidx.compose.foundation.Canvas
+import androidx.compose.foundation.Image
+import androidx.compose.foundation.background
+import androidx.compose.foundation.clickable
+import androidx.compose.foundation.combinedClickable
+import androidx.compose.foundation.hoverable
+import androidx.compose.foundation.interaction.DragInteraction
+import androidx.compose.foundation.interaction.Interaction
+import androidx.compose.foundation.interaction.MutableInteractionSource
+import androidx.compose.foundation.interaction.PressInteraction
+import androidx.compose.foundation.layout.Arrangement
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.Column
+import androidx.compose.foundation.layout.PaddingValues
+import androidx.compose.foundation.layout.Row
+import androidx.compose.foundation.layout.Spacer
+import androidx.compose.foundation.layout.fillMaxWidth
+import androidx.compose.foundation.layout.height
+import androidx.compose.foundation.layout.padding
+import androidx.compose.foundation.layout.size
+import androidx.compose.foundation.shape.CircleShape
+import androidx.compose.foundation.shape.RoundedCornerShape
+import androidx.compose.material3.ButtonDefaults
+import androidx.compose.material3.CircularProgressIndicator
+import androidx.compose.material3.ExperimentalMaterial3Api
+import androidx.compose.material3.Icon
+import androidx.compose.material3.IconButtonDefaults
+import androidx.compose.material3.MaterialTheme
+import androidx.compose.material3.Slider
+import androidx.compose.material3.SliderColors
+import androidx.compose.material3.SliderDefaults.colors
+import androidx.compose.material3.SliderState
+import androidx.compose.material3.Text
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.key
+import androidx.compose.runtime.mutableStateListOf
+import androidx.compose.runtime.mutableStateOf
+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.draw.drawWithContent
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.center
+import androidx.compose.ui.graphics.Brush
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.graphics.CompositingStrategy
+import androidx.compose.ui.graphics.ImageBitmap
+import androidx.compose.ui.graphics.Path
+import androidx.compose.ui.graphics.StrokeCap
+import androidx.compose.ui.graphics.drawscope.Stroke
+import androidx.compose.ui.graphics.drawscope.clipRect
+import androidx.compose.ui.graphics.drawscope.translate
+import androidx.compose.ui.graphics.graphicsLayer
+import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.ContentScale
+import androidx.compose.ui.layout.Layout
+import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Dp
+import androidx.compose.ui.unit.dp
+import androidx.compose.ui.util.fastForEach
+import androidx.compose.ui.util.fastForEachIndexed
+import com.android.compose.PlatformButton
+import com.android.compose.PlatformIconButton
+import com.android.compose.PlatformOutlinedButton
+import com.android.compose.animation.scene.ContentScope
+import com.android.compose.animation.scene.ElementKey
+import com.android.compose.animation.scene.SceneKey
+import com.android.compose.animation.scene.SceneTransitionLayout
+import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState
+import com.android.compose.animation.scene.transitions
+import com.android.compose.theme.LocalAndroidColorScheme
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.common.ui.compose.Icon
+import com.android.systemui.common.ui.compose.load
+import com.android.systemui.communal.ui.compose.extensions.detectLongPressGesture
+import com.android.systemui.media.remedia.shared.model.MediaSessionState
+import com.android.systemui.media.remedia.ui.viewmodel.MediaCardGutsViewModel
+import com.android.systemui.media.remedia.ui.viewmodel.MediaCardViewModel
+import com.android.systemui.media.remedia.ui.viewmodel.MediaOutputSwitcherChipViewModel
+import com.android.systemui.media.remedia.ui.viewmodel.MediaPlayPauseActionViewModel
+import com.android.systemui.media.remedia.ui.viewmodel.MediaSecondaryActionViewModel
+import com.android.systemui.media.remedia.ui.viewmodel.MediaSeekBarViewModel
+import kotlin.math.max
+
+/** Renders the UI of a single media card. */
+@Composable
+private fun Card(
+    viewModel: MediaCardViewModel,
+    presentationStyle: MediaPresentationStyle,
+    modifier: Modifier = Modifier,
+) {
+    val stlState =
+        rememberMutableSceneTransitionLayoutState(
+            initialScene = presentationStyle.toScene(),
+            transitions = Media.Transitions,
+        )
+
+    // Each time the presentation style changes, animate to the corresponding scene.
+    LaunchedEffect(presentationStyle) {
+        stlState.setTargetScene(targetScene = presentationStyle.toScene(), animationScope = this)
+    }
+
+    Box(modifier) {
+        if (stlState.currentScene != Media.Scenes.Compact) {
+            CardBackground(imageLoader = viewModel.artLoader, modifier = Modifier.matchParentSize())
+        }
+
+        key(stlState) {
+            SceneTransitionLayout(state = stlState) {
+                scene(Media.Scenes.Default) {
+                    CardForeground(viewModel = viewModel, threeRows = true, fillHeight = false)
+                }
+
+                scene(Media.Scenes.Compressed) {
+                    CardForeground(viewModel = viewModel, threeRows = false, fillHeight = false)
+                }
+
+                scene(Media.Scenes.Compact) { CompactCardForeground(viewModel = viewModel) }
+            }
+        }
+    }
+}
+
+/**
+ * Renders the foreground of a card, including all UI content and the internal "guts".
+ *
+ * If [threeRows] is `true`, the layout will be organized as three horizontal rows; if `false`, two
+ * rows will be used, resulting in a more compact layout.
+ *
+ * If [fillHeight] is `true`, the card will grow vertically to fill all available space in its
+ * parent. If not, it'll only be as tall as needed to show its UI.
+ */
+@Composable
+private fun ContentScope.CardForeground(
+    viewModel: MediaCardViewModel,
+    threeRows: Boolean,
+    fillHeight: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    // Can't use a Crossfade composable because of the custom layout logic below. Animate the alpha
+    // of the guts (and, indirectly, of the content) from here.
+    val gutsAlphaAnimatable = remember { Animatable(0f) }
+    val isGutsVisible = viewModel.guts.isVisible
+    LaunchedEffect(isGutsVisible) { gutsAlphaAnimatable.animateTo(if (isGutsVisible) 1f else 0f) }
+
+    // Use a custom layout to measure the content even if the content is being hidden because the
+    // internal guts are showing. This is needed because only the content knows the size the of the
+    // card and the guts are set to be the same size of the content.
+    Layout(
+        content = {
+            CardForegroundContent(
+                viewModel = viewModel,
+                threeRows = threeRows,
+                fillHeight = fillHeight,
+                modifier =
+                    Modifier.graphicsLayer {
+                        compositingStrategy = CompositingStrategy.ModulateAlpha
+                        alpha = 1f - gutsAlphaAnimatable.value
+                    },
+            )
+
+            CardGuts(
+                viewModel = viewModel.guts,
+                modifier =
+                    Modifier.graphicsLayer {
+                        compositingStrategy = CompositingStrategy.ModulateAlpha
+                        alpha = gutsAlphaAnimatable.value
+                    },
+            )
+        },
+        modifier = modifier,
+    ) { measurables, constraints ->
+        check(measurables.size == 2)
+        val contentPlaceable = measurables[0].measure(constraints)
+        // Guts should always have the exact dimensions as the content, even if we don't show the
+        // content.
+        val gutsPlaceable =
+            measurables[1].measure(
+                Constraints.fixed(contentPlaceable.width, contentPlaceable.height)
+            )
+
+        layout(contentPlaceable.measuredWidth, contentPlaceable.measuredHeight) {
+            if (!viewModel.guts.isVisible || gutsAlphaAnimatable.isRunning) {
+                contentPlaceable.place(0, 0)
+            }
+            if (viewModel.guts.isVisible || gutsAlphaAnimatable.isRunning) {
+                gutsPlaceable.place(0, 0)
+            }
+        }
+    }
+}
+
+@Composable
+private fun ContentScope.CardForegroundContent(
+    viewModel: MediaCardViewModel,
+    threeRows: Boolean,
+    fillHeight: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    Column(
+        modifier =
+            modifier
+                .combinedClickable(
+                    onClick = viewModel.onClick,
+                    onLongClick = viewModel.onLongClick,
+                    onClickLabel = viewModel.onClickLabel,
+                )
+                .padding(16.dp)
+    ) {
+        // Always add the first/top row, regardless of presentation style.
+        Row(verticalAlignment = Alignment.CenterVertically) {
+            // Icon.
+            Icon(
+                icon = viewModel.icon,
+                tint = LocalAndroidColorScheme.current.primaryFixed,
+                modifier = Modifier.size(24.dp).clip(CircleShape),
+            )
+            Spacer(modifier = Modifier.weight(1f))
+            viewModel.outputSwitcherChips.fastForEach { chip ->
+                OutputSwitcherChip(viewModel = chip, modifier = Modifier.padding(start = 8.dp))
+            }
+        }
+
+        // If the card is taller than necessary to show all the rows, this adds spacing
+        // between the top row and the rows below, anchoring the next rows to the bottom
+        // of the card.
+        if (fillHeight) {
+            Spacer(Modifier.weight(1f))
+        }
+
+        if (threeRows) {
+            // Three row presentation style.
+            //
+            // Second row.
+            Row(
+                verticalAlignment = Alignment.CenterVertically,
+                modifier = Modifier.padding(top = 16.dp),
+            ) {
+                Metadata(
+                    title = viewModel.title,
+                    subtitle = viewModel.subtitle,
+                    color = Color.White,
+                    modifier = Modifier.weight(1f).padding(end = 8.dp),
+                )
+
+                AnimatedVisibility(visible = viewModel.playPauseAction.isVisible) {
+                    PlayPauseAction(
+                        viewModel = viewModel.playPauseAction,
+                        buttonWidth = 48.dp,
+                        buttonColor = LocalAndroidColorScheme.current.primaryFixed,
+                        iconColor = LocalAndroidColorScheme.current.onPrimaryFixed,
+                        buttonCornerRadius = { isPlaying -> if (isPlaying) 16.dp else 48.dp },
+                    )
+                }
+            }
+
+            // Third row.
+            Row(
+                horizontalArrangement = Arrangement.spacedBy(8.dp),
+                verticalAlignment = Alignment.CenterVertically,
+                modifier = Modifier.padding(top = 24.dp),
+            ) {
+                Navigation(viewModel = viewModel.seekBar, isSeekBarVisible = true)
+                viewModel.additionalActions.fastForEachIndexed { index, action ->
+                    SecondaryAction(
+                        viewModel = action,
+                        element = Media.Elements.additionalActionButton(index),
+                    )
+                }
+            }
+        } else {
+            // Two row presentation style.
+            //
+            // Bottom row.
+            Row(
+                verticalAlignment = Alignment.CenterVertically,
+                modifier = Modifier.padding(top = 36.dp),
+            ) {
+                Metadata(
+                    title = viewModel.title,
+                    subtitle = viewModel.subtitle,
+                    color = Color.White,
+                    modifier = Modifier.weight(1f).padding(end = 8.dp),
+                )
+
+                Navigation(
+                    viewModel = viewModel.seekBar,
+                    isSeekBarVisible = false,
+                    modifier = Modifier.padding(end = 8.dp),
+                )
+
+                PlayPauseAction(
+                    viewModel = viewModel.playPauseAction,
+                    buttonWidth = 48.dp,
+                    buttonColor = LocalAndroidColorScheme.current.primaryFixed,
+                    iconColor = LocalAndroidColorScheme.current.onPrimaryFixed,
+                    buttonCornerRadius = { isPlaying -> if (isPlaying) 16.dp else 48.dp },
+                )
+            }
+        }
+    }
+}
+
+/**
+ * Renders a simplified version of [CardForeground] that puts everything on a single row and doesn't
+ * support the guts.
+ */
+@Composable
+private fun ContentScope.CompactCardForeground(
+    viewModel: MediaCardViewModel,
+    modifier: Modifier = Modifier,
+) {
+    Row(
+        horizontalArrangement = Arrangement.spacedBy(16.dp),
+        verticalAlignment = Alignment.CenterVertically,
+        modifier =
+            modifier
+                .clickable(onClick = viewModel.onClick, onClickLabel = viewModel.onClickLabel)
+                .background(MaterialTheme.colorScheme.surfaceContainer)
+                .padding(16.dp),
+    ) {
+        Icon(
+            icon = viewModel.icon,
+            tint = MaterialTheme.colorScheme.onSurface,
+            modifier = Modifier.size(24.dp),
+        )
+
+        Metadata(
+            title = viewModel.title,
+            subtitle = viewModel.subtitle,
+            color = MaterialTheme.colorScheme.onSurface,
+            modifier = Modifier.weight(1f),
+        )
+
+        SecondaryAction(
+            viewModel = viewModel.outputSwitcherChipButton,
+            element = Media.Elements.OutputSwitcherButton,
+            iconColor = MaterialTheme.colorScheme.onSurface,
+        )
+
+        val nextAction = (viewModel.seekBar as? MediaSeekBarViewModel.Showing)?.next
+        if (nextAction != null) {
+            SecondaryAction(
+                viewModel = nextAction,
+                element = Media.Elements.NextButton,
+                iconColor = MaterialTheme.colorScheme.onSurface,
+            )
+        }
+
+        AnimatedVisibility(visible = viewModel.playPauseAction.isVisible) {
+            PlayPauseAction(
+                viewModel = viewModel.playPauseAction,
+                buttonWidth = 72.dp,
+                buttonColor = MaterialTheme.colorScheme.primaryContainer,
+                iconColor = MaterialTheme.colorScheme.onPrimaryContainer,
+                buttonCornerRadius = { isPlaying -> if (isPlaying) 16.dp else 24.dp },
+            )
+        }
+    }
+}
+
+/** Renders the background of a card, loading the artwork and showing an overlay on top of it. */
+@Composable
+private fun CardBackground(imageLoader: suspend () -> ImageBitmap, modifier: Modifier = Modifier) {
+    var image: ImageBitmap? by remember { mutableStateOf(null) }
+    LaunchedEffect(imageLoader) {
+        image = null
+        image = imageLoader()
+    }
+
+    val gradientBaseColor = MaterialTheme.colorScheme.onSurface
+    Box(
+        modifier =
+            modifier.drawWithContent {
+                // Draw the content of the box (loaded art or placeholder).
+                drawContent()
+
+                if (image != null) {
+                    // Then draw the overlay.
+                    drawRect(
+                        brush =
+                            Brush.radialGradient(
+                                0f to gradientBaseColor.copy(alpha = 0.65f),
+                                1f to gradientBaseColor.copy(alpha = 0.75f),
+                                center = size.center,
+                                radius = max(size.width, size.height) / 2,
+                            )
+                    )
+                }
+            }
+    ) {
+        image?.let { loadedImage ->
+            // Loaded art.
+            Image(
+                bitmap = loadedImage,
+                contentDescription = null,
+                contentScale = ContentScale.Crop,
+                modifier = Modifier.matchParentSize(),
+            )
+        }
+            ?: run {
+                // Placeholder.
+                Box(Modifier.background(MaterialTheme.colorScheme.onSurface).matchParentSize())
+            }
+    }
+}
+
+/**
+ * Renders the navigation UI (seek bar and/or previous/next buttons).
+ *
+ * If [isSeekBarVisible] is `false`, the seek bar will not be included in the layout, even if it
+ * would otherwise be showing based on the view-model alone. This is meant for callers to decide
+ * whether they'd like to show the seek bar in addition to the prev/next buttons or just show the
+ * buttons.
+ */
+@Composable
+private fun ContentScope.Navigation(
+    viewModel: MediaSeekBarViewModel,
+    isSeekBarVisible: Boolean,
+    modifier: Modifier = Modifier,
+) {
+    when (viewModel) {
+        is MediaSeekBarViewModel.Showing -> {
+            Row(
+                horizontalArrangement = Arrangement.spacedBy(8.dp),
+                verticalAlignment = Alignment.CenterVertically,
+                modifier = modifier,
+            ) {
+                viewModel.previous?.let {
+                    SecondaryAction(viewModel = it, element = Media.Elements.PrevButton)
+                }
+
+                val interactionSource = remember { MutableInteractionSource() }
+                val colors =
+                    colors(
+                        activeTrackColor = Color.White,
+                        inactiveTrackColor = Color.White.copy(alpha = 0.3f),
+                        thumbColor = Color.White,
+                    )
+                if (isSeekBarVisible) {
+                    // To allow the seek bar slider to fade in and out, it's tagged as an element.
+                    Element(key = Media.Elements.SeekBarSlider, modifier = Modifier.weight(1f)) {
+                        Slider(
+                            interactionSource = interactionSource,
+                            value = viewModel.progress,
+                            onValueChange = { progress -> viewModel.onScrubChange(progress) },
+                            onValueChangeFinished = { viewModel.onScrubFinished() },
+                            colors = colors,
+                            thumb = {
+                                SeekBarThumb(interactionSource = interactionSource, colors = colors)
+                            },
+                            track = { sliderState ->
+                                SeekBarTrack(
+                                    sliderState = sliderState,
+                                    isSquiggly = viewModel.isSquiggly,
+                                    colors = colors,
+                                    modifier = Modifier.fillMaxWidth(),
+                                )
+                            },
+                            modifier = Modifier.fillMaxWidth(),
+                        )
+                    }
+                }
+
+                viewModel.next?.let {
+                    SecondaryAction(viewModel = it, element = Media.Elements.NextButton)
+                }
+            }
+        }
+
+        is MediaSeekBarViewModel.Hidden -> Unit
+    }
+}
+
+/** Renders the thumb of the seek bar. */
+@Composable
+private fun SeekBarThumb(
+    interactionSource: MutableInteractionSource,
+    colors: SliderColors,
+    modifier: Modifier = Modifier,
+) {
+    val interactions = remember { mutableStateListOf<Interaction>() }
+    LaunchedEffect(interactionSource) {
+        interactionSource.interactions.collect { interaction ->
+            when (interaction) {
+                is PressInteraction.Press -> interactions.add(interaction)
+                is PressInteraction.Release -> interactions.remove(interaction.press)
+                is PressInteraction.Cancel -> interactions.remove(interaction.press)
+                is DragInteraction.Start -> interactions.add(interaction)
+                is DragInteraction.Stop -> interactions.remove(interaction.start)
+                is DragInteraction.Cancel -> interactions.remove(interaction.start)
+            }
+        }
+    }
+
+    Spacer(
+        modifier
+            .size(width = 4.dp, height = 16.dp)
+            .hoverable(interactionSource = interactionSource)
+            .background(color = colors.thumbColor, shape = RoundedCornerShape(16.dp))
+    )
+}
+
+/**
+ * Renders the track of the seek bar.
+ *
+ * If [isSquiggly] is `true`, the part to the left of the thumb will animate a squiggly line that
+ * oscillates up and down. The [waveLength] and [amplitude] control the geometry of the squiggle and
+ * the [waveSpeedDpPerSec] controls the speed by which it seems to "move" horizontally.
+ */
+@Composable
+private fun SeekBarTrack(
+    sliderState: SliderState,
+    isSquiggly: Boolean,
+    colors: SliderColors,
+    modifier: Modifier = Modifier,
+    waveLength: Dp = 20.dp,
+    amplitude: Dp = 3.dp,
+    waveSpeedDpPerSec: Dp = 8.dp,
+) {
+    // Animating the amplitude allows the squiggle to gradually grow to its full height or shrink
+    // back to a flat line as needed.
+    val animatedAmplitude by
+        animateDpAsState(
+            targetValue = if (isSquiggly) amplitude else 0.dp,
+            label = "SeekBarTrack.amplitude",
+        )
+
+    // This animates the horizontal movement of the squiggle.
+    val animatedWaveOffset = remember { Animatable(0f) }
+
+    LaunchedEffect(isSquiggly) {
+        if (isSquiggly) {
+            animatedWaveOffset.snapTo(0f)
+            animatedWaveOffset.animateTo(
+                targetValue = 1f,
+                animationSpec =
+                    infiniteRepeatable(
+                        animation =
+                            tween(
+                                durationMillis = (1000 * (waveLength / waveSpeedDpPerSec)).toInt(),
+                                easing = LinearEasing,
+                            ),
+                        repeatMode = RepeatMode.Restart,
+                    ),
+            )
+        }
+    }
+
+    // Render the track.
+    Canvas(modifier = modifier) {
+        val thumbPositionPx = size.width * sliderState.value
+
+        // The squiggly part before the thumb.
+        if (thumbPositionPx > 0) {
+            val amplitudePx = amplitude.toPx()
+            val animatedAmplitudePx = animatedAmplitude.toPx()
+            val waveLengthPx = waveLength.toPx()
+
+            val path =
+                Path().apply {
+                    val halfWaveLengthPx = waveLengthPx / 2
+                    val halfWaveCount = (thumbPositionPx / halfWaveLengthPx).toInt()
+
+                    repeat(halfWaveCount + 3) { index ->
+                        // Draw a half wave (either a hill or a valley shape starting and ending on
+                        // the horizontal center).
+                        relativeQuadraticTo(
+                            // The control point for the bezier curve is on top of the peak of the
+                            // hill or the very center bottom of the valley shape.
+                            dx1 = halfWaveLengthPx / 2,
+                            dy1 = if (index % 2 == 0) -animatedAmplitudePx else animatedAmplitudePx,
+                            // Advance horizontally, half a wave length at a time.
+                            dx2 = halfWaveLengthPx,
+                            dy2 = 0f,
+                        )
+                    }
+                }
+
+            // Now that the squiggle is rendered a bit past the thumb, clip off the part that passed
+            // the thumb. It's easier to clip the extra squiggle than to figure out the bezier curve
+            // for part of a hill/valley.
+            clipRect(
+                left = 0f,
+                top = -amplitudePx,
+                right = thumbPositionPx,
+                bottom = amplitudePx * 2,
+            ) {
+                translate(left = -waveLengthPx * animatedWaveOffset.value, top = 0f) {
+                    // Actually render the squiggle.
+                    drawPath(
+                        path = path,
+                        color = colors.activeTrackColor,
+                        style = Stroke(width = 2.dp.toPx(), cap = StrokeCap.Round),
+                    )
+                }
+            }
+        }
+
+        // The flat line after the thumb.
+        drawLine(
+            color = colors.inactiveTrackColor,
+            start = Offset(thumbPositionPx, 0f),
+            end = Offset(size.width, 0f),
+            strokeWidth = 2.dp.toPx(),
+            cap = StrokeCap.Round,
+        )
+    }
+}
+
+/** Renders the internal "guts" of a card. */
+@Composable
+private fun CardGuts(viewModel: MediaCardGutsViewModel, modifier: Modifier = Modifier) {
+    Box(
+        modifier =
+            modifier.pointerInput(Unit) { detectLongPressGesture { viewModel.onLongClick() } }
+    ) {
+        // Settings button.
+        Icon(
+            icon = checkNotNull(viewModel.settingsButton.icon),
+            modifier =
+                Modifier.align(Alignment.TopEnd).padding(top = 16.dp, end = 16.dp).clickable {
+                    viewModel.settingsButton.onClick()
+                },
+        )
+
+        //  Content.
+        Column(
+            horizontalAlignment = Alignment.CenterHorizontally,
+            verticalArrangement = Arrangement.spacedBy(16.dp),
+            modifier =
+                Modifier.align(Alignment.BottomCenter)
+                    .fillMaxWidth()
+                    .padding(start = 16.dp, end = 32.dp, bottom = 40.dp),
+        ) {
+            Text(text = viewModel.text, color = Color.White)
+
+            Row(
+                horizontalArrangement = Arrangement.spacedBy(8.dp),
+                verticalAlignment = Alignment.CenterVertically,
+            ) {
+                PlatformButton(
+                    onClick = viewModel.primaryAction.onClick,
+                    colors = ButtonDefaults.buttonColors(containerColor = Color.White),
+                ) {
+                    Text(
+                        text = checkNotNull(viewModel.primaryAction.text),
+                        color = LocalAndroidColorScheme.current.onPrimaryFixed,
+                    )
+                }
+
+                viewModel.secondaryAction?.let { button ->
+                    PlatformOutlinedButton(
+                        onClick = button.onClick,
+                        border = BorderStroke(width = 1.dp, color = Color.White),
+                    ) {
+                        Text(text = checkNotNull(button.text), color = Color.White)
+                    }
+                }
+            }
+        }
+    }
+}
+
+/** Renders the metadata labels of a track. */
+@Composable
+private fun ContentScope.Metadata(
+    title: String,
+    subtitle: String,
+    color: Color,
+    modifier: Modifier = Modifier,
+) {
+    // This element can be animated when switching between scenes inside a media card.
+    Element(key = Media.Elements.Metadata, modifier = modifier) {
+        // When the title and/or subtitle change, crossfade between the old and the new.
+        Crossfade(targetState = title to subtitle, label = "Labels.crossfade") { (title, subtitle)
+            ->
+            Column {
+                Text(
+                    text = title,
+                    style = MaterialTheme.typography.bodyLarge,
+                    color = color,
+                    maxLines = 1,
+                    overflow = TextOverflow.Ellipsis,
+                )
+
+                Text(
+                    text = subtitle,
+                    style = MaterialTheme.typography.bodyMedium,
+                    color = color,
+                    maxLines = 1,
+                    overflow = TextOverflow.Ellipsis,
+                )
+            }
+        }
+    }
+}
+
+/**
+ * Renders a small chip showing the current output device and providing a way to switch to a
+ * different output device.
+ */
+@Composable
+private fun OutputSwitcherChip(
+    viewModel: MediaOutputSwitcherChipViewModel,
+    modifier: Modifier = Modifier,
+) {
+    PlatformButton(
+        onClick = viewModel.onClick,
+        colors =
+            ButtonDefaults.buttonColors(
+                containerColor = LocalAndroidColorScheme.current.primaryFixed
+            ),
+        contentPadding = PaddingValues(start = 8.dp, end = 12.dp, top = 4.dp, bottom = 4.dp),
+        modifier = modifier.height(24.dp),
+    ) {
+        Icon(
+            icon = viewModel.icon,
+            tint = LocalAndroidColorScheme.current.onPrimaryFixed,
+            modifier = Modifier.size(16.dp),
+        )
+        viewModel.text?.let {
+            Spacer(Modifier.size(4.dp))
+            Text(
+                text = viewModel.text,
+                style = MaterialTheme.typography.bodySmall,
+                color = LocalAndroidColorScheme.current.onPrimaryFixed,
+            )
+        }
+    }
+}
+
+/** Renders the primary action of media controls: the play/pause button. */
+@Composable
+private fun ContentScope.PlayPauseAction(
+    viewModel: MediaPlayPauseActionViewModel,
+    buttonWidth: Dp,
+    buttonColor: Color,
+    iconColor: Color,
+    buttonCornerRadius: (isPlaying: Boolean) -> Dp,
+    modifier: Modifier = Modifier,
+) {
+    val cornerRadius: Dp by
+        animateDpAsState(
+            targetValue = buttonCornerRadius(viewModel.state != MediaSessionState.Paused),
+            label = "PlayPauseAction.cornerRadius",
+        )
+    // This element can be animated when switching between scenes inside a media card.
+    Element(key = Media.Elements.PlayPauseButton, modifier = modifier) {
+        PlatformButton(
+            onClick = viewModel.onClick,
+            colors = ButtonDefaults.buttonColors(containerColor = buttonColor),
+            shape = RoundedCornerShape(cornerRadius),
+            modifier = Modifier.size(width = buttonWidth, height = 48.dp),
+        ) {
+            when (viewModel.state) {
+                is MediaSessionState.Playing,
+                is MediaSessionState.Paused -> {
+                    // TODO(b/399860531): load this expensive-to-load animated vector drawable off
+                    //  the main thread.
+                    val iconResource = checkNotNull(viewModel.icon)
+                    Icon(
+                        painter =
+                            rememberAnimatedVectorPainter(
+                                animatedImageVector =
+                                    AnimatedImageVector.animatedVectorResource(
+                                        id = iconResource.res
+                                    ),
+                                atEnd = viewModel.state == MediaSessionState.Playing,
+                            ),
+                        contentDescription = iconResource.contentDescription?.load(),
+                        tint = iconColor,
+                        modifier = Modifier.size(24.dp),
+                    )
+                }
+                is MediaSessionState.Buffering -> {
+                    CircularProgressIndicator(color = iconColor, modifier = Modifier.size(24.dp))
+                }
+            }
+        }
+    }
+}
+
+/**
+ * Renders an icon button for an action that's not the play/pause action.
+ *
+ * If [element] is provided, the secondary action element will be able to animate when switching
+ * between scenes inside a media card.
+ */
+@Composable
+private fun ContentScope.SecondaryAction(
+    viewModel: MediaSecondaryActionViewModel,
+    modifier: Modifier = Modifier,
+    element: ElementKey? = null,
+    iconColor: Color = Color.White,
+) {
+    if (element != null) {
+        Element(key = element, modifier = modifier) {
+            SecondaryActionContent(viewModel = viewModel, iconColor = iconColor)
+        }
+    } else {
+        SecondaryActionContent(viewModel = viewModel, iconColor = iconColor, modifier = modifier)
+    }
+}
+
+/** The content of a [SecondaryAction]. */
+@Composable
+private fun SecondaryActionContent(
+    viewModel: MediaSecondaryActionViewModel,
+    iconColor: Color,
+    modifier: Modifier = Modifier,
+) {
+    PlatformIconButton(
+        onClick = viewModel.onClick,
+        iconResource = (viewModel.icon as Icon.Resource).res,
+        contentDescription = viewModel.icon.contentDescription?.load(),
+        colors = IconButtonDefaults.iconButtonColors(contentColor = iconColor),
+        enabled = viewModel.isEnabled,
+        modifier = modifier.size(48.dp).padding(13.dp),
+    )
+}
+
+/** Enumerates all supported media presentation styles. */
+enum class MediaPresentationStyle {
+    /** The "normal" 3-row carousel look. */
+    Default,
+    /** Similar to [Default] but not as tall (2-row carousel look). */
+    Compressed,
+    /** A special single-row treatment that fits nicely in quick settings. */
+    Compact,
+}
+
+private object Media {
+
+    /**
+     * Scenes.
+     *
+     * The implementation uses a [SceneTransitionLayout] to smoothly animate transitions between
+     * different card layouts. Each card layout is identified as its own "scene" and the STL
+     * framework takes care of animating the layouts and their elements as the card morphs between
+     * scenes.
+     */
+    object Scenes {
+        /** The "normal" 3-row carousel look. */
+        val Default = SceneKey("default")
+        /** Similar to [Default] but not as tall (2-row carousel look). */
+        val Compressed = SceneKey("compressed")
+        /** A special single-row treatment that fits nicely in quick settings. */
+        val Compact = SceneKey("compact")
+    }
+
+    /** Definitions of how scene changes are transition-animated. */
+    val Transitions = transitions {
+        from(Scenes.Default, to = Scenes.Compact) {}
+        from(Scenes.Default, to = Scenes.Compressed) { fade(Elements.SeekBarSlider) }
+        from(Scenes.Compact, to = Scenes.Compressed) { fade(Elements.SeekBarSlider) }
+    }
+
+    /**
+     * Element keys.
+     *
+     * Composables that are wrapped in [ContentScope.Element] with one of these as their `key`
+     * parameter will automatically be picked up by the STL transition animation framework and will
+     * be animated from their bounds in the original scene to their bounds in the destination scene.
+     *
+     * In addition, tagging such elements with a key allows developers to customize the transition
+     * animations even further.
+     */
+    object Elements {
+        val PlayPauseButton = ElementKey("play_pause")
+        val Metadata = ElementKey("metadata")
+        val PrevButton = ElementKey("prev")
+        val NextButton = ElementKey("next")
+        val SeekBarSlider = ElementKey("seek_bar_slider")
+        val OutputSwitcherButton = ElementKey("output_switcher")
+
+        fun additionalActionButton(index: Int): ElementKey {
+            return ElementKey("additional_action_$index")
+        }
+    }
+}
+
+private fun MediaPresentationStyle.toScene(): SceneKey {
+    return when (this) {
+        MediaPresentationStyle.Default -> Media.Scenes.Default
+        MediaPresentationStyle.Compressed -> Media.Scenes.Compressed
+        MediaPresentationStyle.Compact -> Media.Scenes.Compact
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCardGutsViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCardGutsViewModel.kt
new file mode 100644
index 0000000..61e3bdc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCardGutsViewModel.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.media.remedia.ui.viewmodel
+
+data class MediaCardGutsViewModel(
+    val isVisible: Boolean,
+    val text: String,
+    val primaryAction: MediaGutsButtonViewModel,
+    val secondaryAction: MediaGutsButtonViewModel? = null,
+    val settingsButton: MediaGutsSettingsButtonViewModel,
+    val onLongClick: () -> Unit,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCardViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCardViewModel.kt
new file mode 100644
index 0000000..ecd6e6d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaCardViewModel.kt
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.media.remedia.ui.viewmodel
+
+import androidx.compose.runtime.Stable
+import androidx.compose.ui.graphics.ImageBitmap
+import com.android.systemui.common.shared.model.Icon
+
+/** Models UI state for a media card. */
+@Stable
+interface MediaCardViewModel {
+    /**
+     * Identifier. Must be unique across all media cards currently shown, to help the horizontal
+     * pager in the UI.
+     */
+    val key: Any
+
+    val icon: Icon
+
+    /**
+     * A callback to load the artwork for the media shown on this card. This callback will be
+     * invoked on the main thread, it's up to the implementation to move the loading off the main
+     * thread.
+     */
+    val artLoader: suspend () -> ImageBitmap
+
+    val title: String
+
+    val subtitle: String
+
+    val playPauseAction: MediaPlayPauseActionViewModel
+
+    val seekBar: MediaSeekBarViewModel
+
+    val additionalActions: List<MediaSecondaryActionViewModel>
+
+    val guts: MediaCardGutsViewModel
+
+    val outputSwitcherChips: List<MediaOutputSwitcherChipViewModel>
+
+    /** Simple icon-only version of the output switcher for use in compact UIs. */
+    val outputSwitcherChipButton: MediaSecondaryActionViewModel
+
+    val onClick: () -> Unit
+
+    /** Accessibility string for the click action of the card. */
+    val onClickLabel: String?
+
+    val onLongClick: () -> Unit
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaGutsButtonViewModel.kt
similarity index 71%
rename from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
rename to packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaGutsButtonViewModel.kt
index 9b7cd70..6ce0a01 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaGutsButtonViewModel.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,8 +13,7 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.media.remedia.ui.viewmodel
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+data class MediaGutsButtonViewModel(val text: String, val onClick: () -> Unit)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaGutsSettingsButtonViewModel.kt
similarity index 68%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaGutsSettingsButtonViewModel.kt
index 9b7cd70..fabfe0e 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaGutsSettingsButtonViewModel.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,8 +13,9 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.media.remedia.ui.viewmodel
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import com.android.systemui.common.shared.model.Icon
+
+data class MediaGutsSettingsButtonViewModel(val icon: Icon, val onClick: () -> Unit)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaOutputSwitcherChipViewModel.kt
similarity index 65%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaOutputSwitcherChipViewModel.kt
index 9b7cd70..f2724da 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaOutputSwitcherChipViewModel.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,8 +13,13 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.media.remedia.ui.viewmodel
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import com.android.systemui.common.shared.model.Icon
+
+data class MediaOutputSwitcherChipViewModel(
+    val icon: Icon,
+    val text: String? = null,
+    val onClick: () -> Unit,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaPlayPauseActionViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaPlayPauseActionViewModel.kt
new file mode 100644
index 0000000..4cb11bc
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaPlayPauseActionViewModel.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.media.remedia.ui.viewmodel
+
+import com.android.systemui.common.shared.model.Icon
+import com.android.systemui.media.remedia.shared.model.MediaSessionState
+
+/** Models UI state for the play/pause action button within media controls. */
+data class MediaPlayPauseActionViewModel(
+    val isVisible: Boolean,
+    val state: MediaSessionState,
+    val icon: Icon.Resource?,
+    val onClick: () -> Unit,
+)
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaSecondaryActionViewModel.kt
similarity index 60%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaSecondaryActionViewModel.kt
index 9b7cd70..a480680 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaSecondaryActionViewModel.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,8 +13,14 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.media.remedia.ui.viewmodel
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import com.android.systemui.common.shared.model.Icon
+
+/** Models UI state for a secondary action button within media controls. */
+data class MediaSecondaryActionViewModel(
+    val icon: Icon,
+    val isEnabled: Boolean,
+    val onClick: () -> Unit,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaSeekBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaSeekBarViewModel.kt
new file mode 100644
index 0000000..f1ced6b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/media/remedia/ui/viewmodel/MediaSeekBarViewModel.kt
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.media.remedia.ui.viewmodel
+
+import androidx.annotation.FloatRange
+
+/** Models UI state for the seek bar. */
+sealed interface MediaSeekBarViewModel {
+
+    /** The seek bar should be showing. */
+    data class Showing(
+        /** The progress to show on the seek bar, between `0` and `1`. */
+        @FloatRange(from = 0.0, to = 1.0) val progress: Float,
+        /** The previous button; or `null` if it should be absent in the UI. */
+        val previous: MediaSecondaryActionViewModel?,
+        /** The next button; or `null` if it should be absent in the UI. */
+        val next: MediaSecondaryActionViewModel?,
+        /**
+         * Whether the portion of the seek bar track before the thumb should show the squiggle
+         * animation.
+         */
+        val isSquiggly: Boolean,
+        /**
+         * Whether the UI should show as "scrubbing" because the user is actively moving the thumb
+         * of the seek bar.
+         */
+        val isScrubbing: Boolean,
+        /**
+         * A callback to invoke while the user is "scrubbing" (e.g. actively moving the thumb of the
+         * seek bar). The position/progress of the actual track should not be changed during this
+         * time.
+         */
+        val onScrubChange: (progress: Float) -> Unit,
+        /**
+         * A callback to invoke once the user finishes "scrubbing" (e.g. stopped moving the thumb of
+         * the seek bar). The position/progress should be committed.
+         */
+        val onScrubFinished: () -> Unit,
+    ) : MediaSeekBarViewModel
+
+    /** The seek bar should be hidden. */
+    data object Hidden : MediaSeekBarViewModel
+}
diff --git a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
index ea515c9..4559a7a 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SceneContainerPlugin.kt
@@ -25,6 +25,8 @@
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Overlays
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BOUNCER_SHOWING
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_COMMUNAL_HUB_SHOWING
 import com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
@@ -35,6 +37,7 @@
 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags
 import dagger.Lazy
 import javax.inject.Inject
+import kotlinx.coroutines.flow.StateFlow
 
 /**
  * A plugin for [SysUiState] that provides overrides for certain state flags that must be pulled
@@ -46,17 +49,28 @@
 constructor(
     private val sceneInteractor: Lazy<SceneInteractor>,
     private val occlusionInteractor: Lazy<SceneContainerOcclusionInteractor>,
+    private val shadeDisplaysRepository: Lazy<ShadeDisplaysRepository>,
 ) {
 
+    private val shadeDisplayId: StateFlow<Int> by lazy { shadeDisplaysRepository.get().displayId }
+
     /**
      * Returns an override value for the given [flag] or `null` if the scene framework isn't enabled
      * or if the flag value doesn't need to be overridden.
      */
-    fun flagValueOverride(@SystemUiStateFlags flag: Long): Boolean? {
+    fun flagValueOverride(@SystemUiStateFlags flag: Long, displayId: Int): Boolean? {
         if (!SceneContainerFlag.isEnabled) {
             return null
         }
 
+        if (ShadeWindowGoesAround.isEnabled && shadeDisplayId.value != displayId) {
+            // The shade is in another display. All flags related to the shade container will map to
+            // false on other displays now.
+            //
+            // Note that this assumes there is only one SceneContainer and it is only on the shade
+            // window display. If there will be more, this will need to be revisited
+            return false
+        }
         val transitionState = sceneInteractor.get().transitionState.value
         val idleTransitionStateOrNull = transitionState as? ObservableTransitionState.Idle
         val invisibleDueToOcclusion = occlusionInteractor.get().invisibleDueToOcclusion.value
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUIStateChange.kt b/packages/SystemUI/src/com/android/systemui/model/SysUIStateChange.kt
new file mode 100644
index 0000000..aaed606
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUIStateChange.kt
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.model
+
+import com.android.systemui.shared.system.QuickStepContract.getSystemUiStateString
+
+/**
+ * Represents a set of state changes. A bit can either be set to `true` or `false`.
+ *
+ * This is used in [SysUIStateDisplaysInteractor] to selectively change bits.
+ */
+class StateChange {
+    private var flagsToSet: Long = 0
+    private var flagsToClear: Long = 0
+
+    /**
+     * Sets the [state] of the given [bit].
+     *
+     * @return `this` for chaining purposes
+     */
+    fun setFlag(bit: Long, state: Boolean): StateChange {
+        if (state) {
+            flagsToSet = flagsToSet or bit
+            flagsToClear = flagsToClear and bit.inv()
+        } else {
+            flagsToClear = flagsToClear or bit
+            flagsToSet = flagsToSet and bit.inv()
+        }
+        return this
+    }
+
+    fun hasChanges() = flagsToSet != 0L || flagsToClear != 0L
+
+    /**
+     * Applies all changed flags to [sysUiState].
+     *
+     * Note this doesn't call [SysUiState.commitUpdate].
+     */
+    fun applyTo(sysUiState: SysUiState) {
+        iterateBits(flagsToSet or flagsToClear) { bit ->
+            val isBitSetInNewState = flagsToSet and bit != 0L
+            sysUiState.setFlag(bit, isBitSetInNewState)
+        }
+    }
+
+    fun applyTo(sysUiState: Long): Long {
+        var newState = sysUiState
+        newState = newState or flagsToSet
+        newState = newState and flagsToClear.inv()
+        return newState
+    }
+
+    private inline fun iterateBits(flags: Long, action: (bit: Long) -> Unit) {
+        var remaining = flags
+        while (remaining != 0L) {
+            val lowestBit = remaining and -remaining
+            action(lowestBit)
+
+            remaining -= lowestBit
+        }
+    }
+
+    /**
+     * Clears all the flags changed in a [sysUiState].
+     *
+     * Note this doesn't call [SysUiState.commitUpdate].
+     */
+    fun clearFrom(sysUiState: SysUiState) {
+        iterateBits(flagsToSet or flagsToClear) { bit -> sysUiState.setFlag(bit, false) }
+    }
+
+    fun clear() {
+        flagsToSet = 0
+        flagsToClear = 0
+    }
+
+    override fun toString(): String {
+        return """StateChange(flagsToSet=${getSystemUiStateString(flagsToSet)}, flagsToClear=${
+            getSystemUiStateString(
+                flagsToClear
+            )
+        })"""
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUIStateDispatcher.kt b/packages/SystemUI/src/com/android/systemui/model/SysUIStateDispatcher.kt
new file mode 100644
index 0000000..2bdd9a8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUIStateDispatcher.kt
@@ -0,0 +1,77 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.model
+
+import android.view.Display
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
+import java.util.concurrent.CopyOnWriteArrayList
+import javax.inject.Inject
+
+/**
+ * Channels changes from several [SysUiState]s to a single callback.
+ *
+ * There are several [SysUiState]s (one per display). This class allows for listeners to listen to
+ * sysui state updates from any of those [SysUiState] instances.
+ *
+ *                      ┌────────────────────┐
+ *                      │ SysUIStateOverride │
+ *                      │ displayId=2        │
+ *                      └┬───────────────────┘
+ *                       │  ▲
+ * ┌───────────────┐     │  │  ┌────────────────────┐
+ * │ SysUIState    │     │  │  │ SysUIStateOverride │
+ * │ displayId=0   │     │  │  │ displayId=1        │
+ * └────────────┬──┘     │  │  └┬───────────────────┘
+ *              │        │  │   │ ▲
+ *              ▼        ▼  │   ▼ │
+ *            ┌─────────────┴─────┴─┐
+ *            │SysUiStateDispatcher │
+ *            └────────┬────────────┘
+ *                     │
+ *                     ▼
+ *             ┌──────────────────┐
+ *             │ listeners for    │
+ *             │ all displays     │
+ *             └──────────────────┘
+ */
+@SysUISingleton
+class SysUIStateDispatcher @Inject constructor() {
+
+    private val listeners = CopyOnWriteArrayList<SysUiState.SysUiStateCallback>()
+
+    /** Called from each [SysUiState] to propagate new state changes. */
+    fun dispatchSysUIStateChange(sysUiFlags: Long, displayId: Int) {
+        if (displayId != Display.DEFAULT_DISPLAY && !ShadeWindowGoesAround.isEnabled) return
+        listeners.forEach { listener ->
+            listener.onSystemUiStateChanged(sysUiFlags = sysUiFlags, displayId = displayId)
+        }
+    }
+
+    /**
+     * Registers a listener to listen for system UI state changes.
+     *
+     * Listeners will have [SysUiState.SysUiStateCallback.onSystemUiStateChanged] called whenever a
+     * system UI state changes.
+     */
+    fun registerListener(listener: SysUiState.SysUiStateCallback) {
+        listeners += listener
+    }
+
+    fun unregisterListener(listener: SysUiState.SysUiStateCallback) {
+        listeners -= listener
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUIStateOverride.kt b/packages/SystemUI/src/com/android/systemui/model/SysUIStateOverride.kt
new file mode 100644
index 0000000..89e06e2
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUIStateOverride.kt
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.model
+
+import android.view.Display
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+/**
+ * This class is used to provide per-display overrides for only certain flags.
+ *
+ * While some of the [SystemUiStateFlags] are per display (e.g. shade expansion, dialog visible),
+ * some of them are device specific (e.g. whether it's awake or not). A [SysUIStateOverride] is
+ * created for each display that is not [Display.DEFAULT_DISPLAY], and if some flags are set on it,
+ * they will override whatever the default display state had in those.
+ */
+class SysUIStateOverride
+@AssistedInject
+constructor(
+    @Assisted override val displayId: Int,
+    private val sceneContainerPlugin: SceneContainerPlugin?,
+    dumpManager: DumpManager,
+    private val defaultDisplayState: SysUiState,
+    private val stateDispatcher: SysUIStateDispatcher,
+) : SysUiStateImpl(displayId, sceneContainerPlugin, dumpManager, stateDispatcher) {
+
+    private val override = StateChange()
+    private var lastSentFlags = defaultDisplayState.flags
+
+    private val defaultFlagsChangedCallback = { _: Long, otherDisplayId: Int ->
+        if (otherDisplayId == Display.DEFAULT_DISPLAY) {
+            commitUpdate()
+        }
+    }
+
+    override fun start() {
+        super.start()
+        stateDispatcher.registerListener(defaultFlagsChangedCallback)
+    }
+
+    override fun destroy() {
+        super.destroy()
+        stateDispatcher.unregisterListener(defaultFlagsChangedCallback)
+    }
+
+    override fun commitUpdate() {
+        if (flags != lastSentFlags) {
+            stateDispatcher.dispatchSysUIStateChange(flags, displayId)
+            lastSentFlags = flags
+        }
+    }
+
+    override val flags: Long
+        get() = override.applyTo(defaultDisplayState.flags)
+
+    override fun setFlag(@SystemUiStateFlags flag: Long, enabled: Boolean): SysUiState {
+        val toSet = flagWithOptionalOverrides(flag, enabled, displayId, sceneContainerPlugin)
+        override.setFlag(flag, toSet)
+        return this
+    }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(displayId: Int): SysUIStateOverride
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/model/SysUiState.kt b/packages/SystemUI/src/com/android/systemui/model/SysUiState.kt
index ed190a1..e99ee7d 100644
--- a/packages/SystemUI/src/com/android/systemui/model/SysUiState.kt
+++ b/packages/SystemUI/src/com/android/systemui/model/SysUiState.kt
@@ -16,64 +16,125 @@
 package com.android.systemui.model
 
 import android.util.Log
+import android.view.Display
 import com.android.systemui.Dumpable
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.settings.DisplayTracker
+import com.android.systemui.display.data.repository.PerDisplayInstanceProviderWithTeardown
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.model.SysUiState.SysUiStateCallback
 import com.android.systemui.shared.system.QuickStepContract
 import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
 import dalvik.annotation.optimization.NeverCompile
 import java.io.PrintWriter
+import javax.inject.Inject
 
 /** Contains sysUi state flags and notifies registered listeners whenever changes happen. */
-@SysUISingleton
-class SysUiState(
-    private val displayTracker: DisplayTracker,
+interface SysUiState : Dumpable {
+    /**
+     * Add listener to be notified of changes made to SysUI state.
+     *
+     * The callback will also be called as part of this function.
+     */
+    fun addCallback(callback: SysUiStateCallback)
+
+    /** Removes a callback for state changes. */
+    fun removeCallback(callback: SysUiStateCallback)
+
+    /** Returns whether a flag is enabled in this state. */
+    fun isFlagEnabled(@SystemUiStateFlags flag: Long): Boolean {
+        return (flags and flag) != 0L
+    }
+
+    /** Returns the current sysui state flags. */
+    val flags: Long
+
+    /** Methods to this call can be chained together before calling [commitUpdate]. */
+    fun setFlag(@SystemUiStateFlags flag: Long, enabled: Boolean): SysUiState
+
+    /** Call to save all the flags updated from [setFlag]. */
+    @Deprecated("Each SysUIState instance is now display specific. Just use commitUpdate()")
+    fun commitUpdate(displayId: Int)
+
+    /** Call to save all the flags updated from [setFlag]. */
+    fun commitUpdate()
+
+    /** Callback to be notified whenever system UI state flags are changed. */
+    fun interface SysUiStateCallback {
+
+        /** To be called when any SysUiStateFlag gets updated for a specific [displayId]. */
+        fun onSystemUiStateChanged(@SystemUiStateFlags sysUiFlags: Long, displayId: Int)
+    }
+
+    /**
+     * Destroys an instance. It shouldn't be used anymore afterwards.
+     *
+     * This is mainly used to clean up instances associated with displays that are removed.
+     */
+    fun destroy()
+
+    /** Initializes the state after construction. */
+    fun start()
+
+    /** The display ID this instances is associated with */
+    val displayId: Int
+
+    companion object {
+        const val DEBUG: Boolean = false
+    }
+}
+
+private const val TAG = "SysUIState"
+
+open class SysUiStateImpl
+@AssistedInject
+constructor(
+    @Assisted override val displayId: Int,
     private val sceneContainerPlugin: SceneContainerPlugin?,
-) : Dumpable {
+    private val dumpManager: DumpManager,
+    private val stateDispatcher: SysUIStateDispatcher,
+) : SysUiState {
+
+    private val debugName
+        get() = "SysUiStateImpl-ForDisplay=$displayId"
+
+    override fun start() {
+        dumpManager.registerNormalDumpable(debugName, this)
+    }
+
     /** Returns the current sysui state flags. */
     @get:SystemUiStateFlags
     @SystemUiStateFlags
-    var flags: Long = 0
-        private set
+    override val flags: Long
+        get() = _flags
 
-    private val callbacks: MutableList<SysUiStateCallback> = ArrayList()
+    private var _flags: Long = 0
     private var flagsToSet: Long = 0
     private var flagsToClear: Long = 0
 
     /**
      * Add listener to be notified of changes made to SysUI state. The callback will also be called
      * as part of this function.
+     *
+     * Note that the listener would receive updates for all displays.
      */
-    fun addCallback(callback: SysUiStateCallback) {
-        callbacks.add(callback)
-        callback.onSystemUiStateChanged(flags)
+    override fun addCallback(callback: SysUiStateCallback) {
+        stateDispatcher.registerListener(callback)
+        callback.onSystemUiStateChanged(flags, displayId)
     }
 
     /** Callback will no longer receive events on state change */
-    fun removeCallback(callback: SysUiStateCallback) {
-        callbacks.remove(callback)
-    }
-
-    fun isFlagEnabled(@SystemUiStateFlags flag: Long): Boolean {
-        return (flags and flag) != 0L
+    override fun removeCallback(callback: SysUiStateCallback) {
+        stateDispatcher.unregisterListener(callback)
     }
 
     /** Methods to this call can be chained together before calling [.commitUpdate]. */
-    fun setFlag(@SystemUiStateFlags flag: Long, enabled: Boolean): SysUiState {
-        var enabled = enabled
-        val overrideOrNull = sceneContainerPlugin?.flagValueOverride(flag)
-        if (overrideOrNull != null && enabled != overrideOrNull) {
-            if (DEBUG) {
-                Log.d(
-                    TAG,
-                    "setFlag for flag $flag and value $enabled overridden to $overrideOrNull by scene container plugin",
-                )
-            }
+    override fun setFlag(@SystemUiStateFlags flag: Long, enabled: Boolean): SysUiState {
+        val toSet = flagWithOptionalOverrides(flag, enabled, displayId, sceneContainerPlugin)
 
-            enabled = overrideOrNull
-        }
-
-        if (enabled) {
+        if (toSet) {
             flagsToSet = flagsToSet or flag
         } else {
             flagsToClear = flagsToClear or flag
@@ -81,20 +142,22 @@
         return this
     }
 
-    /** Call to save all the flags updated from [.setFlag]. */
-    fun commitUpdate(displayId: Int) {
-        updateFlags(displayId)
+    @Deprecated(
+        "Each SysUIState instance is now display specific. Just use commitUpdate.",
+        ReplaceWith("commitUpdate()"),
+    )
+    override fun commitUpdate(displayId: Int) {
+        // TODO b/398011576 - handle updates for different displays.
+        commitUpdate()
+    }
+
+    override fun commitUpdate() {
+        updateFlags()
         flagsToSet = 0
         flagsToClear = 0
     }
 
-    private fun updateFlags(displayId: Int) {
-        if (displayId != displayTracker.defaultDisplayId) {
-            // Ignore non-default displays for now
-            Log.w(TAG, "Ignoring flag update for display: $displayId", Throwable())
-            return
-        }
-
+    private fun updateFlags() {
         var newState = flags
         newState = newState or flagsToSet
         newState = newState and flagsToClear.inv()
@@ -103,15 +166,12 @@
 
     /** Notify all those who are registered that the state has changed. */
     private fun notifyAndSetSystemUiStateChanged(newFlags: Long, oldFlags: Long) {
-        if (DEBUG) {
+        if (SysUiState.DEBUG) {
             Log.d(TAG, "SysUiState changed: old=$oldFlags new=$newFlags")
         }
         if (newFlags != oldFlags) {
-            callbacks.forEach { callback: SysUiStateCallback ->
-                callback.onSystemUiStateChanged(newFlags)
-            }
-
-            flags = newFlags
+            _flags = newFlags
+            stateDispatcher.dispatchSysUIStateChange(newFlags, displayId)
         }
     }
 
@@ -127,14 +187,62 @@
         pw.println(QuickStepContract.isAssistantGestureDisabled(flags))
     }
 
-    /** Callback to be notified whenever system UI state flags are changed. */
-    interface SysUiStateCallback {
-        /** To be called when any SysUiStateFlag gets updated */
-        fun onSystemUiStateChanged(@SystemUiStateFlags sysUiFlags: Long)
+    override fun destroy() {
+        dumpManager.unregisterDumpable(debugName)
+    }
+
+    @AssistedFactory
+    interface Factory {
+        /** Creates a new instance of [SysUiStateImpl] for a given [displayId]. */
+        fun create(displayId: Int): SysUiStateImpl
     }
 
     companion object {
         private val TAG: String = SysUiState::class.java.simpleName
-        const val DEBUG: Boolean = false
+    }
+}
+
+/** Returns the flag value taking into account [SceneContainerPlugin] potential overrides. */
+fun flagWithOptionalOverrides(
+    flag: Long,
+    enabled: Boolean,
+    displayId: Int,
+    sceneContainerPlugin: SceneContainerPlugin?,
+): Boolean {
+    var toSet = enabled
+    val overrideOrNull = sceneContainerPlugin?.flagValueOverride(flag = flag, displayId = displayId)
+    if (overrideOrNull != null && toSet != overrideOrNull) {
+        if (SysUiState.DEBUG) {
+            Log.d(
+                TAG,
+                "setFlag for flag $flag and value $toSet overridden to " +
+                    "$overrideOrNull by scene container plugin",
+            )
+        }
+
+        toSet = overrideOrNull
+    }
+    return toSet
+}
+
+/** Creates and destroy instances of [SysUiState] */
+@SysUISingleton
+class SysUIStateInstanceProvider
+@Inject
+constructor(
+    private val factory: SysUiStateImpl.Factory,
+    private val overrideFactory: SysUIStateOverride.Factory,
+) : PerDisplayInstanceProviderWithTeardown<SysUiState> {
+    override fun createInstance(displayId: Int): SysUiState {
+        return if (displayId == Display.DEFAULT_DISPLAY) {
+                factory.create(displayId)
+            } else {
+                overrideFactory.create(displayId)
+            }
+            .apply { start() }
+    }
+
+    override fun destroyInstance(instance: SysUiState) {
+        instance.destroy()
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt b/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt
index e293e20..3f804f7 100644
--- a/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt
+++ b/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUi.kt
@@ -42,7 +42,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, Flags.FLAG_MODES_UI)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, Flags.FLAG_MODES_UI)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUiIcons.kt b/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUiIcons.kt
index 032b0ac..44a3d77 100644
--- a/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUiIcons.kt
+++ b/packages/SystemUI/src/com/android/systemui/modes/shared/ModesUiIcons.kt
@@ -42,8 +42,8 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() =
-        RefactorFlagUtils.assertInNewMode(isEnabled, Flags.FLAG_MODES_UI_ICONS)
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, Flags.FLAG_MODES_UI_ICONS)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
index 5fa0095..50d0a45 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBarControllerImpl.java
@@ -18,7 +18,6 @@
 
 import static com.android.systemui.navigationbar.gestural.EdgeBackGestureHandler.DEBUG_MISSING_GESTURE_TAG;
 import static com.android.systemui.shared.recents.utilities.Utilities.isLargeScreen;
-import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
 import static com.android.wm.shell.Flags.enableTaskbarNavbarUnification;
 import static com.android.wm.shell.Flags.enableTaskbarOnPhones;
 
@@ -37,6 +36,7 @@
 import android.view.IWindowManager;
 import android.view.View;
 import android.view.WindowManagerGlobal;
+import android.window.DesktopExperienceFlags;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -285,7 +285,7 @@
 
         @Override
         public void onDisplayAddSystemDecorations(int displayId) {
-            if (enableDisplayContentModeManagement()) {
+            if (DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
                 mHasNavBar.put(displayId, true);
             }
             Display display = mDisplayManager.getDisplay(displayId);
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
index c4d847f..efed260 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/TaskbarDelegate.java
@@ -44,7 +44,6 @@
 import android.content.Context;
 import android.graphics.Rect;
 import android.hardware.display.DisplayManager;
-import android.inputmethodservice.InputMethodService;
 import android.inputmethodservice.InputMethodService.BackDispositionMode;
 import android.inputmethodservice.InputMethodService.ImeWindowVisibility;
 import android.os.Handler;
@@ -503,9 +502,7 @@
     @Override
     public void setImeWindowStatus(int displayId, @ImeWindowVisibility int vis,
             @BackDispositionMode int backDisposition, boolean showImeSwitcher) {
-        // Count imperceptible changes as visible so we transition taskbar out quickly.
-        final boolean isImeVisible = mNavBarHelper.isImeVisible(vis)
-                || (vis & InputMethodService.IME_VISIBLE_IMPERCEPTIBLE) != 0;
+        final boolean isImeVisible = mNavBarHelper.isImeVisible(vis);
         final int flags = Utilities.updateNavbarFlagsFromIme(mNavbarFlags, backDisposition,
                 isImeVisible, showImeSwitcher);
         if (flags == mNavbarFlags) {
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
index f44c2c0..237ec7c 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/gestural/EdgeBackGestureHandler.java
@@ -355,11 +355,12 @@
 
     private final SysUiState.SysUiStateCallback mSysUiStateCallback =
             new SysUiState.SysUiStateCallback() {
-        @Override
-        public void onSystemUiStateChanged(@SystemUiStateFlags long sysUiFlags) {
-            mSysUiFlags = sysUiFlags;
-        }
-    };
+                @Override
+                public void onSystemUiStateChanged(@SystemUiStateFlags long sysUiFlags,
+                        int displayId) {
+                    mSysUiFlags = sysUiFlags;
+                }
+            };
 
     private final Consumer<Boolean> mOnIsInPipStateChangedListener =
             (isInPip) -> mIsInPip = isInPip;
@@ -1128,6 +1129,7 @@
                     mGestureBlockingActivityRunning.get(), mIsInPip, mDisplaySize,
                     mEdgeWidthLeft, mLeftInset, mEdgeWidthRight, mRightInset, mExcludeRegion));
         } else if (mAllowGesture || mLogGesture) {
+            boolean mLastFrameThresholdCrossed = mThresholdCrossed;
             if (!mThresholdCrossed) {
                 mEndPoint.x = (int) ev.getX();
                 mEndPoint.y = (int) ev.getY();
@@ -1180,9 +1182,7 @@
                         return;
                     } else if (dx > dy && dx > mTouchSlop) {
                         if (mAllowGesture) {
-                            if (mBackAnimation != null) {
-                                mBackAnimation.onThresholdCrossed();
-                            } else {
+                            if (mBackAnimation == null) {
                                 pilferPointers();
                             }
                             mThresholdCrossed = true;
@@ -1197,6 +1197,9 @@
                 // forward touch
                 mEdgeBackPlugin.onMotionEvent(ev);
                 dispatchToBackAnimation(ev);
+                if (mBackAnimation != null && mThresholdCrossed && !mLastFrameThresholdCrossed) {
+                    mBackAnimation.onThresholdCrossed();
+                }
             }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java b/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java
index 694b525..ea2bf6a 100644
--- a/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java
+++ b/packages/SystemUI/src/com/android/systemui/process/condition/SystemProcessCondition.java
@@ -48,7 +48,7 @@
     }
 
     @Override
-    protected int getStartStrategy() {
+    public int getStartStrategy() {
         return START_EAGERLY;
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
index fa987dd..9fc1b7a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSContainerImpl.java
@@ -255,7 +255,7 @@
      * @return size in pixels of QQS
      */
     public int getQqsHeight() {
-        SceneContainerFlag.assertInNewMode();
+        SceneContainerFlag.unsafeAssertInNewMode();
         return mHeader.getMeasuredHeight();
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
index 44c8dc3..f1f5b26 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/composefragment/QSFragmentCompose.kt
@@ -42,7 +42,6 @@
 import androidx.compose.foundation.layout.Spacer
 import androidx.compose.foundation.layout.fillMaxSize
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.offset
 import androidx.compose.foundation.layout.padding
 import androidx.compose.foundation.layout.requiredHeightIn
@@ -64,6 +63,7 @@
 import androidx.compose.ui.input.pointer.PointerInputChange
 import androidx.compose.ui.input.pointer.pointerInput
 import androidx.compose.ui.layout.approachLayout
+import androidx.compose.ui.layout.layout
 import androidx.compose.ui.layout.onPlaced
 import androidx.compose.ui.layout.onSizeChanged
 import androidx.compose.ui.layout.positionInRoot
@@ -128,6 +128,7 @@
 import com.android.systemui.qs.panels.ui.compose.TileGrid
 import com.android.systemui.qs.shared.ui.ElementKeys
 import com.android.systemui.qs.ui.composable.QuickSettingsShade
+import com.android.systemui.qs.ui.composable.QuickSettingsShade.systemGestureExclusionInShade
 import com.android.systemui.qs.ui.composable.QuickSettingsTheme
 import com.android.systemui.res.R
 import com.android.systemui.util.LifecycleFragment
@@ -250,10 +251,23 @@
     private fun Content() {
         PlatformTheme(isDarkTheme = true) {
             ProvideShortcutHelperIndication(interactionsConfig = interactionsConfig()) {
-                if (viewModel.isQsVisibleAndAnyShadeExpanded) {
+                // TODO(b/389985793): Make sure that there is no coroutine work or recompositions
+                // happening when alwaysCompose is true but isQsVisibleAndAnyShadeExpanded is false.
+                if (alwaysCompose || viewModel.isQsVisibleAndAnyShadeExpanded) {
                     Box(
                         modifier =
-                            Modifier.graphicsLayer { alpha = viewModel.viewAlpha }
+                            Modifier.thenIf(alwaysCompose) {
+                                    Modifier.layout { measurable, constraints ->
+                                        measurable.measure(constraints).run {
+                                            layout(width, height) {
+                                                if (viewModel.isQsVisibleAndAnyShadeExpanded) {
+                                                    place(0, 0)
+                                                }
+                                            }
+                                        }
+                                    }
+                                }
+                                .graphicsLayer { alpha = viewModel.viewAlpha }
                                 .thenIf(notificationScrimClippingParams.isEnabled) {
                                     Modifier.notificationScrimClip {
                                         notificationScrimClippingParams.params
@@ -331,12 +345,12 @@
         }
 
         SceneTransitionLayout(state = sceneState, modifier = Modifier.fillMaxSize()) {
-            scene(QuickSettings) {
+            scene(QuickSettings, alwaysCompose = alwaysCompose) {
                 LaunchedEffect(Unit) { viewModel.onQSOpen() }
                 Element(QuickSettings.rootElementKey, Modifier) { QuickSettingsElement() }
             }
 
-            scene(QuickQuickSettings) {
+            scene(QuickQuickSettings, alwaysCompose = alwaysCompose) {
                 LaunchedEffect(Unit) { viewModel.onQQSOpen() }
                 // Cannot pass the element modifier in because the top element has a `testTag`
                 // and this would overwrite it.
@@ -626,7 +640,20 @@
             ) {
                 val Tiles =
                     @Composable {
-                        QuickQuickSettings(viewModel = viewModel.quickQuickSettingsViewModel)
+                        QuickQuickSettings(
+                            viewModel = viewModel.quickQuickSettingsViewModel,
+                            listening = {
+                                /*
+                                 *  When always compose is false, this will always be true, and we'll be
+                                 *  listening whenever this is composed.
+                                 *  When always compose is true, we listen if we are visible and not
+                                 *  fully expanded
+                                 */
+                                !alwaysCompose ||
+                                    (viewModel.isQsVisibleAndAnyShadeExpanded &&
+                                        viewModel.expansionState.progress < 1f)
+                            },
+                        )
                     }
                 val Media =
                     @Composable {
@@ -716,10 +743,13 @@
                                 BrightnessSliderContainer(
                                     viewModel = containerViewModel.brightnessSliderViewModel,
                                     modifier =
-                                        Modifier.fillMaxWidth()
-                                            .height(
-                                                QuickSettingsShade.Dimensions.BrightnessSliderHeight
-                                            ),
+                                        Modifier.systemGestureExclusionInShade(
+                                                enabled = {
+                                                    layoutState.transitionState is
+                                                        TransitionState.Idle
+                                                }
+                                            )
+                                            .fillMaxWidth(),
                                 )
                             }
                         val TileGrid =
@@ -729,6 +759,18 @@
                                     TileGrid(
                                         viewModel = containerViewModel.tileGridViewModel,
                                         modifier = Modifier.fillMaxWidth(),
+                                        listening = {
+                                            /*
+                                             *  When always compose is false, this will always be true,
+                                             *  and we'll be listening whenever this is composed.
+                                             *  When always compose is true, we look a the second
+                                             *  condition and we'll listen if QS is visible AND we are
+                                             *  not fully collapsed.
+                                             */
+                                            !alwaysCompose ||
+                                                (viewModel.isQsVisibleAndAnyShadeExpanded &&
+                                                    viewModel.expansionState.progress > 0f)
+                                        },
                                     )
                                 }
                             }
@@ -833,6 +875,7 @@
                 println("qqsPositionOnScreen", rect)
             }
             println("QQS visible", qqsVisible.value)
+            println("Always composed", alwaysCompose)
             if (::viewModel.isInitialized) {
                 printSection("View Model") { viewModel.dump(this@run, args) }
             }
@@ -1180,3 +1223,6 @@
         // we are OK using this as our content is clipped and all corner radius are larger than this
         surfaceCornerRadius = 28.dp,
     )
+
+private inline val alwaysCompose
+    get() = Flags.alwaysComposeQsUiFragment()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/flags/QsDetailedView.kt b/packages/SystemUI/src/com/android/systemui/qs/flags/QsDetailedView.kt
index 3afaef5..6865e0e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/flags/QsDetailedView.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/flags/QsDetailedView.kt
@@ -81,7 +81,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /** Returns a developer-readable string that describes the current requirement list. */
     @JvmStatic
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
index 2670787..c45fa97 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
@@ -18,6 +18,7 @@
 
 import android.annotation.AttrRes
 import android.annotation.ColorInt
+import androidx.compose.runtime.Stable
 import com.android.systemui.animation.Expandable
 import com.android.systemui.common.shared.model.Icon
 
@@ -25,6 +26,7 @@
  * A ViewModel for a simple footer actions button. This is used for the user switcher, settings and
  * power buttons.
  */
+@Stable
 data class FooterActionsButtonViewModel(
     val id: Int,
     val icon: Icon,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index 9546e35..aea280c 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -75,6 +75,7 @@
 
     /** The model for the power button. */
     val power: Flow<FooterActionsButtonViewModel?>,
+    val initialPower: () -> FooterActionsButtonViewModel?,
 
     /**
      * Observe the device monitoring dialog requests and show the dialog accordingly. This function
@@ -181,7 +182,7 @@
 fun createFooterActionsViewModel(
     @ShadeDisplayAware appContext: Context,
     footerActionsInteractor: FooterActionsInteractor,
-    shadeMode: Flow<ShadeMode>,
+    shadeMode: StateFlow<ShadeMode>,
     falsingManager: FalsingManager,
     globalActionsDialogLite: GlobalActionsDialogLite,
     activityStarter: ActivityStarter,
@@ -291,6 +292,12 @@
         settings = settings,
         power = power,
         observeDeviceMonitoringDialogRequests = ::observeDeviceMonitoringDialogRequests,
+        initialPower =
+            if (showPowerButton) {
+                { powerButtonViewModel(qsThemedContext, ::onPowerButtonClicked, shadeMode.value) }
+            } else {
+                { null }
+            },
     )
 }
 
@@ -411,20 +418,28 @@
     shadeMode: Flow<ShadeMode>,
 ): Flow<FooterActionsButtonViewModel?> {
     return shadeMode.map { mode ->
-        val isDualShade = mode is ShadeMode.Dual
-        FooterActionsButtonViewModel(
-            id = R.id.pm_lite,
-            Icon.Resource(
-                android.R.drawable.ic_lock_power_off,
-                ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu),
-            ),
-            iconTint =
-                Utils.getColorAttrDefaultColor(
-                    qsThemedContext,
-                    if (isDualShade) R.attr.onShadeInactiveVariant else R.attr.onShadeActive,
-                ),
-            backgroundColor = if (isDualShade) R.attr.shadeInactive else R.attr.shadeActive,
-            onPowerButtonClicked,
-        )
+        powerButtonViewModel(qsThemedContext, onPowerButtonClicked, mode)
     }
 }
+
+fun powerButtonViewModel(
+    qsThemedContext: Context,
+    onPowerButtonClicked: (Expandable) -> Unit,
+    shadeMode: ShadeMode,
+): FooterActionsButtonViewModel {
+    val isDualShade = shadeMode is ShadeMode.Dual
+    return FooterActionsButtonViewModel(
+        id = R.id.pm_lite,
+        Icon.Resource(
+            android.R.drawable.ic_lock_power_off,
+            ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu),
+        ),
+        iconTint =
+            Utils.getColorAttrDefaultColor(
+                qsThemedContext,
+                if (isDualShade) R.attr.onShadeInactiveVariant else R.attr.onShadeActive,
+            ),
+        backgroundColor = if (isDualShade) R.attr.shadeInactive else R.attr.shadeActive,
+        onPowerButtonClicked,
+    )
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
index 185ea93..1fb884d 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/GridLayout.kt
@@ -27,7 +27,17 @@
 
 /** A layout of tiles, indicating how they should be composed when showing in QS or in edit mode. */
 interface GridLayout {
-    @Composable fun ContentScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier)
+
+    /**
+     * [listening] can be used to compose the grid but limit when tiles should be listening. It
+     * should be a function tracking a snapshot state.
+     */
+    @Composable
+    fun ContentScope.TileGrid(
+        tiles: List<TileViewModel>,
+        modifier: Modifier,
+        listening: () -> Boolean,
+    )
 
     @Composable
     fun EditTileGrid(
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
index a071206..865ae9a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/PaginatedGridLayout.kt
@@ -32,7 +32,6 @@
 import androidx.compose.foundation.shape.CornerSize
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.snapshotFlow
@@ -43,6 +42,7 @@
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.ContentScope
 import com.android.compose.modifiers.padding
+import com.android.systemui.common.ui.compose.PagerDots
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.development.ui.compose.BuildNumber
 import com.android.systemui.development.ui.viewmodel.BuildNumberViewModel
@@ -65,17 +65,16 @@
     @PaginatedBaseLayoutType private val delegateGridLayout: PaginatableGridLayout,
 ) : GridLayout by delegateGridLayout {
     @Composable
-    override fun ContentScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
+    override fun ContentScope.TileGrid(
+        tiles: List<TileViewModel>,
+        modifier: Modifier,
+        listening: () -> Boolean,
+    ) {
         val viewModel =
             rememberViewModel(traceName = "PaginatedGridLayout-TileGrid") {
                 viewModelFactory.create()
             }
 
-        DisposableEffect(tiles) {
-            val token = Any()
-            tiles.forEach { it.startListening(token) }
-            onDispose { tiles.forEach { it.stopListening(token) } }
-        }
         val columns = viewModel.columns
         val rows = integerResource(R.integer.quick_settings_paginated_grid_num_rows)
 
@@ -122,7 +121,7 @@
             ) {
                 val page = pages[it]
 
-                with(delegateGridLayout) { TileGrid(tiles = page, modifier = Modifier) }
+                with(delegateGridLayout) { TileGrid(tiles = page, modifier = Modifier, listening) }
             }
             FooterBar(
                 buildNumberViewModelFactory = viewModel.buildNumberViewModelFactory,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
index cdc03bb..d20b360 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/QuickQuickSettings.kt
@@ -18,7 +18,6 @@
 
 import androidx.compose.foundation.layout.Box
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
@@ -41,6 +40,7 @@
 fun ContentScope.QuickQuickSettings(
     viewModel: QuickQuickSettingsViewModel,
     modifier: Modifier = Modifier,
+    listening: () -> Boolean,
 ) {
 
     val sizedTiles = viewModel.tileViewModels
@@ -51,11 +51,6 @@
 
     val spans by remember(sizedTiles) { derivedStateOf { sizedTiles.fastMap { it.width } } }
 
-    DisposableEffect(tiles) {
-        val token = Any()
-        tiles.forEach { it.startListening(token) }
-        onDispose { tiles.forEach { it.stopListening(token) } }
-    }
     val columns = viewModel.columns
     Box(modifier = modifier) {
         GridAnchor()
@@ -91,4 +86,6 @@
             }
         }
     }
+
+    TileListener(tiles, listening)
 }
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 fd10f91..1858825 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
@@ -22,9 +22,13 @@
 import com.android.systemui.qs.panels.ui.viewmodel.TileGridViewModel
 
 @Composable
-fun ContentScope.TileGrid(viewModel: TileGridViewModel, modifier: Modifier = Modifier) {
+fun ContentScope.TileGrid(
+    viewModel: TileGridViewModel,
+    modifier: Modifier = Modifier,
+    listening: () -> Boolean = { true },
+) {
     val gridLayout = viewModel.gridLayout
     val tiles = viewModel.tileViewModels
 
-    with(gridLayout) { TileGrid(tiles, modifier) }
+    with(gridLayout) { TileGrid(tiles, modifier, listening) }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileListener.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileListener.kt
new file mode 100644
index 0000000..6fb8f1b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/TileListener.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.qs.panels.ui.compose
+
+import androidx.compose.runtime.Composable
+import androidx.compose.runtime.LaunchedEffect
+import androidx.compose.runtime.snapshotFlow
+import com.android.systemui.qs.panels.ui.viewmodel.TileViewModel
+
+/**
+ * Use to have tiles start/stop listening when this is composed. Additionally, the listening state
+ * will be gated by [listeningEnabled].
+ */
+@Composable
+fun TileListener(tiles: List<TileViewModel>, listeningEnabled: () -> Boolean) {
+    LaunchedEffect(tiles) {
+        val token = Any()
+        try {
+            snapshotFlow { listeningEnabled() }
+                .collect { listening ->
+                    tiles.forEach {
+                        if (listening) {
+                            it.startListening(token)
+                        } else {
+                            it.stopListening(token)
+                        }
+                    }
+                }
+        } finally {
+            tiles.forEach { it.stopListening(token) }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
index 85658bb..50012ab 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/CommonTile.kt
@@ -26,12 +26,14 @@
 import androidx.compose.animation.graphics.res.rememberAnimatedVectorPainter
 import androidx.compose.animation.graphics.vector.AnimatedImageVector
 import androidx.compose.foundation.Image
+import androidx.compose.foundation.basicMarquee
 import androidx.compose.foundation.combinedClickable
 import androidx.compose.foundation.layout.Arrangement
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.Row
 import androidx.compose.foundation.layout.fillMaxHeight
+import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.height
 import androidx.compose.foundation.layout.size
 import androidx.compose.foundation.layout.width
@@ -39,6 +41,7 @@
 import androidx.compose.foundation.text.BasicText
 import androidx.compose.material3.MaterialTheme
 import androidx.compose.runtime.Composable
+import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.LaunchedEffect
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.key
@@ -49,8 +52,16 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.draw.clip
 import androidx.compose.ui.draw.drawBehind
+import androidx.compose.ui.draw.drawWithContent
+import androidx.compose.ui.geometry.Offset
+import androidx.compose.ui.geometry.Size
+import androidx.compose.ui.graphics.BlendMode
+import androidx.compose.ui.graphics.Brush
 import androidx.compose.ui.graphics.Color
 import androidx.compose.ui.graphics.ColorFilter
+import androidx.compose.ui.graphics.ColorProducer
+import androidx.compose.ui.graphics.CompositingStrategy
+import androidx.compose.ui.graphics.graphicsLayer
 import androidx.compose.ui.platform.LocalContext
 import androidx.compose.ui.res.stringResource
 import androidx.compose.ui.semantics.Role
@@ -60,7 +71,7 @@
 import androidx.compose.ui.semantics.semantics
 import androidx.compose.ui.semantics.stateDescription
 import androidx.compose.ui.semantics.toggleableState
-import androidx.compose.ui.text.style.TextOverflow
+import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.dp
 import com.android.compose.modifiers.size
@@ -73,6 +84,9 @@
 import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.SideIconHeight
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.SideIconWidth
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TILE_INITIAL_DELAY_MILLIS
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TILE_MARQUEE_ITERATIONS
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileLabelBlurWidth
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel
 import com.android.systemui.qs.panels.ui.viewmodel.AccessibilityUiState
 import com.android.systemui.qs.ui.compose.borderOnFocus
@@ -104,30 +118,31 @@
         val focusBorderColor = MaterialTheme.colorScheme.secondary
         Box(
             modifier =
-                Modifier.size(CommonTileDefaults.ToggleTargetSize).thenIf(toggleClick != null) {
-                    Modifier.borderOnFocus(color = focusBorderColor, iconShape.topEnd)
-                        .clip(iconShape)
-                        .verticalSquish(squishiness)
-                        .drawBehind { drawRect(animatedBackgroundColor) }
-                        .combinedClickable(
-                            onClick = toggleClick!!,
-                            onLongClick = onLongClick,
-                            onLongClickLabel = longPressLabel,
-                            hapticFeedbackEnabled = !Flags.msdlFeedback(),
-                        )
-                        .thenIf(accessibilityUiState != null) {
-                            Modifier.semantics {
-                                    accessibilityUiState as AccessibilityUiState
-                                    contentDescription = accessibilityUiState.contentDescription
-                                    stateDescription = accessibilityUiState.stateDescription
-                                    accessibilityUiState.toggleableState?.let {
-                                        toggleableState = it
+                Modifier.size(CommonTileDefaults.ToggleTargetSize)
+                    .clip(iconShape)
+                    .verticalSquish(squishiness)
+                    .drawBehind { drawRect(animatedBackgroundColor) }
+                    .thenIf(toggleClick != null) {
+                        Modifier.borderOnFocus(color = focusBorderColor, iconShape.topEnd)
+                            .combinedClickable(
+                                onClick = toggleClick!!,
+                                onLongClick = onLongClick,
+                                onLongClickLabel = longPressLabel,
+                                hapticFeedbackEnabled = !Flags.msdlFeedback(),
+                            )
+                            .thenIf(accessibilityUiState != null) {
+                                Modifier.semantics {
+                                        accessibilityUiState as AccessibilityUiState
+                                        contentDescription = accessibilityUiState.contentDescription
+                                        stateDescription = accessibilityUiState.stateDescription
+                                        accessibilityUiState.toggleableState?.let {
+                                            toggleableState = it
+                                        }
+                                        role = Role.Switch
                                     }
-                                    role = Role.Switch
-                                }
-                                .sysuiResTag(TEST_TAG_TOGGLE)
-                        }
-                }
+                                    .sysuiResTag(TEST_TAG_TOGGLE)
+                            }
+                    }
         ) {
             SmallTileContent(
                 iconProvider = iconProvider,
@@ -167,18 +182,15 @@
     val animatedSecondaryLabelColor by
         animateColorAsState(colors.secondaryLabel, label = "QSTileSecondaryLabelColor")
     Column(verticalArrangement = Arrangement.Center, modifier = modifier.fillMaxHeight()) {
-        BasicText(
-            label,
+        TileLabel(
+            text = label,
             style = MaterialTheme.typography.labelLarge,
             color = { animatedLabelColor },
-            maxLines = 1,
-            overflow = TextOverflow.Ellipsis,
         )
         if (!TextUtils.isEmpty(secondaryLabel)) {
-            BasicText(
+            TileLabel(
                 secondaryLabel ?: "",
                 color = { animatedSecondaryLabelColor },
-                maxLines = 1,
                 style = MaterialTheme.typography.bodyMedium,
                 modifier =
                     Modifier.thenIf(
@@ -194,9 +206,9 @@
 
 @Composable
 fun SmallTileContent(
-    modifier: Modifier = Modifier,
     iconProvider: Context.() -> Icon,
     color: Color,
+    modifier: Modifier = Modifier,
     size: () -> Dp = { CommonTileDefaults.IconSize },
     animateToEnd: Boolean = false,
 ) {
@@ -212,31 +224,39 @@
             }
         }
     if (loadedDrawable is Animatable) {
+        // Skip initial animation, icons should animate only as the state change
+        // and not when first composed
+        var shouldSkipInitialAnimation by remember { mutableStateOf(true) }
+        LaunchedEffect(Unit) { shouldSkipInitialAnimation = animateToEnd }
+
         val painter =
             when (icon) {
                 is Icon.Resource -> {
                     val image = AnimatedImageVector.animatedVectorResource(id = icon.res)
                     key(icon) {
-                        if (animateToEnd) {
-                            rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = true)
-                        } else {
-                            var atEnd by remember(icon.res) { mutableStateOf(false) }
-                            LaunchedEffect(key1 = icon.res) { atEnd = true }
-                            rememberAnimatedVectorPainter(
-                                animatedImageVector = image,
-                                atEnd = atEnd,
-                            )
-                        }
+                        var atEnd by remember(icon) { mutableStateOf(shouldSkipInitialAnimation) }
+                        LaunchedEffect(key1 = icon.res) { atEnd = true }
+
+                        rememberAnimatedVectorPainter(animatedImageVector = image, atEnd = atEnd)
                     }
                 }
 
                 is Icon.Loaded -> {
-                    LaunchedEffect(loadedDrawable) {
+                    val painter = rememberDrawablePainter(loadedDrawable)
+
+                    // rememberDrawablePainter automatically starts the animation. Using
+                    // SideEffect here to immediately stop it if needed
+                    DisposableEffect(painter) {
                         if (loadedDrawable is AnimatedVectorDrawable) {
                             loadedDrawable.forceAnimationOnUI()
                         }
+                        if (shouldSkipInitialAnimation) {
+                            loadedDrawable.stop()
+                        }
+                        onDispose {}
                     }
-                    rememberDrawablePainter(loadedDrawable)
+
+                    painter
                 }
             }
 
@@ -251,6 +271,45 @@
     }
 }
 
+@Composable
+private fun TileLabel(
+    text: String,
+    color: ColorProducer,
+    style: TextStyle,
+    modifier: Modifier = Modifier,
+) {
+    BasicText(
+        text = text,
+        color = color,
+        style = style,
+        maxLines = 1,
+        modifier =
+            modifier
+                .fillMaxWidth()
+                .graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen }
+                .drawWithContent {
+                    drawContent()
+                    // Draw a blur over the end of the text
+                    val edgeWidthPx = TileLabelBlurWidth.toPx()
+                    drawRect(
+                        topLeft = Offset(size.width - edgeWidthPx, 0f),
+                        size = Size(edgeWidthPx, size.height),
+                        brush =
+                            Brush.horizontalGradient(
+                                colors = listOf(Color.Transparent, Color.Black),
+                                startX = size.width,
+                                endX = size.width - edgeWidthPx,
+                            ),
+                        blendMode = BlendMode.DstIn,
+                    )
+                }
+                .basicMarquee(
+                    iterations = TILE_MARQUEE_ITERATIONS,
+                    initialDelayMillis = TILE_INITIAL_DELAY_MILLIS,
+                ),
+    )
+}
+
 object CommonTileDefaults {
     val IconSize = 32.dp
     val LargeTileIconSize = 28.dp
@@ -258,9 +317,13 @@
     val SideIconHeight = 20.dp
     val ToggleTargetSize = 56.dp
     val TileHeight = 72.dp
-    val TilePadding = 8.dp
+    val TileStartPadding = 8.dp
+    val TileEndPadding = 16.dp
     val TileArrangementPadding = 6.dp
     val InactiveCornerRadius = 50.dp
+    val TileLabelBlurWidth = 32.dp
+    const val TILE_MARQUEE_ITERATIONS = 1
+    const val TILE_INITIAL_DELAY_MILLIS = 2000
 
     @Composable fun longPressLabel() = stringResource(id = R.string.accessibility_long_click_tile)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
index ddadb88..69b967a 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/EditTile.kt
@@ -22,6 +22,7 @@
 import androidx.compose.animation.animateContentSize
 import androidx.compose.animation.core.LinearEasing
 import androidx.compose.animation.core.animateDpAsState
+import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.animation.core.tween
 import androidx.compose.animation.fadeIn
 import androidx.compose.animation.fadeOut
@@ -78,6 +79,7 @@
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.key
+import androidx.compose.runtime.mutableStateListOf
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.remember
 import androidx.compose.runtime.rememberCoroutineScope
@@ -140,6 +142,7 @@
 import com.android.systemui.qs.panels.ui.compose.selection.rememberResizingState
 import com.android.systemui.qs.panels.ui.compose.selection.rememberSelectionState
 import com.android.systemui.qs.panels.ui.compose.selection.selectableTile
+import com.android.systemui.qs.panels.ui.model.AvailableTileGridCell
 import com.android.systemui.qs.panels.ui.model.GridCell
 import com.android.systemui.qs.panels.ui.model.SpacerGridCell
 import com.android.systemui.qs.panels.ui.model.TileGridCell
@@ -290,8 +293,19 @@
                                 Text(text = stringResource(id = R.string.drag_to_add_tiles))
                             }
 
+                            val availableTiles = remember {
+                                mutableStateListOf<AvailableTileGridCell>().apply {
+                                    addAll(toAvailableTiles(listState.tiles, otherTiles))
+                                }
+                            }
+                            LaunchedEffect(listState.tiles, otherTiles) {
+                                availableTiles.apply {
+                                    clear()
+                                    addAll(toAvailableTiles(listState.tiles, otherTiles))
+                                }
+                            }
                             AvailableTileGrid(
-                                otherTiles,
+                                availableTiles,
                                 selectionState,
                                 columns,
                                 onAddTile,
@@ -444,7 +458,7 @@
 
 @Composable
 private fun AvailableTileGrid(
-    tiles: List<SizedTile<EditTileViewModel>>,
+    tiles: List<AvailableTileGridCell>,
     selectionState: MutableSelectionState,
     columns: Int,
     onAddTile: (TileSpec) -> Unit,
@@ -453,7 +467,7 @@
     // Available tiles aren't visible during drag and drop, so the row/col isn't needed
     val groupedTiles =
         remember(tiles.fastMap { it.tile.category }, tiles.fastMap { it.tile.label }) {
-            groupAndSort(tiles.fastMap { TileGridCell(it, 0, 0) })
+            groupAndSort(tiles)
         }
     val labelColors = EditModeTileDefaults.editTileColors()
 
@@ -478,11 +492,10 @@
                         horizontalArrangement = spacedBy(TileArrangementPadding),
                         modifier = Modifier.fillMaxWidth().height(IntrinsicSize.Max),
                     ) {
-                        row.forEachIndexed { index, tileGridCell ->
-                            key(tileGridCell.tile.tileSpec) {
+                        row.forEach { tileGridCell ->
+                            key(tileGridCell.key) {
                                 AvailableTileGridCell(
                                     cell = tileGridCell,
-                                    index = index,
                                     dragAndDropState = dragAndDropState,
                                     selectionState = selectionState,
                                     onAddTile = onAddTile,
@@ -505,10 +518,7 @@
 }
 
 private fun GridCell.key(index: Int): Any {
-    return when (this) {
-        is TileGridCell -> key
-        is SpacerGridCell -> index
-    }
+    return if (this is TileGridCell) key else index
 }
 
 /**
@@ -687,41 +697,44 @@
 
 @Composable
 private fun AvailableTileGridCell(
-    cell: TileGridCell,
-    index: Int,
+    cell: AvailableTileGridCell,
     dragAndDropState: DragAndDropState,
     selectionState: MutableSelectionState,
     onAddTile: (TileSpec) -> Unit,
     modifier: Modifier = Modifier,
 ) {
-    val onClickActionName = stringResource(id = R.string.accessibility_qs_edit_tile_add_action)
-    val stateDescription = stringResource(id = R.string.accessibility_qs_edit_position, index + 1)
+    val stateDescription: String? =
+        if (cell.isAvailable) null
+        else stringResource(R.string.accessibility_qs_edit_tile_already_added)
+
+    val alpha by animateFloatAsState(if (cell.isAvailable) 1f else .38f)
     val colors = EditModeTileDefaults.editTileColors()
-    val onClick = {
-        onAddTile(cell.tile.tileSpec)
-        selectionState.select(cell.tile.tileSpec)
-    }
 
     // Displays the tile as an icon tile with the label underneath
     Column(
         horizontalAlignment = Alignment.CenterHorizontally,
-        verticalArrangement = spacedBy(CommonTileDefaults.TilePadding, Alignment.Top),
-        modifier = modifier,
+        verticalArrangement = spacedBy(CommonTileDefaults.TileStartPadding, Alignment.Top),
+        modifier =
+            modifier
+                .graphicsLayer { this.alpha = alpha }
+                .semantics(mergeDescendants = true) {
+                    stateDescription?.let { this.stateDescription = it }
+                },
     ) {
         Box(Modifier.fillMaxWidth().height(TileHeight)) {
-            Box(
-                Modifier.fillMaxSize()
-                    .clickable(onClick = onClick, onClickLabel = onClickActionName)
-                    .semantics(mergeDescendants = true) { this.stateDescription = stateDescription }
-                    .dragAndDropTileSource(
+            val draggableModifier =
+                if (cell.isAvailable) {
+                    Modifier.dragAndDropTileSource(
                         SizedTileImpl(cell.tile, cell.width),
                         dragAndDropState,
                         DragType.Add,
                     ) {
                         selectionState.unSelect()
                     }
-                    .tileBackground(colors.background)
-            ) {
+                } else {
+                    Modifier
+                }
+            Box(draggableModifier.fillMaxSize().tileBackground(colors.background)) {
                 // Icon
                 SmallTileContent(
                     iconProvider = { cell.tile.icon },
@@ -733,9 +746,13 @@
 
             StaticTileBadge(
                 icon = Icons.Default.Add,
-                contentDescription = onClickActionName,
-                onClick = onClick,
-            )
+                contentDescription =
+                    stringResource(id = R.string.accessibility_qs_edit_tile_add_action),
+                enabled = cell.isAvailable,
+            ) {
+                onAddTile(cell.tile.tileSpec)
+                selectionState.select(cell.tile.tileSpec)
+            }
         }
         Box(Modifier.fillMaxSize()) {
             Text(
@@ -796,7 +813,7 @@
                         placeable.place(startPadding.roundToInt(), 0)
                     }
                 }
-                .tilePadding(),
+                .largeTilePadding(),
     ) {
         // Icon
         Box(Modifier.size(ToggleTargetSize)) {
@@ -819,9 +836,18 @@
     }
 }
 
+private fun toAvailableTiles(
+    currentTiles: List<GridCell>,
+    otherTiles: List<SizedTile<EditTileViewModel>>,
+): List<AvailableTileGridCell> {
+    return currentTiles.filterIsInstance<TileGridCell>().fastMap {
+        AvailableTileGridCell(it.tile, isAvailable = false)
+    } + otherTiles.fastMap { AvailableTileGridCell(it.tile) }
+}
+
 private fun MeasureScope.iconHorizontalCenter(containerSize: Int): Float {
     return (containerSize - ToggleTargetSize.roundToPx()) / 2f -
-        CommonTileDefaults.TilePadding.toPx()
+        CommonTileDefaults.TileStartPadding.toPx()
 }
 
 private fun Modifier.tileBackground(color: Color): Modifier {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
index 0503049..6236ada 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/InfiniteGridLayout.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.qs.panels.ui.compose.infinitegrid
 
 import androidx.compose.runtime.Composable
-import androidx.compose.runtime.DisposableEffect
 import androidx.compose.runtime.derivedStateOf
 import androidx.compose.runtime.getValue
 import androidx.compose.runtime.remember
@@ -34,6 +33,7 @@
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager.Companion.LOCATION_QS
 import com.android.systemui.qs.panels.shared.model.SizedTileImpl
 import com.android.systemui.qs.panels.ui.compose.PaginatableGridLayout
+import com.android.systemui.qs.panels.ui.compose.TileListener
 import com.android.systemui.qs.panels.ui.compose.bounceableInfo
 import com.android.systemui.qs.panels.ui.compose.rememberEditListState
 import com.android.systemui.qs.panels.ui.viewmodel.BounceableTileViewModel
@@ -59,12 +59,11 @@
 ) : PaginatableGridLayout {
 
     @Composable
-    override fun ContentScope.TileGrid(tiles: List<TileViewModel>, modifier: Modifier) {
-        DisposableEffect(tiles) {
-            val token = Any()
-            tiles.forEach { it.startListening(token) }
-            onDispose { tiles.forEach { it.stopListening(token) } }
-        }
+    override fun ContentScope.TileGrid(
+        tiles: List<TileViewModel>,
+        modifier: Modifier,
+        listening: () -> Boolean,
+    ) {
         val viewModel =
             rememberViewModel(traceName = "InfiniteGridLayout.TileGrid") {
                 viewModelFactory.create()
@@ -116,6 +115,8 @@
                 )
             }
         }
+
+        TileListener(tiles, listening)
     }
 
     @Composable
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
index d73dc87..a56fabc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/infinitegrid/Tile.kt
@@ -84,7 +84,9 @@
 import com.android.systemui.qs.flags.QsDetailedView
 import com.android.systemui.qs.panels.ui.compose.BounceableInfo
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileEndPadding
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileHeight
+import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.TileStartPadding
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.longPressLabel
 import com.android.systemui.qs.panels.ui.viewmodel.DetailsViewModel
 import com.android.systemui.qs.panels.ui.viewmodel.TileUiState
@@ -270,7 +272,7 @@
                     iconOnly = iconOnly,
                 )
                 .sysuiResTag(if (iconOnly) TEST_TAG_SMALL else TEST_TAG_LARGE)
-                .tilePadding(),
+                .thenIf(!iconOnly) { Modifier.largeTilePadding() }, // Icon tiles are center aligned
         content = content,
     )
 }
@@ -284,7 +286,7 @@
             .clip(TileDefaults.animateTileShapeAsState(state = uiState.state).value)
             .background(colors.background)
             .height(TileHeight)
-            .tilePadding()
+            .largeTilePadding()
     ) {
         LargeTileContent(
             label = uiState.label,
@@ -311,8 +313,8 @@
     return spacedBy(space = CommonTileDefaults.TileArrangementPadding, alignment = Alignment.Start)
 }
 
-fun Modifier.tilePadding(): Modifier {
-    return padding(CommonTileDefaults.TilePadding)
+fun Modifier.largeTilePadding(): Modifier {
+    return padding(start = TileStartPadding, end = TileEndPadding)
 }
 
 @Composable
@@ -356,10 +358,10 @@
     val ActiveIconCornerRadius = 16.dp
     val ActiveTileCornerRadius = 24.dp
 
-    /** An active tile without dual target uses the active color as background */
+    /** An active icon tile uses the active color as background */
     @Composable
     @ReadOnlyComposable
-    fun activeTileColors(): TileColors =
+    fun activeIconTileColors(): TileColors =
         TileColors(
             background = MaterialTheme.colorScheme.primary,
             iconBackground = MaterialTheme.colorScheme.primary,
@@ -418,10 +420,10 @@
     fun getColorForState(uiState: TileUiState, iconOnly: Boolean): TileColors {
         return when (uiState.state) {
             STATE_ACTIVE -> {
-                if (uiState.handlesSecondaryClick && !iconOnly) {
+                if (!iconOnly) {
                     activeDualTargetTileColors()
                 } else {
-                    activeTileColors()
+                    activeIconTileColors()
                 }
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
index 699e5f6..153238fc 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/selection/Selection.kt
@@ -19,6 +19,7 @@
 import androidx.compose.animation.animateColor
 import androidx.compose.animation.core.Transition
 import androidx.compose.animation.core.animateFloat
+import androidx.compose.animation.core.animateFloatAsState
 import androidx.compose.animation.core.animateOffset
 import androidx.compose.animation.core.animateSize
 import androidx.compose.animation.core.updateTransition
@@ -61,6 +62,7 @@
 import androidx.compose.ui.unit.toSize
 import androidx.compose.ui.zIndex
 import com.android.compose.modifiers.size
+import com.android.compose.modifiers.thenIf
 import com.android.systemui.qs.panels.ui.compose.infinitegrid.CommonTileDefaults.InactiveCornerRadius
 import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BADGE_ANGLE_RAD
 import com.android.systemui.qs.panels.ui.compose.selection.SelectionDefaults.BadgeSize
@@ -184,18 +186,37 @@
     }
 }
 
+/**
+ * Draws a clickable badge in the top end corner of the parent composable.
+ *
+ * The badge will fade in and fade out based on whether or not it's enabled.
+ *
+ * @param icon the [ImageVector] to display in the badge
+ * @param contentDescription the content description for the icon
+ * @param enabled Whether the badge should be visible and clickable
+ * @param onClick the callback when the badge is clicked
+ */
 @Composable
-fun StaticTileBadge(icon: ImageVector, contentDescription: String?, onClick: () -> Unit) {
+fun StaticTileBadge(
+    icon: ImageVector,
+    contentDescription: String?,
+    enabled: Boolean,
+    onClick: () -> Unit,
+) {
     val offset = with(LocalDensity.current) { Offset(BadgeXOffset.toPx(), BadgeYOffset.toPx()) }
+    val alpha by animateFloatAsState(if (enabled) 1f else 0f)
     MinimumInteractiveSizeComponent(angle = { BADGE_ANGLE_RAD }, offset = { offset }) {
         Box(
             Modifier.fillMaxSize()
-                .clickable(
-                    interactionSource = null,
-                    indication = null,
-                    onClickLabel = contentDescription,
-                    onClick = onClick,
-                )
+                .graphicsLayer { this.alpha = alpha }
+                .thenIf(enabled) {
+                    Modifier.clickable(
+                        interactionSource = null,
+                        indication = null,
+                        onClickLabel = contentDescription,
+                        onClick = onClick,
+                    )
+                }
         ) {
             val secondaryColor = MaterialTheme.colorScheme.secondary
             Icon(
@@ -214,7 +235,8 @@
 private fun MinimumInteractiveSizeComponent(
     angle: () -> Float,
     offset: () -> Offset,
-    content: @Composable BoxScope.() -> Unit,
+    modifier: Modifier = Modifier,
+    content: @Composable BoxScope.() -> Unit = {},
 ) {
     // Use a higher zIndex than the tile to draw over it, and manually create the touch target
     // as we're drawing over neighbor tiles as well.
@@ -222,7 +244,8 @@
     Box(
         contentAlignment = Alignment.Center,
         modifier =
-            Modifier.zIndex(2f)
+            modifier
+                .zIndex(2f)
                 .systemGestureExclusion { Rect(Offset.Zero, it.size.toSize()) }
                 .layout { measurable, constraints ->
                     val size = minTouchTargetSize.roundToPx()
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt
index 360266a..99f52c2 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/compose/toolbar/Toolbar.kt
@@ -46,8 +46,10 @@
 
         Spacer(modifier = Modifier.weight(1f))
 
-        viewModel.powerButtonViewModel?.let {
-            IconButton(it, useModifierBasedExpandable = true, Modifier.sysuiResTag("pm_lite"))
-        }
+        IconButton(
+            { viewModel.powerButtonViewModel },
+            useModifierBasedExpandable = true,
+            Modifier.sysuiResTag("pm_lite"),
+        )
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
index c0441f8..78fd8c0 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/panels/ui/model/TileGridCell.kt
@@ -21,13 +21,13 @@
 import com.android.systemui.qs.panels.shared.model.SizedTile
 import com.android.systemui.qs.panels.shared.model.splitInRowsSequence
 import com.android.systemui.qs.panels.ui.viewmodel.EditTileViewModel
+import com.android.systemui.qs.pipeline.shared.TileSpec
 import com.android.systemui.qs.shared.model.CategoryAndName
 
 /** Represents an item from a grid associated with a row and a span */
 sealed interface GridCell {
     val row: Int
     val span: GridItemSpan
-    val s: String
 }
 
 /**
@@ -40,7 +40,6 @@
     override val row: Int,
     override val width: Int,
     override val span: GridItemSpan = GridItemSpan(width),
-    override val s: String = "${tile.tileSpec.spec}-$row-$width",
     val column: Int,
 ) : GridCell, SizedTile<EditTileViewModel>, CategoryAndName by tile {
     val key: String = "${tile.tileSpec.spec}-$row"
@@ -52,12 +51,23 @@
     ) : this(tile = sizedTile.tile, row = row, column = column, width = sizedTile.width)
 }
 
+/**
+ * Represents a [EditTileViewModel] from the edit mode available tiles grid and whether it is
+ * available to add or not.
+ */
+@Immutable
+data class AvailableTileGridCell(
+    override val tile: EditTileViewModel,
+    override val width: Int = 1,
+    val isAvailable: Boolean = true,
+    val key: TileSpec = tile.tileSpec,
+) : SizedTile<EditTileViewModel>, CategoryAndName by tile
+
 /** Represents an empty space used to fill incomplete rows. Will always display as a 1x1 tile */
 @Immutable
 data class SpacerGridCell(
     override val row: Int,
     override val span: GridItemSpan = GridItemSpan(1),
-    override val s: String = "spacer",
 ) : GridCell
 
 /**
diff --git a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
index 5dc8d1b..26148de 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/pipeline/shared/QSPipelineFlagsRepository.kt
@@ -14,7 +14,7 @@
 
     companion object Utils {
         fun assertNewTiles() =
-            RefactorFlagUtils.assertInNewMode(
+            RefactorFlagUtils.unsafeAssertInNewMode(
                 AconfigFlags.qsNewTiles(),
                 AconfigFlags.FLAG_QS_NEW_TILES
             )
diff --git a/packages/SystemUI/src/com/android/systemui/recents/LauncherProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/LauncherProxyService.java
index 9af4630..4be35f1 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/LauncherProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/LauncherProxyService.java
@@ -66,6 +66,7 @@
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.util.Log;
+import android.view.Display;
 import android.view.InputDevice;
 import android.view.KeyCharacterMap;
 import android.view.KeyEvent;
@@ -94,6 +95,7 @@
 import com.android.systemui.keyguard.WakefulnessLifecycle;
 import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager;
 import com.android.systemui.model.SysUiState;
+import com.android.systemui.model.SysUiState.SysUiStateCallback;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.NavigationModeController;
 import com.android.systemui.navigationbar.views.NavigationBar;
@@ -584,7 +586,8 @@
 
             // Force-update the systemui state flags
             updateSystemUiStateFlags();
-            notifySystemUiStateFlags(mSysUiState.getFlags());
+            // TODO b/398011576 - send the state for all displays.
+            notifySystemUiStateFlags(mSysUiState.getFlags(), Display.DEFAULT_DISPLAY);
 
             notifyConnectionChanged();
         }
@@ -650,6 +653,13 @@
                 }
             };
 
+    private final SysUiStateCallback mSysUiStateCallback =
+            new SysUiStateCallback() {
+                @Override
+                public void onSystemUiStateChanged(long sysUiFlags, int displayId) {
+                    notifySystemUiStateFlags(sysUiFlags, displayId);
+                }
+            };
     @SuppressWarnings("OptionalUsedAsFieldOrParameterType")
     @Inject
     public LauncherProxyService(Context context,
@@ -708,8 +718,10 @@
                 com.android.internal.R.string.config_recentsComponentName));
         mQuickStepIntent = new Intent(ACTION_QUICKSTEP)
                 .setPackage(mRecentsComponentName.getPackageName());
+        // TODO b/398011576 - Here we're still only handling the default display state. We should
+        //  have a callback for any sysuiState change.
         mSysUiState = sysUiState;
-        mSysUiState.addCallback(this::notifySystemUiStateFlags);
+        mSysUiState.addCallback(mSysUiStateCallback);
         mUiEventLogger = uiEventLogger;
         mDisplayTracker = displayTracker;
         mUnfoldTransitionProgressForwarder = unfoldTransitionProgressForwarder;
@@ -815,14 +827,15 @@
         }
     }
 
-    private void notifySystemUiStateFlags(@SystemUiStateFlags long flags) {
+    private void notifySystemUiStateFlags(@SystemUiStateFlags long flags, int displayId) {
         if (SysUiState.DEBUG) {
             Log.d(TAG_OPS, "Notifying sysui state change to launcher service: proxy="
-                    + mLauncherProxy + " flags=" + flags);
+                    + mLauncherProxy + " display=" + displayId + " flags="
+                    + QuickStepContract.getSystemUiStateString(flags) + " displayId=" + displayId);
         }
         try {
             if (mLauncherProxy != null) {
-                mLauncherProxy.onSystemUiStateChanged(flags);
+                mLauncherProxy.onSystemUiStateChanged(flags, displayId);
             }
         } catch (RemoteException e) {
             Log.e(TAG_OPS, "Failed to notify sysui state change", e);
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/KeyguardStateCallbackStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/KeyguardStateCallbackStartable.kt
index 4044381..ecd93b2 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/KeyguardStateCallbackStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/KeyguardStateCallbackStartable.kt
@@ -69,7 +69,7 @@
     }
 
     fun addCallback(callback: IKeyguardStateCallback) {
-        SceneContainerFlag.assertInNewMode()
+        SceneContainerFlag.unsafeAssertInNewMode()
 
         callbacks.add(callback)
 
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
index 733b421..634323c 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/flag/SceneContainerFlag.kt
@@ -83,7 +83,9 @@
      * testing.
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, DESCRIPTION)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, DESCRIPTION)
 
     /** Returns a developer-readable string that describes the current requirement list. */
     @JvmStatic
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
index 0dd0e3d..1d470c2 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt
@@ -33,6 +33,7 @@
         sceneDataSourceDelegator: SceneDataSourceDelegator,
         qsSceneAdapter: Provider<QSSceneAdapter>,
         sceneJankMonitorFactory: SceneJankMonitor.Factory,
+        windowRootViewKeyEventHandler: WindowRootViewKeyEventHandler,
     ) {
         setLayoutInsetsController(layoutInsetController)
         SceneWindowRootViewBinder.bind(
@@ -53,6 +54,7 @@
             qsSceneAdapter = qsSceneAdapter,
             sceneJankMonitorFactory = sceneJankMonitorFactory,
         )
+        setWindowRootViewKeyEventHandler(windowRootViewKeyEventHandler)
     }
 
     override fun setVisibility(visibility: Int) {
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
index 364da5f..42bf753 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootView.kt
@@ -21,6 +21,7 @@
 import android.util.AttributeSet
 import android.util.Pair
 import android.view.DisplayCutout
+import android.view.KeyEvent
 import android.view.View
 import android.view.WindowInsets
 import android.widget.FrameLayout
@@ -37,6 +38,11 @@
     private var rightInset = 0
 
     private var previousInsets: WindowInsets? = null
+    private lateinit var windowRootViewKeyEventHandler: WindowRootViewKeyEventHandler
+
+    fun setWindowRootViewKeyEventHandler(wrvkeh: WindowRootViewKeyEventHandler) {
+        windowRootViewKeyEventHandler = wrvkeh
+    }
 
     override fun onAttachedToWindow() {
         super.onAttachedToWindow()
@@ -137,6 +143,24 @@
         return parent.let { it !is View || it.id == android.R.id.content }
     }
 
+    override fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        windowRootViewKeyEventHandler.collectKeyEvent(event)
+
+        if (windowRootViewKeyEventHandler.interceptMediaKey(event)) {
+            return true
+        }
+
+        if (super.dispatchKeyEvent(event)) {
+            return true
+        }
+
+        return windowRootViewKeyEventHandler.dispatchKeyEvent(event)
+    }
+
+    override fun dispatchKeyEventPreIme(event: KeyEvent): Boolean {
+        return windowRootViewKeyEventHandler.dispatchKeyEventPreIme(event) ?: false
+    }
+
     /** Controller responsible for calculating insets for the shade window. */
     interface LayoutInsetsController {
 
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootViewKeyEventHandler.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootViewKeyEventHandler.kt
new file mode 100644
index 0000000..863af92
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/WindowRootViewKeyEventHandler.kt
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.ui.view
+
+import android.view.KeyEvent
+import com.android.systemui.classifier.FalsingCollector
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler
+import dagger.Lazy
+import javax.inject.Inject
+
+@SysUISingleton
+class WindowRootViewKeyEventHandler
+@Inject
+constructor(
+    val sysUIKeyEventHandlerLazy: Lazy<SysUIKeyEventHandler>,
+    val falsingCollector: FalsingCollector,
+) {
+    fun dispatchKeyEvent(event: KeyEvent): Boolean {
+        return sysUIKeyEventHandlerLazy.get().dispatchKeyEvent(event)
+    }
+
+    fun dispatchKeyEventPreIme(event: KeyEvent): Boolean {
+        return sysUIKeyEventHandlerLazy.get().dispatchKeyEventPreIme(event)
+    }
+
+    fun interceptMediaKey(event: KeyEvent): Boolean {
+        return sysUIKeyEventHandlerLazy.get().interceptMediaKey(event)
+    }
+
+    /** Collects the KeyEvent without intercepting it. */
+    fun collectKeyEvent(event: KeyEvent) {
+        falsingCollector.onKeyEvent(event)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
index 9208fc3..271f4dc 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ActionIntentCreator.kt
@@ -23,18 +23,31 @@
 import android.content.Context
 import android.content.Intent
 import android.content.pm.PackageManager
+import android.content.pm.PackageManager.NameNotFoundException
 import android.net.Uri
 import android.os.UserHandle
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.res.R
 import com.android.systemui.screenshot.scroll.LongScreenshotActivity
 import com.android.systemui.shared.Flags.usePreferredImageEditor
+import java.util.function.Consumer
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.withContext
 
 @SysUISingleton
 class ActionIntentCreator
 @Inject
-constructor(private val context: Context, private val packageManager: PackageManager) {
+constructor(
+    private val context: Context,
+    private val packageManager: PackageManager,
+    @Application private val applicationScope: CoroutineScope,
+    @Background private val backgroundDispatcher: CoroutineDispatcher,
+) {
     /** @return a chooser intent to share the given URI. */
     fun createShare(uri: Uri): Intent = createShare(uri, subject = null, text = null)
 
@@ -76,11 +89,16 @@
             .addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
     }
 
+    // Non-suspend version for java compat
+    fun createEdit(rawUri: Uri, consumer: Consumer<Intent>) {
+        applicationScope.launch { consumer.accept(createEdit(rawUri)) }
+    }
+
     /**
      * @return an ACTION_EDIT intent for the given URI, directed to config_preferredScreenshotEditor
      *   if enabled, falling back to config_screenshotEditor if that's non-empty.
      */
-    fun createEdit(rawUri: Uri): Intent {
+    suspend fun createEdit(rawUri: Uri): Intent {
         val uri = uriWithoutUserId(rawUri)
         val editIntent = Intent(Intent.ACTION_EDIT)
 
@@ -112,22 +130,30 @@
             .addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
     }
 
-    private fun preferredEditor(): ComponentName? =
+    private suspend fun preferredEditor(): ComponentName? =
         runCatching {
                 val preferredEditor = context.getString(R.string.config_preferredScreenshotEditor)
                 val component = ComponentName.unflattenFromString(preferredEditor) ?: return null
 
+                return if (isComponentAvailable(component)) component else null
+            }
+            .getOrNull()
+
+    private suspend fun isComponentAvailable(component: ComponentName): Boolean =
+        withContext(backgroundDispatcher) {
+            try {
                 val info =
                     packageManager.getPackageInfo(
                         component.packageName,
                         PackageManager.GET_ACTIVITIES,
                     )
-
-                return info.activities
-                    ?.firstOrNull { it.componentName.className.equals(component.className) }
-                    ?.componentName
+                info.activities?.firstOrNull {
+                    it.componentName.className == component.className
+                } != null
+            } catch (e: NameNotFoundException) {
+                false
             }
-            .getOrNull()
+        }
 
     private fun defaultEditor(): ComponentName? =
         runCatching {
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
index 4373389..d91f267 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/ScreenshotActionsProvider.kt
@@ -22,6 +22,7 @@
 import android.util.Log
 import androidx.appcompat.content.res.AppCompatResources
 import com.android.internal.logging.UiEventLogger
+import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.log.DebugLogger.debugLog
 import com.android.systemui.res.R
 import com.android.systemui.screenshot.ScreenshotEvent.SCREENSHOT_EDIT_TAPPED
@@ -34,6 +35,8 @@
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
 import java.util.UUID
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 /**
  * Provides actions for screenshots. This class can be overridden by a vendor-specific SysUI
@@ -68,6 +71,7 @@
     private val context: Context,
     private val uiEventLogger: UiEventLogger,
     private val actionIntentCreator: ActionIntentCreator,
+    @Application private val applicationScope: CoroutineScope,
     @Assisted val requestId: UUID,
     @Assisted val request: ScreenshotData,
     @Assisted val actionExecutor: ActionExecutor,
@@ -75,7 +79,7 @@
 ) : ScreenshotActionsProvider {
     private var addedScrollChip = false
     private var onScrollClick: Runnable? = null
-    private var pendingAction: ((ScreenshotSavedResult) -> Unit)? = null
+    private var pendingAction: (suspend (ScreenshotSavedResult) -> Unit)? = null
     private var result: ScreenshotSavedResult? = null
     private var webUri: Uri? = null
 
@@ -166,15 +170,16 @@
             return
         }
         this.result = result
-        pendingAction?.invoke(result)
+        pendingAction?.also { applicationScope.launch { it.invoke(result) } }
     }
 
     override fun onAssistContent(assistContent: AssistContent?) {
         webUri = assistContent?.webUri
     }
 
-    private fun onDeferrableActionTapped(onResult: (ScreenshotSavedResult) -> Unit) {
-        result?.let { onResult.invoke(it) } ?: run { pendingAction = onResult }
+    private fun onDeferrableActionTapped(onResult: suspend (ScreenshotSavedResult) -> Unit) {
+        result?.let { applicationScope.launch { onResult.invoke(it) } }
+            ?: run { pendingAction = onResult }
     }
 
     @AssistedFactory
@@ -188,6 +193,6 @@
     }
 
     companion object {
-        private const val TAG = "ScreenshotActionsProvider"
+        private const val TAG = "ScreenshotActionsPrvdr"
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/screenshot/scroll/LongScreenshotActivity.java b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/LongScreenshotActivity.java
index 48e08a0..88ffd4f 100644
--- a/packages/SystemUI/src/com/android/systemui/screenshot/scroll/LongScreenshotActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/screenshot/scroll/LongScreenshotActivity.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.screenshot.scroll;
 
+import static com.android.systemui.shared.Flags.usePreferredImageEditor;
+
 import android.app.Activity;
 import android.app.ActivityOptions;
 import android.content.ComponentName;
@@ -350,31 +352,57 @@
     private void doEdit(Uri uri) {
         if (mScreenshotUserHandle != Process.myUserHandle()) {
             // TODO: Fix transition for work profile. Omitting it in the meantime.
-            mActionExecutor.launchIntentAsync(
-                    mActionIntentCreator.createEdit(uri),
-                    mScreenshotUserHandle, false,
-                    /* activityOptions */ null, /* transitionCoordinator */ null);
-        } else {
-            String editorPackage = getString(R.string.config_screenshotEditor);
-            Intent intent = new Intent(Intent.ACTION_EDIT);
-            intent.setDataAndType(uri, "image/png");
-            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
-                    | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
-            Bundle options = null;
+            mActionIntentCreator.createEdit(uri, intent -> {
+                mActionExecutor.launchIntentAsync(
+                        intent,
+                        mScreenshotUserHandle, false,
+                        /* activityOptions */ null, /* transitionCoordinator */ null);
+            });
 
-            // Skip shared element transition for implicit edit intents
-            if (!TextUtils.isEmpty(editorPackage)) {
-                intent.setComponent(ComponentName.unflattenFromString(editorPackage));
-                mTransitionView.setImageBitmap(mOutputBitmap);
-                mTransitionView.setVisibility(View.VISIBLE);
-                mTransitionView.setTransitionName(
-                        ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME);
-                options = ActivityOptions.makeSceneTransitionAnimation(this, mTransitionView,
-                        ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle();
-                // TODO: listen for transition completing instead of finishing onStop
-                mTransitionStarted = true;
+        } else {
+            if (usePreferredImageEditor()) {
+                mActionIntentCreator.createEdit(uri, intent -> {
+                    Bundle options = null;
+
+                    if (intent.getComponent() != null) {
+                        // Modify intent for shared transition if we're opening a specific editor.
+                        intent.removeFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+                        intent.removeFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+                        mTransitionView.setImageBitmap(mOutputBitmap);
+                        mTransitionView.setVisibility(View.VISIBLE);
+                        mTransitionView.setTransitionName(
+                                ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME);
+                        options = ActivityOptions.makeSceneTransitionAnimation(this,
+                                mTransitionView,
+                                ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle();
+                        // TODO: listen for transition completing instead of finishing onStop
+                        mTransitionStarted = true;
+                    }
+
+                    startActivity(intent, options);
+                });
+            } else {
+                String editorPackage = getString(R.string.config_screenshotEditor);
+                Intent intent = new Intent(Intent.ACTION_EDIT);
+                intent.setDataAndType(uri, "image/png");
+                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION
+                        | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
+                Bundle options = null;
+
+                // Skip shared element transition for implicit edit intents
+                if (!TextUtils.isEmpty(editorPackage)) {
+                    intent.setComponent(ComponentName.unflattenFromString(editorPackage));
+                    mTransitionView.setImageBitmap(mOutputBitmap);
+                    mTransitionView.setVisibility(View.VISIBLE);
+                    mTransitionView.setTransitionName(
+                            ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME);
+                    options = ActivityOptions.makeSceneTransitionAnimation(this, mTransitionView,
+                            ChooserActivity.FIRST_IMAGE_PREVIEW_TRANSITION_NAME).toBundle();
+                    // TODO: listen for transition completing instead of finishing onStop
+                    mTransitionStarted = true;
+                }
+                startActivity(intent, options);
             }
-            startActivity(intent, options);
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/settings/brightness/ComposeDialogComposableProvider.kt b/packages/SystemUI/src/com/android/systemui/settings/brightness/ComposeDialogComposableProvider.kt
index dde2ebc..9e20055 100644
--- a/packages/SystemUI/src/com/android/systemui/settings/brightness/ComposeDialogComposableProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/settings/brightness/ComposeDialogComposableProvider.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.settings.brightness
 
 import androidx.compose.foundation.layout.fillMaxWidth
-import androidx.compose.foundation.layout.height
 import androidx.compose.runtime.Composable
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.platform.ComposeView
@@ -26,7 +25,6 @@
 import com.android.systemui.brightness.ui.compose.BrightnessSliderContainer
 import com.android.systemui.brightness.ui.viewmodel.BrightnessSliderViewModel
 import com.android.systemui.lifecycle.rememberViewModel
-import com.android.systemui.qs.ui.composable.QuickSettingsShade
 
 object ComposeDialogComposableProvider {
 
@@ -46,10 +44,7 @@
         rememberViewModel(traceName = "BrightnessDialog.viewModel") {
             brightnessSliderViewModelFactory.create(false)
         }
-    BrightnessSliderContainer(
-        viewModel = viewModel,
-        Modifier.fillMaxWidth().height(QuickSettingsShade.Dimensions.BrightnessSliderHeight),
-    )
+    BrightnessSliderContainer(viewModel = viewModel, Modifier.fillMaxWidth())
 }
 
 class ComposableProvider(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index eea0470..24e7976 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -65,6 +65,7 @@
 import android.util.IndentingPrintWriter;
 import android.util.Log;
 import android.util.MathUtils;
+import android.view.Display;
 import android.view.HapticFeedbackConstants;
 import android.view.InputDevice;
 import android.view.MotionEvent;
@@ -96,6 +97,7 @@
 import com.android.systemui.bouncer.domain.interactor.AlternateBouncerInteractor;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.classifier.FalsingCollector;
+import com.android.systemui.common.domain.interactor.SysUIStateDisplaysInteractor;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -119,6 +121,7 @@
 import com.android.systemui.media.controls.domain.pipeline.MediaDataManager;
 import com.android.systemui.media.controls.ui.controller.KeyguardMediaController;
 import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager;
+import com.android.systemui.model.StateChange;
 import com.android.systemui.model.SysUiState;
 import com.android.systemui.navigationbar.NavigationBarController;
 import com.android.systemui.navigationbar.NavigationModeController;
@@ -137,6 +140,7 @@
 import com.android.systemui.settings.brightness.data.repository.BrightnessMirrorShowingRepository;
 import com.android.systemui.settings.brightness.domain.interactor.BrightnessMirrorShowingInteractor;
 import com.android.systemui.shade.data.repository.FlingInfo;
+import com.android.systemui.shade.data.repository.ShadeDisplaysRepository;
 import com.android.systemui.shade.data.repository.ShadeRepository;
 import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor;
 import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround;
@@ -201,6 +205,7 @@
 import com.google.android.msdl.data.model.MSDLToken;
 import com.google.android.msdl.domain.MSDLPlayer;
 
+import dagger.Lazy;
 import kotlin.Unit;
 
 import kotlinx.coroutines.CoroutineDispatcher;
@@ -391,7 +396,7 @@
     /** Whether the notifications are displayed full width (no margins on the side). */
     private boolean mIsFullWidth;
     private boolean mBlockingExpansionForCurrentTouch;
-     // Following variables maintain state of events when input focus transfer may occur.
+    // Following variables maintain state of events when input focus transfer may occur.
     private boolean mExpectingSynthesizedDown;
     private boolean mLastEventSynthesizedDown;
 
@@ -450,7 +455,10 @@
     private final MediaDataManager mMediaDataManager;
     @PanelState
     private int mCurrentPanelState = STATE_CLOSED;
+    @Deprecated // Use SysUIStateInteractor instead
     private final SysUiState mSysUiState;
+    private final SysUIStateDisplaysInteractor mSysUIStateDisplaysInteractor;
+    private final Lazy<ShadeDisplaysRepository> mShadeDisplaysRepository;
     private final NotificationShadeDepthController mDepthController;
     private final NavigationBarController mNavigationBarController;
     private final int mDisplayId;
@@ -607,6 +615,7 @@
             ShadeRepository shadeRepository,
             Optional<SysUIUnfoldComponent> unfoldComponent,
             SysUiState sysUiState,
+            SysUIStateDisplaysInteractor sysUIStateDisplaysInteractor,
             KeyguardUnlockAnimationController keyguardUnlockAnimationController,
             KeyguardIndicationController keyguardIndicationController,
             NotificationListContainer notificationListContainer,
@@ -631,7 +640,8 @@
             KeyguardClockPositionAlgorithm keyguardClockPositionAlgorithm,
             MSDLPlayer msdlPlayer,
             BrightnessMirrorShowingRepository brightnessMirrorShowingRepository,
-            BlurConfig blurConfig) {
+            BlurConfig blurConfig,
+            Lazy<ShadeDisplaysRepository> shadeDisplaysRepository) {
         mBlurConfig = blurConfig;
         SceneContainerFlag.assertInLegacyMode();
         keyguardStateController.addCallback(new KeyguardStateController.Callback() {
@@ -738,6 +748,8 @@
         mMediaDataManager = mediaDataManager;
         mTapAgainViewController = tapAgainViewController;
         mSysUiState = sysUiState;
+        mSysUIStateDisplaysInteractor = sysUIStateDisplaysInteractor;
+        mShadeDisplaysRepository = shadeDisplaysRepository;
         mKeyguardBypassController = bypassController;
         mUpdateMonitor = keyguardUpdateMonitor;
         mLockscreenShadeTransitionController = lockscreenShadeTransitionController;
@@ -2253,7 +2265,7 @@
             Log.i(TAG, "Ignoring status Bar long press on virtualized test device.");
             return;
         }
-        ShadeExpandsOnStatusBarLongPress.assertInNewMode();
+        ShadeExpandsOnStatusBarLongPress.unsafeAssertInNewMode();
         mStatusBarLongPressDowntime = event.getDownTime();
         if (isTracking()) {
             onTrackingStopped(true);
@@ -2701,13 +2713,50 @@
             Log.d(TAG, "Updating panel sysui state flags: fullyExpanded="
                     + isFullyExpanded() + " inQs=" + mQsController.getExpanded());
         }
+        if (ShadeWindowGoesAround.isEnabled()) {
+            setPerDisplaySysUIStateFlags();
+        } else {
+            setDefaultDisplayFlags();
+        }
+    }
+
+    private int getShadeDisplayId() {
+        if (ShadeWindowGoesAround.isEnabled()) {
+            var pendingDisplayId =
+                    mShadeDisplaysRepository.get().getPendingDisplayId().getValue();
+            // Use the pendingDisplayId from the repository, *not* the Shade's context.
+            // This ensures correct UI state updates also if this method is called just *before*
+            // the Shade window moves to another display.
+            // The pendingDisplayId is guaranteed to be updated before this method is called.
+            return pendingDisplayId;
+        } else {
+            return Display.DEFAULT_DISPLAY;
+        }
+    }
+
+    private void setPerDisplaySysUIStateFlags() {
+        mSysUIStateDisplaysInteractor.setFlagsExclusivelyToDisplay(
+                getShadeDisplayId(),
+                new StateChange()
+                        .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE,
+                                isPanelExpanded() && !isCollapsing())
+                        .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
+                                isFullyExpanded() && !mQsController.getExpanded())
+                        .setFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
+                                isFullyExpanded() && mQsController.getExpanded())
+        );
+    }
+
+    @Deprecated
+    private void setDefaultDisplayFlags() {
         mSysUiState
                 .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE,
                         isPanelExpanded() && !isCollapsing())
                 .setFlag(SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED,
                         isFullyExpanded() && !mQsController.getExpanded())
                 .setFlag(SYSUI_STATE_QUICK_SETTINGS_EXPANDED,
-                        isFullyExpanded() && mQsController.getExpanded()).commitUpdate(mDisplayId);
+                        isFullyExpanded() && mQsController.getExpanded()).commitUpdate(
+                        mDisplayId);
     }
 
     private void debugLog(String fmt, Object... args) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
index 1721700..84efdc2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowView.java
@@ -105,26 +105,6 @@
         }
     }
 
-    @Override
-    public boolean dispatchKeyEvent(KeyEvent event) {
-        mInteractionEventHandler.collectKeyEvent(event);
-
-        if (mInteractionEventHandler.interceptMediaKey(event)) {
-            return true;
-        }
-
-        if (super.dispatchKeyEvent(event)) {
-            return true;
-        }
-
-        return mInteractionEventHandler.dispatchKeyEvent(event);
-    }
-
-    @Override
-    public boolean dispatchKeyEventPreIme(KeyEvent event) {
-        return mInteractionEventHandler.dispatchKeyEventPreIme(event);
-    }
-
     protected void setInteractionEventHandler(InteractionEventHandler listener) {
         mInteractionEventHandler = listener;
     }
@@ -363,17 +343,6 @@
         boolean handleTouchEvent(MotionEvent ev);
 
         void didNotHandleTouchEvent(MotionEvent ev);
-
-        boolean interceptMediaKey(KeyEvent event);
-
-        boolean dispatchKeyEvent(KeyEvent event);
-
-        boolean dispatchKeyEventPreIme(KeyEvent event);
-
-        /**
-         * Collects the KeyEvent without intercepting it
-         */
-        void collectKeyEvent(KeyEvent event);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index 10a9fd2..c74f6c3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -27,7 +27,6 @@
 import android.util.Log;
 import android.view.Choreographer;
 import android.view.GestureDetector;
-import android.view.KeyEvent;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewGroup;
@@ -50,7 +49,6 @@
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlagsClassic;
 import com.android.systemui.flags.Flags;
-import com.android.systemui.keyevent.domain.interactor.SysUIKeyEventHandler;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor;
 import com.android.systemui.keyguard.shared.model.Edge;
@@ -60,6 +58,7 @@
 import com.android.systemui.qs.flags.QSComposeFragment;
 import com.android.systemui.res.R;
 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
+import com.android.systemui.scene.ui.view.WindowRootViewKeyEventHandler;
 import com.android.systemui.settings.brightness.domain.interactor.BrightnessMirrorShowingInteractor;
 import com.android.systemui.shade.domain.interactor.PanelExpansionInteractor;
 import com.android.systemui.shade.domain.interactor.ShadeAnimationInteractor;
@@ -89,7 +88,6 @@
 import com.android.systemui.window.ui.viewmodel.WindowRootViewModel;
 
 import kotlinx.coroutines.CoroutineDispatcher;
-import kotlinx.coroutines.ExperimentalCoroutinesApi;
 import kotlinx.coroutines.flow.Flow;
 
 import java.io.PrintWriter;
@@ -117,8 +115,7 @@
     private final AmbientState mAmbientState;
     private final PulsingGestureListener mPulsingGestureListener;
     private final NotificationInsetsController mNotificationInsetsController;
-    private final FeatureFlagsClassic mFeatureFlagsClassic;
-    private final SysUIKeyEventHandler mSysUIKeyEventHandler;
+    private final WindowRootViewKeyEventHandler mWindowRootViewKeyEventHandler;
     private final PrimaryBouncerInteractor mPrimaryBouncerInteractor;
     private final AlternateBouncerInteractor mAlternateBouncerInteractor;
     private final QuickSettingsController mQuickSettingsController;
@@ -202,7 +199,7 @@
             NotificationLaunchAnimationInteractor notificationLaunchAnimationInteractor,
             FeatureFlagsClassic featureFlagsClassic,
             SystemClock clock,
-            SysUIKeyEventHandler sysUIKeyEventHandler,
+            WindowRootViewKeyEventHandler windowRootViewKeyEventHandler,
             QuickSettingsController quickSettingsController,
             PrimaryBouncerInteractor primaryBouncerInteractor,
             AlternateBouncerInteractor alternateBouncerInteractor,
@@ -232,8 +229,7 @@
         mNotificationInsetsController = notificationInsetsController;
         mKeyguardTransitionInteractor = keyguardTransitionInteractor;
         mGlanceableHubContainerController = glanceableHubContainerController;
-        mFeatureFlagsClassic = featureFlagsClassic;
-        mSysUIKeyEventHandler = sysUIKeyEventHandler;
+        mWindowRootViewKeyEventHandler = windowRootViewKeyEventHandler;
         mPrimaryBouncerInteractor = primaryBouncerInteractor;
         mAlternateBouncerInteractor = alternateBouncerInteractor;
         mQuickSettingsController = quickSettingsController;
@@ -370,6 +366,7 @@
         mPulsingWakeupGestureHandler = new GestureDetector(mView.getContext(),
                 mPulsingGestureListener);
         mView.setLayoutInsetsController(mNotificationInsetsController);
+        mView.setWindowRootViewKeyEventHandler(mWindowRootViewKeyEventHandler);
         mView.setInteractionEventHandler(new NotificationShadeWindowView.InteractionEventHandler() {
             boolean mUseDragDownHelperForTouch = false;
             boolean mLastInterceptWasDragDownHelper = false;
@@ -605,26 +602,6 @@
                     mService.setInteracting(StatusBarManager.WINDOW_STATUS_BAR, false);
                 }
             }
-
-            @Override
-            public boolean interceptMediaKey(KeyEvent event) {
-                return mSysUIKeyEventHandler.interceptMediaKey(event);
-            }
-
-            @Override
-            public boolean dispatchKeyEventPreIme(KeyEvent event) {
-                return mSysUIKeyEventHandler.dispatchKeyEventPreIme(event);
-            }
-
-            @Override
-            public boolean dispatchKeyEvent(KeyEvent event) {
-                return mSysUIKeyEventHandler.dispatchKeyEvent(event);
-            }
-
-            @Override
-            public void collectKeyEvent(KeyEvent event) {
-                mFalsingCollector.onKeyEvent(event);
-            }
         });
 
         mView.setOnHierarchyChangeListener(new ViewGroup.OnHierarchyChangeListener() {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
index 42c63f9..c671f7d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/QuickSettingsControllerImpl.java
@@ -959,6 +959,7 @@
     void setShadeExpansion(float expandedHeight, float expandedFraction) {
         mShadeExpandedHeight = expandedHeight;
         mShadeExpandedFraction = expandedFraction;
+        mMediaHierarchyManager.setShadeExpandedFraction(expandedFraction);
     }
 
     @VisibleForTesting
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
index 96b224f..cd22473 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeDisplayAwareModule.kt
@@ -36,6 +36,7 @@
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.res.R
 import com.android.systemui.scene.ui.view.WindowRootView
+import com.android.systemui.shade.data.repository.MutableShadeDisplaysRepository
 import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
 import com.android.systemui.shade.data.repository.ShadeDisplaysRepositoryImpl
 import com.android.systemui.shade.display.ShadeDisplayPolicyModule
@@ -205,7 +206,18 @@
 
     @SysUISingleton
     @Provides
-    fun provideShadePositionRepository(impl: ShadeDisplaysRepositoryImpl): ShadeDisplaysRepository {
+    fun provideShadePositionRepository(
+        impl: MutableShadeDisplaysRepository
+    ): ShadeDisplaysRepository {
+        ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
+        return impl
+    }
+
+    @SysUISingleton
+    @Provides
+    fun provideMutableShadePositionRepository(
+        impl: ShadeDisplaysRepositoryImpl
+    ): MutableShadeDisplaysRepository {
         ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
         return impl
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpandsOnStatusBarLongPress.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpandsOnStatusBarLongPress.kt
index 6d8e898..63b618f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeExpandsOnStatusBarLongPress.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeExpandsOnStatusBarLongPress.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
index 55ee27d..150ef3a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
@@ -42,6 +42,7 @@
 import com.android.systemui.scene.ui.view.SceneJankMonitor
 import com.android.systemui.scene.ui.view.SceneWindowRootView
 import com.android.systemui.scene.ui.view.WindowRootView
+import com.android.systemui.scene.ui.view.WindowRootViewKeyEventHandler
 import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
 import com.android.systemui.settings.UserTracker
 import com.android.systemui.statusbar.LightRevealScrim
@@ -88,6 +89,7 @@
             sceneDataSourceDelegator: Provider<SceneDataSourceDelegator>,
             qsSceneAdapter: Provider<QSSceneAdapter>,
             sceneJankMonitorFactory: SceneJankMonitor.Factory,
+            windowRootViewKeyEventHandler: WindowRootViewKeyEventHandler,
         ): WindowRootView {
             return if (SceneContainerFlag.isEnabled) {
                 checkNoSceneDuplicates(scenesProvider.get())
@@ -104,6 +106,7 @@
                     sceneDataSourceDelegator = sceneDataSourceDelegator.get(),
                     qsSceneAdapter = qsSceneAdapter,
                     sceneJankMonitorFactory = sceneJankMonitorFactory,
+                    windowRootViewKeyEventHandler = windowRootViewKeyEventHandler,
                 )
                 sceneWindowRootView
             } else {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
index 3513334..e18ed83 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/FakeShadeDisplayRepository.kt
@@ -22,16 +22,28 @@
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 
-class FakeShadeDisplayRepository : ShadeDisplaysRepository {
+class FakeShadeDisplayRepository : MutableShadeDisplaysRepository {
     private val _displayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
+    private val _pendingDisplayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
 
     fun setDisplayId(displayId: Int) {
         _displayId.value = displayId
     }
 
+    fun setPendingDisplayId(displayId: Int) {
+        _pendingDisplayId.value = displayId
+    }
+
+    override fun onDisplayChangedSucceeded(displayId: Int) {
+        setDisplayId(displayId)
+    }
+
     override val displayId: StateFlow<Int>
         get() = _displayId
 
+    override val pendingDisplayId: StateFlow<Int>
+        get() = _pendingDisplayId
+
     override val currentPolicy: ShadeDisplayPolicy
         get() = FakeShadeDisplayPolicy
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
index 2a14ca4..7117a23 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeDisplaysRepository.kt
@@ -29,6 +29,7 @@
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
@@ -40,10 +41,28 @@
 
 /** Source of truth for the display currently holding the shade. */
 interface ShadeDisplaysRepository {
-    /** ID of the display which currently hosts the shade */
+    /** ID of the display which currently hosts the shade. */
     val displayId: StateFlow<Int>
     /** The current policy set. */
     val currentPolicy: ShadeDisplayPolicy
+
+    /**
+     * Id of the display that should host the shade.
+     *
+     * If this differs from [displayId], it means there is a shade movement in progress. Classes
+     * that rely on the shade being already moved (and its context/resources updated) should rely on
+     * [displayId]. Classes that need to do work associated with the shade move, should listen at
+     * this.
+     */
+    val pendingDisplayId: StateFlow<Int>
+}
+
+/** Provides a way to set whether the display changed succeeded. */
+interface MutableShadeDisplaysRepository : ShadeDisplaysRepository {
+    /**
+     * To be called when the shade changed window, and its resources have been completely updated.
+     */
+    fun onDisplayChangedSucceeded(displayId: Int)
 }
 
 /**
@@ -63,7 +82,7 @@
     @ShadeOnDefaultDisplayWhenLocked private val shadeOnDefaultDisplayWhenLocked: Boolean,
     keyguardRepository: KeyguardRepository,
     displayRepository: DisplayRepository,
-) : ShadeDisplaysRepository {
+) : MutableShadeDisplaysRepository {
 
     private val policy: StateFlow<ShadeDisplayPolicy> =
         globalSettings
@@ -105,10 +124,16 @@
     override val currentPolicy: ShadeDisplayPolicy
         get() = policy.value
 
-    override val displayId: StateFlow<Int> =
+    override val pendingDisplayId: StateFlow<Int> =
         keyguardAwareDisplayPolicy.stateIn(
             bgScope,
             SharingStarted.WhileSubscribed(),
             Display.DEFAULT_DISPLAY,
         )
+    private val _committedDisplayId = MutableStateFlow(Display.DEFAULT_DISPLAY)
+    override val displayId: StateFlow<Int> = _committedDisplayId
+
+    override fun onDisplayChangedSucceeded(displayId: Int) {
+        _committedDisplayId.value = displayId
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt
index 4edba27..3b98708 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDialogContextInteractor.kt
@@ -47,14 +47,16 @@
 constructor(
     @Main private val defaultContext: Context,
     private val displayWindowPropertyRepository: Provider<DisplayWindowPropertiesRepository>,
-    private val shadeDisplaysRepository: ShadeDisplaysRepository,
+    private val shadeDisplaysRepository: Provider<ShadeDisplaysRepository>,
     @Background private val bgScope: CoroutineScope,
 ) : CoreStartable, ShadeDialogContextInteractor {
 
     override fun start() {
         if (ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()) return
         bgScope.launchTraced(TAG) {
-            shadeDisplaysRepository.displayId
+            shadeDisplaysRepository
+                .get()
+                .displayId
                 // No need for default display pre-warming.
                 .filter { it != Display.DEFAULT_DISPLAY }
                 .collectLatest { displayId ->
@@ -70,7 +72,7 @@
             if (!ShadeWindowGoesAround.isEnabled) {
                 return defaultContext
             }
-            val displayId = shadeDisplaysRepository.displayId.value
+            val displayId = shadeDisplaysRepository.get().displayId.value
             return getContextOrDefault(displayId)
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
index 9a5c968..0e0f58d 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeDisplaysInteractor.kt
@@ -32,6 +32,7 @@
 import com.android.systemui.shade.ShadeTraceLogger.logMoveShadeWindowTo
 import com.android.systemui.shade.ShadeTraceLogger.t
 import com.android.systemui.shade.ShadeTraceLogger.traceReparenting
+import com.android.systemui.shade.data.repository.MutableShadeDisplaysRepository
 import com.android.systemui.shade.data.repository.ShadeDisplaysRepository
 import com.android.systemui.shade.display.ShadeExpansionIntent
 import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
@@ -44,6 +45,7 @@
 import kotlin.coroutines.CoroutineContext
 import kotlin.time.Duration.Companion.seconds
 import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.collectLatest
 import kotlinx.coroutines.flow.filter
 import kotlinx.coroutines.flow.first
@@ -55,7 +57,7 @@
 class ShadeDisplaysInteractor
 @Inject
 constructor(
-    private val shadePositionRepository: ShadeDisplaysRepository,
+    private val shadePositionRepository: MutableShadeDisplaysRepository,
     @ShadeDisplayAware private val shadeContext: WindowContext,
     @ShadeDisplayAware private val configurationRepository: ConfigurationRepository,
     @Background private val bgScope: CoroutineScope,
@@ -72,11 +74,14 @@
     private val hasActiveNotifications: Boolean
         get() = activeNotificationsInteractor.areAnyNotificationsPresentValue
 
+    /** Current display id of the shade window. */
+    val displayId: StateFlow<Int> = shadePositionRepository.displayId
+
     override fun start() {
         ShadeWindowGoesAround.isUnexpectedlyInLegacyMode()
         listenForWindowContextConfigChanges()
         bgScope.launchTraced(TAG) {
-            shadePositionRepository.displayId.collectLatest { displayId ->
+            shadePositionRepository.pendingDisplayId.collectLatest { displayId ->
                 moveShadeWindowTo(displayId)
             }
         }
@@ -108,7 +113,8 @@
             val currentDisplay = shadeContext.display ?: error("Current shade display is null")
             currentId = currentDisplay.displayId
             if (currentId == destinationId) {
-                error("Trying to move the shade to a display it was already in")
+                Log.w(TAG, "Trying to move the shade to a display ($currentId) it was already in ")
+                return
             }
 
             withContext(mainThreadContext) {
@@ -118,6 +124,7 @@
                         reparentToDisplayId(id = destinationId)
                     }
                     checkContextDisplayMatchesExpected(destinationId)
+                    shadePositionRepository.onDisplayChangedSucceeded(destinationId)
                 }
             }
         } catch (e: IllegalStateException) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
index 8114685..52de0ab 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
@@ -56,7 +56,7 @@
     private val shadeModeInteractor: ShadeModeInteractor,
 ) : BaseShadeInteractor {
     init {
-        SceneContainerFlag.assertInNewMode()
+        SceneContainerFlag.unsafeAssertInNewMode()
     }
 
     override val shadeExpansion: StateFlow<Float> =
diff --git a/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt b/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt
index dc444ff..81824f6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/shared/flag/ShadeWindowGoesAround.kt
@@ -67,7 +67,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
index bfd512f..ef0660f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyboardShortcutListSearch.java
@@ -566,12 +566,11 @@
                         Arrays.asList(
                                 Pair.create(KeyEvent.KEYCODE_TAB, KeyEvent.META_META_ON))),
                 /* Back: go back to previous state (back button) */
-                /* Meta + Escape, Meta + backspace, Meta + left arrow */
+                /* Meta + Escape, Meta + left arrow */
                 new ShortcutKeyGroupMultiMappingInfo(
                         context.getString(R.string.group_system_go_back),
                         Arrays.asList(
                                 Pair.create(KeyEvent.KEYCODE_ESCAPE, KeyEvent.META_META_ON),
-                                Pair.create(KeyEvent.KEYCODE_DEL, KeyEvent.META_META_ON),
                                 Pair.create(KeyEvent.KEYCODE_DPAD_LEFT, KeyEvent.META_META_ON))),
                 /* Take a full screenshot: Meta + S */
                 new ShortcutKeyGroupMultiMappingInfo(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
index 32da6ff..ec04edb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationLockscreenUserManagerImpl.java
@@ -47,6 +47,7 @@
 import android.net.Uri;
 import android.os.Looper;
 import android.os.Process;
+import android.os.SystemClock;
 import android.os.UserHandle;
 import android.os.UserManager;
 import android.provider.Settings;
@@ -75,6 +76,7 @@
 import com.android.systemui.recents.LauncherProxyService;
 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
 import com.android.systemui.settings.UserTracker;
+import com.android.systemui.shared.system.SysUiStatsLog;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection;
 import com.android.systemui.statusbar.notification.collection.render.NotificationVisibilityProvider;
@@ -809,6 +811,10 @@
      *    lock time.
      */
     private boolean shouldShowSensitiveContentRedactedView(NotificationEntry ent) {
+        if (android.app.Flags.redactionOnLockscreenMetrics()) {
+            return shouldShowSensitiveContentRedactedViewWithLog(ent);
+        }
+
         if (!LockscreenOtpRedaction.isEnabled()) {
             return false;
         }
@@ -817,6 +823,7 @@
             return false;
         }
 
+        long notificationTime = getEarliestNotificationTime(ent);
         if (!mRedactOtpOnWifi.get()) {
             if (mConnectedToWifi.get()) {
                 return false;
@@ -824,7 +831,7 @@
 
             long lastWifiConnectTime = mLastWifiConnectionTime.get();
             // If the device has connected to wifi since receiving the notification, do not redact
-            if (ent.getSbn().getPostTime() < lastWifiConnectTime) {
+            if (notificationTime < lastWifiConnectTime) {
                 return false;
             }
         }
@@ -837,13 +844,87 @@
         // when this notification arrived, do not redact
         long latestTimeForRedaction = mLastLockTime.get() + mOtpRedactionRequiredLockTimeMs.get();
 
-        if (ent.getSbn().getPostTime() < latestTimeForRedaction) {
+        if (notificationTime < latestTimeForRedaction) {
             return false;
         }
 
         return true;
     }
 
+    /*
+     * We show the sensitive content redaction view if
+     * 1. The feature is enabled
+     * 2. The notification has the `hasSensitiveContent` ranking variable set to true
+     * 3. The device is locked
+     * 4. The device is NOT connected to Wifi
+     * 5. The device has not connected to Wifi since receiving the notification
+     * 6. The notification arrived at least LOCK_TIME_FOR_SENSITIVE_REDACTION_MS after the last
+     *    lock time.
+     *
+     * This version of the method logs a metric about the request.
+     */
+    private boolean shouldShowSensitiveContentRedactedViewWithLog(NotificationEntry ent) {
+        if (!LockscreenOtpRedaction.isEnabled()) {
+            return false;
+        }
+
+        if (ent.getRanking() == null || !ent.getRanking().hasSensitiveContent()) {
+            return false;
+        }
+
+        long notificationWhen = ent.getSbn().getNotification().getWhen();
+        long notificationTime = getEarliestNotificationTime(ent);
+        boolean locked = mLocked.get();
+        long lockTime = mLastLockTime.get();
+        boolean wifiConnected = mConnectedToWifi.get();
+        long wifiConnectionTime = mLastWifiConnectionTime.get();
+
+        boolean shouldRedact = true;
+        if (!locked) {
+            shouldRedact = false;
+        }
+
+        if (!mRedactOtpOnWifi.get()) {
+            if (wifiConnected) {
+                shouldRedact = false;
+            }
+
+            // If the device has connected to wifi since receiving the notification, do not redact
+            if (notificationTime < wifiConnectionTime) {
+                shouldRedact = false;
+            }
+        }
+
+        // If the lock screen was not already locked for at least mOtpRedactionRequiredLockTimeMs
+        // when this notification arrived, do not redact
+        long latestTimeForRedaction = lockTime + mOtpRedactionRequiredLockTimeMs.get();
+
+        if (notificationTime < latestTimeForRedaction) {
+            shouldRedact = false;
+        }
+
+        int whenAndEarliestDiff = clampLongToIntRange(notificationWhen - notificationTime);
+        int earliestAndLockDiff = clampLongToIntRange(lockTime - notificationTime);
+        int earliestAndWifiDiff = clampLongToIntRange(wifiConnectionTime - notificationTime);
+        SysUiStatsLog.write(SysUiStatsLog.OTP_NOTIFICATION_DISPLAYED, shouldRedact,
+                whenAndEarliestDiff, locked, earliestAndLockDiff, wifiConnected,
+                earliestAndWifiDiff);
+        return shouldRedact;
+    }
+
+    private int clampLongToIntRange(long toConvert) {
+        return (int) Math.min(Integer.MAX_VALUE, Math.max(Integer.MIN_VALUE, toConvert));
+    }
+
+    // Get the earliest time the user might have seen this notification. This is either the
+    // notification's "when" time, or the notification entry creation time
+    private long getEarliestNotificationTime(NotificationEntry notif) {
+        long notifWhenWallClock = notif.getSbn().getNotification().getWhen();
+        long creationTimeDelta = SystemClock.elapsedRealtime() - notif.getCreationTime();
+        long creationTimeWallClock = System.currentTimeMillis() - creationTimeDelta;
+        return Math.min(notifWhenWallClock, creationTimeWallClock);
+    }
+
     private boolean packageHasVisibilityOverride(String key) {
         if (mCommonNotifCollectionLazy.get() == null) {
             Log.wtf(TAG, "mEntryManager was null!", new Throwable());
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
index 240953d..18f4b4a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationMediaManager.java
@@ -16,7 +16,6 @@
 package com.android.systemui.statusbar;
 
 import static com.android.systemui.Flags.mediaControlsUserInitiatedDeleteintent;
-import static com.android.systemui.Flags.notificationMediaManagerBackgroundExecution;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -116,12 +115,7 @@
             if (DEBUG_MEDIA) {
                 Log.v(TAG, "DEBUG_MEDIA: onMetadataChanged: " + metadata);
             }
-            if (notificationMediaManagerBackgroundExecution()) {
-                mBackgroundExecutor.execute(() -> setMediaMetadata(metadata));
-            } else {
-                setMediaMetadata(metadata);
-            }
-
+            mBackgroundExecutor.execute(() -> setMediaMetadata(metadata));
             dispatchUpdateMediaMetaData();
         }
     };
@@ -283,11 +277,7 @@
 
     public void addCallback(MediaListener callback) {
         mMediaListeners.add(callback);
-        if (notificationMediaManagerBackgroundExecution()) {
-            mBackgroundExecutor.execute(() -> updateMediaMetaData(callback));
-        } else {
-            updateMediaMetaData(callback);
-        }
+        mBackgroundExecutor.execute(() -> updateMediaMetaData(callback));
     }
 
     private void updateMediaMetaData(MediaListener callback) {
@@ -303,55 +293,13 @@
     public void findAndUpdateMediaNotifications() {
         // TODO(b/169655907): get the semi-filtered notifications for current user
         Collection<NotificationEntry> allNotifications = mNotifPipeline.getAllNotifs();
-        if (notificationMediaManagerBackgroundExecution()) {
-            // Create new sbn list to be accessed in background thread.
-            List<StatusBarNotification> statusBarNotifications = new ArrayList<>();
-            for (NotificationEntry entry: allNotifications) {
-                statusBarNotifications.add(entry.getSbn());
-            }
-            mBackgroundExecutor.execute(() -> findPlayingMediaNotification(statusBarNotifications));
-        } else {
-            findPlayingMediaNotification(allNotifications);
-        }
-        dispatchUpdateMediaMetaData();
-    }
-
-    /**
-     * Find a notification and media controller associated with the playing media session, and
-     * update this manager's internal state.
-     * TODO(b/273443374) check this method
-     */
-    void findPlayingMediaNotification(@NonNull Collection<NotificationEntry> allNotifications) {
-        // Promote the media notification with a controller in 'playing' state, if any.
-        NotificationEntry mediaNotification = null;
-        MediaController controller = null;
+        // Create new sbn list to be accessed in background thread.
+        List<StatusBarNotification> statusBarNotifications = new ArrayList<>();
         for (NotificationEntry entry : allNotifications) {
-            Notification notif = entry.getSbn().getNotification();
-            if (notif.isMediaNotification()) {
-                final MediaSession.Token token =
-                        entry.getSbn().getNotification().extras.getParcelable(
-                                Notification.EXTRA_MEDIA_SESSION, MediaSession.Token.class);
-                if (token != null) {
-                    MediaController aController = new MediaController(mContext, token);
-                    if (PlaybackState.STATE_PLAYING
-                            == getMediaControllerPlaybackState(aController)) {
-                        if (DEBUG_MEDIA) {
-                            Log.v(TAG, "DEBUG_MEDIA: found mediastyle controller matching "
-                                    + entry.getSbn().getKey());
-                        }
-                        mediaNotification = entry;
-                        controller = aController;
-                        break;
-                    }
-                }
-            }
+            statusBarNotifications.add(entry.getSbn());
         }
-
-        StatusBarNotification statusBarNotification = null;
-        if (mediaNotification != null) {
-            statusBarNotification = mediaNotification.getSbn();
-        }
-        setUpControllerAndKey(controller, statusBarNotification);
+        mBackgroundExecutor.execute(() -> findPlayingMediaNotification(statusBarNotifications));
+        dispatchUpdateMediaMetaData();
     }
 
     /**
@@ -415,11 +363,7 @@
     }
 
     public void clearCurrentMediaNotification() {
-        if (notificationMediaManagerBackgroundExecution()) {
-            mBackgroundExecutor.execute(this::clearMediaNotification);
-        } else {
-            clearMediaNotification();
-        }
+        mBackgroundExecutor.execute(this::clearMediaNotification);
     }
 
     private void clearMediaNotification() {
@@ -429,11 +373,7 @@
 
     private void dispatchUpdateMediaMetaData() {
         ArrayList<MediaListener> callbacks = new ArrayList<>(mMediaListeners);
-        if (notificationMediaManagerBackgroundExecution()) {
-            mBackgroundExecutor.execute(() -> updateMediaMetaData(callbacks));
-        } else {
-            updateMediaMetaData(callbacks);
-        }
+        mBackgroundExecutor.execute(() -> updateMediaMetaData(callbacks));
     }
 
     private void updateMediaMetaData(List<MediaListener> callbacks) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index 84266e8..bdfdb81 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -38,13 +38,13 @@
 import com.android.systemui.Flags.spatialModelAppPushback
 import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.dagger.SysUISingleton
-import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.shade.ShadeExpansionChangeEvent
 import com.android.systemui.shade.ShadeExpansionListener
+import com.android.systemui.shared.Flags.ambientAod
 import com.android.systemui.statusbar.phone.BiometricUnlockController
 import com.android.systemui.statusbar.phone.BiometricUnlockController.MODE_WAKE_AND_UNLOCK
 import com.android.systemui.statusbar.phone.DozeParameters
@@ -53,16 +53,15 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.statusbar.policy.SplitShadeStateController
 import com.android.systemui.util.WallpaperController
-import com.android.systemui.wallpapers.domain.interactor.WallpaperInteractor
 import com.android.systemui.window.domain.interactor.WindowRootViewBlurInteractor
 import com.android.wm.shell.appzoomout.AppZoomOut
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.launch
 import java.io.PrintWriter
 import java.util.Optional
 import javax.inject.Inject
 import kotlin.math.max
 import kotlin.math.sign
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.launch
 
 /**
  * Responsible for blurring the notification shade window, and applying a zoom effect to the
@@ -79,14 +78,12 @@
     private val keyguardInteractor: KeyguardInteractor,
     private val choreographer: Choreographer,
     private val wallpaperController: WallpaperController,
-    private val wallpaperInteractor: WallpaperInteractor,
     private val notificationShadeWindowController: NotificationShadeWindowController,
     private val dozeParameters: DozeParameters,
     @ShadeDisplayAware private val context: Context,
     private val splitShadeStateController: SplitShadeStateController,
     private val windowRootViewBlurInteractor: WindowRootViewBlurInteractor,
     private val appZoomOutOptional: Optional<AppZoomOut>,
-    @Application private val applicationScope: CoroutineScope,
     dumpManager: DumpManager,
     configurationController: ConfigurationController,
 ) : ShadeExpansionListener, Dumpable {
@@ -97,6 +94,7 @@
         private const val MIN_VELOCITY = -MAX_VELOCITY
         private const val INTERACTION_BLUR_FRACTION = 0.8f
         private const val ANIMATION_BLUR_FRACTION = 1f - INTERACTION_BLUR_FRACTION
+        private const val TRANSITION_THRESHOLD = 0.98f
         private const val TAG = "DepthController"
     }
 
@@ -115,8 +113,6 @@
     private var prevTimestamp: Long = -1
     private var prevShadeDirection = 0
     private var prevShadeVelocity = 0f
-    private var prevDozeAmount: Float = 0f
-    @VisibleForTesting var wallpaperSupportsAmbientMode: Boolean = false
     // tracks whether app launch transition is in progress. This involves two independent factors
     // that control blur, shade expansion and app launch animation from outside sysui.
     // They can complete out of order, this flag will be reset by the animation that finishes later.
@@ -163,6 +159,9 @@
     /**
      * When launching an app from the shade, the animations progress should affect how blurry the
      * shade is, overriding the expansion amount.
+     *
+     * TODO(b/399617511): remove this once [Flags.notificationShadeBlur] is launched and the Shade
+     *   closing is actually instantaneous.
      */
     var blursDisabledForAppLaunch: Boolean = false
         set(value) {
@@ -192,8 +191,12 @@
                 return
             }
 
-            shadeAnimation.animateTo(0)
-            shadeAnimation.finishIfRunning()
+            if (Flags.notificationShadeBlur()) {
+                shadeAnimation.skipTo(0)
+            } else {
+                shadeAnimation.animateTo(0)
+                shadeAnimation.finishIfRunning()
+            }
         }
         @Deprecated(
             message =
@@ -226,15 +229,7 @@
         }
 
     /** Blur radius of the wake-up animation on this frame. */
-    private var wakeBlurRadius = 0f
-        set(value) {
-            if (field == value) return
-            field = value
-            scheduleUpdate()
-        }
-
-    /** Blur radius of the unlock animation on this frame. */
-    private var unlockBlurRadius = 0f
+    private var wakeAndUnlockBlurRadius = 0f
         set(value) {
             if (field == value) return
             field = value
@@ -261,16 +256,14 @@
             ShadeInterpolation.getNotificationScrimAlpha(qsPanelExpansion) * shadeExpansion
         combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(qsExpandedRatio))
         combinedBlur = max(combinedBlur, blurUtils.blurRadiusOfRatio(transitionToFullShadeProgress))
-        var shadeRadius = max(combinedBlur, max(wakeBlurRadius, unlockBlurRadius))
+        var shadeRadius = max(combinedBlur, wakeAndUnlockBlurRadius)
 
         if (areBlursDisabledForAppLaunch || blursDisabledForUnlock) {
             shadeRadius = 0f
         }
 
         var blur = shadeRadius.toInt()
-        // If the blur comes from waking up, we don't want to zoom out the background
-        val zoomOut =
-            if (shadeRadius != wakeBlurRadius) blurRadiusToZoomOut(blurRadius = shadeRadius) else 0f
+        val zoomOut = blurRadiusToZoomOut(blurRadius = shadeRadius)
         // Make blur be 0 if it is necessary to stop blur effect.
         if (scrimsVisible) {
             if (!Flags.notificationShadeBlur()) {
@@ -355,14 +348,14 @@
                         startDelay = keyguardStateController.keyguardFadingAwayDelay
                         interpolator = Interpolators.FAST_OUT_SLOW_IN
                         addUpdateListener { animation: ValueAnimator ->
-                            unlockBlurRadius =
+                            wakeAndUnlockBlurRadius =
                                 blurUtils.blurRadiusOfRatio(animation.animatedValue as Float)
                         }
                         addListener(
                             object : AnimatorListenerAdapter() {
                                 override fun onAnimationEnd(animation: Animator) {
                                     keyguardAnimator = null
-                                    unlockBlurRadius = 0f
+                                    wakeAndUnlockBlurRadius = 0f
                                 }
                             }
                         )
@@ -398,20 +391,15 @@
             }
 
             override fun onDozeAmountChanged(linear: Float, eased: Float) {
-                prevDozeAmount = eased
-                updateWakeBlurRadius(prevDozeAmount)
+                wakeAndUnlockBlurRadius =
+                    if (ambientAod()) {
+                        0f
+                    } else {
+                        blurUtils.blurRadiusOfRatio(eased)
+                    }
             }
         }
 
-    private fun updateWakeBlurRadius(ratio: Float) {
-        wakeBlurRadius =
-            if (!wallpaperSupportsAmbientMode) {
-                0f
-            } else {
-                blurUtils.blurRadiusOfRatio(ratio)
-            }
-    }
-
     init {
         dumpManager.registerCriticalDumpable(javaClass.name, this)
         if (WAKE_UP_ANIMATION_ENABLED) {
@@ -433,12 +421,6 @@
                 }
             }
         )
-        applicationScope.launch {
-            wallpaperInteractor.wallpaperSupportsAmbientMode.collect { supported ->
-                wallpaperSupportsAmbientMode = supported
-                updateWakeBlurRadius(prevDozeAmount)
-            }
-        }
         initBlurListeners()
     }
 
@@ -515,6 +497,22 @@
         scheduleUpdate()
     }
 
+    fun onTransitionAnimationProgress(progress: Float) {
+        if (!Flags.notificationShadeBlur() || !Flags.moveTransitionAnimationLayer()) return
+        // Because the Shade takes a few frames to actually trigger the unblur after a transition
+        // has ended, we need to disable it manually, or the opening window itself will be blurred
+        // for a few frames due to relative ordering. We do this towards the end, so that the
+        // window is already covering the background and the unblur is not visible.
+        if (progress >= TRANSITION_THRESHOLD && shadeAnimation.radius > 0) {
+            blursDisabledForAppLaunch = true
+        }
+    }
+
+    fun onTransitionAnimationEnd() {
+        if (!Flags.notificationShadeBlur() || !Flags.moveTransitionAnimationLayer()) return
+        blursDisabledForAppLaunch = false
+    }
+
     private fun updateShadeAnimationBlur(
         expansion: Float,
         tracking: Boolean,
@@ -613,8 +611,7 @@
             it.println("shouldApplyShadeBlur: ${shouldApplyShadeBlur()}")
             it.println("shadeAnimation: ${shadeAnimation.radius}")
             it.println("brightnessMirrorRadius: ${brightnessMirrorSpring.radius}")
-            it.println("wakeBlur: $wakeBlurRadius")
-            it.println("unlockBlur: $wakeBlurRadius")
+            it.println("wakeAndUnlockBlur: $wakeAndUnlockBlurRadius")
             it.println("blursDisabledForAppLaunch: $blursDisabledForAppLaunch")
             it.println("appLaunchTransitionIsInProgress: $appLaunchTransitionIsInProgress")
             it.println("qsPanelExpansion: $qsPanelExpansion")
@@ -660,6 +657,20 @@
             springAnimation.addEndListener { _, _, _, _ -> pendingRadius = -1 }
         }
 
+        /**
+         * Starts an animation to [newRadius], or updates the current one if already ongoing.
+         * IMPORTANT: do NOT use this method + [finishIfRunning] to instantaneously change the value
+         * of the animation. The change will NOT be instantaneous. Use [skipTo] instead.
+         *
+         * Explanation:
+         * 1. If idle, [SpringAnimation.animateToFinalPosition] requests a start to the animation.
+         * 2. On the first frame after an idle animation is requested to start, the animation simply
+         *    acquires the starting value and does nothing else.
+         * 3. [SpringAnimation.skipToEnd] requests a fast-forward to the end value, but this happens
+         *    during calculation of the next animation value. Because on the first frame no such
+         *    calculation happens (point #2), there is one lagging frame where we still see the old
+         *    value.
+         */
         fun animateTo(newRadius: Int) {
             if (pendingRadius == newRadius) {
                 return
@@ -668,6 +679,19 @@
             springAnimation.animateToFinalPosition(newRadius.toFloat())
         }
 
+        /**
+         * Instantaneously set a new blur radius to this animation. Always use this instead of
+         * [animateTo] and [finishIfRunning] to make sure that the change takes effect in the next
+         * frame. See the doc for [animateTo] for an explanation.
+         */
+        fun skipTo(newRadius: Int) {
+            if (pendingRadius == newRadius) return
+            pendingRadius = newRadius
+            springAnimation.cancel()
+            springAnimation.setStartValue(newRadius.toFloat())
+            springAnimation.animateToFinalPosition(newRadius.toFloat())
+        }
+
         fun finishIfRunning() {
             if (springAnimation.isRunning) {
                 springAnimation.skipToEnd()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
index f466278..be3afad 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/call/ui/viewmodel/CallChipViewModel.kt
@@ -144,7 +144,7 @@
         } else {
             OngoingActivityChipModel.ClickBehavior.ExpandAction(
                 onClick = { expandable ->
-                    StatusBarChipsModernization.assertInNewMode()
+                    StatusBarChipsModernization.unsafeAssertInNewMode()
                     val animationController =
                         expandable.activityTransitionController(
                             Cuj.CUJ_STATUS_BAR_APP_LAUNCH_FROM_CALL_CHIP
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
index d8c3e25..a0de879 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/SingleNotificationChipInteractor.kt
@@ -56,7 +56,7 @@
     private val logger = Logger(logBuffer, "Notif".pad())
     // [StatusBarChipLogTag] recommends a max tag length of 20, so [extraLogTag] should NOT be the
     // top-level tag. It should instead be provided as the first string in each log message.
-    private val extraLogTag = "SingleChipInteractor[key=$key]"
+    private val extraLogTag = "SingleNotifChipInteractor[key=$key][id=${hashCode()}]"
 
     init {
         if (startingModel.promotedContent == null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
index edb4418..9380dfe 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/domain/interactor/StatusBarNotificationChipsInteractor.kt
@@ -38,6 +38,7 @@
 import kotlinx.coroutines.flow.MutableSharedFlow
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.SharedFlow
+import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.asSharedFlow
 import kotlinx.coroutines.flow.combine
 import kotlinx.coroutines.flow.distinctUntilChanged
@@ -45,6 +46,7 @@
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.onEach
+import kotlinx.coroutines.flow.stateIn
 
 /** An interactor for the notification chips shown in the status bar. */
 @SysUISingleton
@@ -73,7 +75,7 @@
         _promotedNotificationChipTapEvent.asSharedFlow()
 
     suspend fun onPromotedNotificationChipTapped(key: String) {
-        StatusBarNotifChips.assertInNewMode()
+        StatusBarNotifChips.unsafeAssertInNewMode()
         _promotedNotificationChipTapEvent.emit(key)
     }
 
@@ -147,28 +149,42 @@
      */
     val allNotificationChips: Flow<List<NotificationChipModel>> =
         if (StatusBarNotifChips.isEnabled) {
-            // For all our current interactors...
-            // TODO(b/364653005): When a promoted notification is added or removed, each individual
-            // interactor's [notificationChip] flow becomes un-collected then re-collected, which
-            // can cause some flows to remove then add callbacks when they don't need to. Is there a
-            // better structure for this? Maybe Channels or a StateFlow with a short timeout?
-            promotedNotificationInteractors.flatMapLatest { interactors ->
-                if (interactors.isNotEmpty()) {
-                    // Combine each interactor's [notificationChip] flow...
-                    val allNotificationChips: List<Flow<NotificationChipModel?>> =
-                        interactors.map { interactor -> interactor.notificationChip }
-                    combine(allNotificationChips) {
+                // For all our current interactors...
+                promotedNotificationInteractors.flatMapLatest { interactors ->
+                    if (interactors.isNotEmpty()) {
+                        // Combine each interactor's [notificationChip] flow...
+                        val allNotificationChips: List<Flow<NotificationChipModel?>> =
+                            interactors.map { interactor -> interactor.notificationChip }
+                        combine(allNotificationChips) {
                             // ... and emit just the non-null & sorted chips
                             it.filterNotNull().sortedWith(chipComparator)
                         }
-                        .logSort()
-                } else {
-                    flowOf(emptyList())
+                    } else {
+                        flowOf(emptyList())
+                    }
                 }
+            } else {
+                flowOf(emptyList())
             }
-        } else {
-            flowOf(emptyList())
-        }
+            .distinctUntilChanged()
+            .logSort()
+            .stateIn(
+                backgroundScope,
+                SharingStarted.WhileSubscribed(
+                    // When a promoted notification is added or removed, the `.flatMapLatest` above
+                    // will stop collection and then re-start collection on each individual
+                    // interactor's flow. (It will happen even for a chip that didn't change.) We
+                    // don't want the individual interactor flows to stop then re-start because they
+                    // may be maintaining values that would get thrown away when collection stops
+                    // (like an app's last visible time).
+                    // stopTimeoutMillis ensures we maintain those values even during the brief
+                    // moment (1-2ms) when `.flatMapLatest` causes collect to stop then immediately
+                    // restart.
+                    // Note: Channels could also work to solve this.
+                    stopTimeoutMillis = 1000
+                ),
+                initialValue = emptyList(),
+            )
 
     /** Emits the notifications that should actually be *shown* as chips in the status bar. */
     val shownNotificationChips: Flow<List<NotificationChipModel>> =
@@ -199,14 +215,14 @@
         }
 
     private fun Flow<List<NotificationChipModel>>.logSort(): Flow<List<NotificationChipModel>> {
-        return this.distinctUntilChanged().onEach { chips ->
+        return this.onEach { chips ->
             val logString =
                 chips.joinToString {
                     "{key=${it.key}. " +
                         "lastVisibleAppTime=${it.lastAppVisibleTime}. " +
                         "creationTime=${it.creationTime}}"
                 }
-            logger.d({ "Sorted chips: $str1" }) { str1 = logString }
+            logger.d({ "Sorted notif chips: $str1" }) { str1 = logString }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/shared/StatusBarNotifChips.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/shared/StatusBarNotifChips.kt
index 47ffbaf..6431f30 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/shared/StatusBarNotifChips.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/shared/StatusBarNotifChips.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
index 994357f..2fe6270 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/notification/ui/viewmodel/NotifChipsViewModel.kt
@@ -71,7 +71,7 @@
     private fun NotificationChipModel.toActivityChipModel(
         headsUpState: TopPinnedState
     ): OngoingActivityChipModel.Active {
-        StatusBarNotifChips.assertInNewMode()
+        StatusBarNotifChips.unsafeAssertInNewMode()
         val contentDescription = getContentDescription(this.appName)
         val icon =
             if (this.statusBarChipIconView != null) {
@@ -81,7 +81,7 @@
                     contentDescription,
                 )
             } else {
-                StatusBarConnectedDisplays.assertInNewMode()
+                StatusBarConnectedDisplays.unsafeAssertInNewMode()
                 OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon(
                     this.key,
                     contentDescription,
@@ -103,7 +103,7 @@
             }
         val clickBehavior =
             OngoingActivityChipModel.ClickBehavior.ShowHeadsUpNotification({
-                StatusBarChipsModernization.assertInNewMode()
+                StatusBarChipsModernization.unsafeAssertInNewMode()
                 clickListener.invoke()
             })
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
index 20dec11..02e4ba4 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/binder/OngoingActivityChipBinder.kt
@@ -202,7 +202,7 @@
                 )
             }
             is OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon -> {
-                StatusBarConnectedDisplays.assertInNewMode()
+                StatusBarConnectedDisplays.unsafeAssertInNewMode()
                 val iconView = fetchStatusBarIconView(iconViewStore, icon)
                 if (iconView == null) {
                     // This means that the notification key doesn't exist anymore.
@@ -223,7 +223,7 @@
         iconViewStore: IconViewStore?,
         icon: OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon,
     ): StatusBarIconView? {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
         if (iconViewStore == null) {
             throw IllegalStateException("Store should always be non-null when flag is enabled.")
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt
index 5242fea..ac55bf2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/ChipContent.kt
@@ -27,11 +27,13 @@
 import androidx.compose.ui.node.LayoutModifierNode
 import androidx.compose.ui.node.ModifierNodeElement
 import androidx.compose.ui.platform.LocalContext
+import androidx.compose.ui.platform.LocalDensity
 import androidx.compose.ui.res.dimensionResource
 import androidx.compose.ui.text.TextMeasurer
 import androidx.compose.ui.text.TextStyle
 import androidx.compose.ui.text.rememberTextMeasurer
 import androidx.compose.ui.unit.Constraints
+import androidx.compose.ui.unit.Density
 import androidx.compose.ui.unit.Dp
 import androidx.compose.ui.unit.constrain
 import androidx.compose.ui.unit.dp
@@ -45,6 +47,7 @@
 @Composable
 fun ChipContent(viewModel: OngoingActivityChipModel.Active, modifier: Modifier = Modifier) {
     val context = LocalContext.current
+    val density = LocalDensity.current
     val isTextOnly = viewModel.icon == null
     val hasEmbeddedIcon =
         viewModel.icon is OngoingActivityChipModel.ChipIcon.StatusBarView ||
@@ -86,7 +89,7 @@
                             startPadding = startPadding,
                             endPadding = endPadding,
                         )
-                        .neverDecreaseWidth(),
+                        .neverDecreaseWidth(density),
             )
         }
 
@@ -97,7 +100,7 @@
                 style = textStyle,
                 color = textColor,
                 softWrap = false,
-                modifier = modifier.neverDecreaseWidth(),
+                modifier = modifier.neverDecreaseWidth(density),
             )
         }
 
@@ -150,23 +153,31 @@
 }
 
 /** A modifier that ensures the width of the content only increases and never decreases. */
-private fun Modifier.neverDecreaseWidth(): Modifier {
-    return this.then(NeverDecreaseWidthElement)
+private fun Modifier.neverDecreaseWidth(density: Density): Modifier {
+    return this.then(NeverDecreaseWidthElement(density))
 }
 
-private data object NeverDecreaseWidthElement : ModifierNodeElement<NeverDecreaseWidthNode>() {
+private data class NeverDecreaseWidthElement(val density: Density) :
+    ModifierNodeElement<NeverDecreaseWidthNode>() {
     override fun create(): NeverDecreaseWidthNode {
         return NeverDecreaseWidthNode()
     }
 
     override fun update(node: NeverDecreaseWidthNode) {
-        error("This should never be called")
+        node.onDensityUpdated()
     }
 }
 
 private class NeverDecreaseWidthNode : Modifier.Node(), LayoutModifierNode {
     private var minWidth = 0
 
+    fun onDensityUpdated() {
+        // When the font or display size changes, we should re-determine what our minWidth is from
+        // scratch (e.g. if the font size decreased, we may be able to take *less* room).
+        // See b/395607413.
+        minWidth = 0
+    }
+
     override fun MeasureScope.measure(
         measurable: Measurable,
         constraints: Constraints,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt
index 95e454a..d67cb8f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChip.kt
@@ -75,7 +75,12 @@
             }
         }
         is OngoingActivityChipModel.ClickBehavior.ShowHeadsUpNotification -> {
-            ChipBody(model, iconViewStore, onClick = { clickBehavior.onClick() })
+            ChipBody(
+                model,
+                iconViewStore,
+                onClick = { clickBehavior.onClick() },
+                modifier = modifier,
+            )
         }
 
         is OngoingActivityChipModel.ClickBehavior.None -> {
@@ -195,7 +200,7 @@
             StatusBarIcon(colors, viewModel.impl.notification?.key, modifier) { viewModel.impl }
         }
         is OngoingActivityChipModel.ChipIcon.StatusBarNotificationIcon -> {
-            StatusBarConnectedDisplays.assertInNewMode()
+            StatusBarConnectedDisplays.unsafeAssertInNewMode()
             check(iconViewStore != null)
 
             StatusBarIcon(colors, viewModel.notificationKey, modifier) {
@@ -223,6 +228,7 @@
     iconFactory: () -> StatusBarIconView?,
 ) {
     val context = LocalContext.current
+    val colorTintList = ColorStateList.valueOf(colors.text(context))
 
     val iconSizePx =
         context.resources.getDimensionPixelSize(
@@ -233,9 +239,9 @@
         factory = { _ ->
             iconFactory.invoke()?.apply {
                 layoutParams = ViewGroup.LayoutParams(iconSizePx, iconSizePx)
-                imageTintList = ColorStateList.valueOf(colors.text(context))
             } ?: throw IllegalStateException("Missing StatusBarIconView for $notificationKey")
         },
+        update = { iconView -> iconView.imageTintList = colorTintList },
     )
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt
index 3b8c0f4..7080c34 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/compose/OngoingActivityChips.kt
@@ -25,6 +25,7 @@
 import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.res.dimensionResource
+import com.android.systemui.compose.modifiers.sysuiResTag
 import com.android.systemui.res.R
 import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
 import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder
@@ -47,7 +48,13 @@
         chips.active
             .filter { !it.isHidden }
             .forEach {
-                key(it.key) { OngoingActivityChip(model = it, iconViewStore = iconViewStore) }
+                key(it.key) {
+                    OngoingActivityChip(
+                        model = it,
+                        iconViewStore = iconViewStore,
+                        modifier = Modifier.sysuiResTag(it.key),
+                    )
+                }
             }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
index cf0342b..0cfc321 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/model/OngoingActivityChipModel.kt
@@ -148,7 +148,7 @@
                 shouldAnimate,
             ) {
             init {
-                StatusBarNotifChips.assertInNewMode()
+                StatusBarNotifChips.unsafeAssertInNewMode()
             }
 
             override val logName = "Active.ShortTimeDelta"
@@ -227,7 +227,7 @@
             val contentDescription: ContentDescription,
         ) : ChipIcon {
             init {
-                StatusBarConnectedDisplays.assertInNewMode()
+                StatusBarConnectedDisplays.unsafeAssertInNewMode()
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModel.kt
index a978c04..229d1a5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipViewModel.kt
@@ -71,7 +71,7 @@
             tag: String,
         ): (Expandable) -> Unit {
             return { expandable ->
-                StatusBarChipsModernization.assertInNewMode()
+                StatusBarChipsModernization.unsafeAssertInNewMode()
                 logger.log(tag, LogLevel.INFO, {}, { "Chip clicked" })
                 val dialog = dialogDelegate.createDialog()
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
index 1a30caf..eae2c25 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/chips/ui/viewmodel/OngoingActivityChipsViewModel.kt
@@ -350,6 +350,26 @@
                 .stateIn(scope, SharingStarted.Lazily, MultipleOngoingActivityChipsModelLegacy())
         }
 
+    private val activeChips =
+        if (StatusBarChipsModernization.isEnabled) {
+            chips.map { it.active }
+        } else {
+            chipsLegacy.map {
+                val list = mutableListOf<OngoingActivityChipModel.Active>()
+                if (it.primary is OngoingActivityChipModel.Active) {
+                    list.add(it.primary)
+                }
+                if (it.secondary is OngoingActivityChipModel.Active) {
+                    list.add(it.secondary)
+                }
+                list
+            }
+        }
+
+    /** A flow modeling just the keys for the currently visible chips. */
+    val visibleChipKeys: Flow<List<String>> =
+        activeChips.map { chips -> chips.filter { !it.isHidden }.map { it.key } }
+
     /**
      * Sort the given chip [bundle] in order of priority, and divide the chips between active,
      * overflow, and inactive (see [MultipleOngoingActivityChipsModel] for a description of each).
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt
index d25ca28..601d105 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/CommandQueueInitializer.kt
@@ -47,7 +47,7 @@
 ) : CoreStartable {
 
     override fun start() {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
         val resultPerDisplay: Map<String, RegisterStatusBarResult> =
             try {
                 barService.registerStatusBarForAllDisplays(commandQueue)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarOrchestratorStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarOrchestratorStore.kt
index 7069791..7964950 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarOrchestratorStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarOrchestratorStore.kt
@@ -16,25 +16,19 @@
 
 package com.android.systemui.statusbar.core
 
-import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.DisplayScopeRepository
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
+import com.android.systemui.statusbar.data.repository.StatusBarPerDisplayStoreImpl
 import com.android.systemui.statusbar.phone.AutoHideControllerStore
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import com.android.systemui.statusbar.window.data.repository.StatusBarWindowStateRepositoryStore
-import dagger.Lazy
-import dagger.Module
-import dagger.Provides
-import dagger.multibindings.ClassKey
-import dagger.multibindings.IntoMap
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 
-/** [PerDisplayStoreImpl] for providing display specific [StatusBarOrchestrator]. */
+/** [StatusBarPerDisplayStoreImpl] for providing display specific [StatusBarOrchestrator]. */
 @SysUISingleton
 class MultiDisplayStatusBarOrchestratorStore
 @Inject
@@ -48,10 +42,14 @@
     private val autoHideControllerStore: AutoHideControllerStore,
     private val displayScopeRepository: DisplayScopeRepository,
     private val statusBarWindowStateRepositoryStore: StatusBarWindowStateRepositoryStore,
-) : PerDisplayStoreImpl<StatusBarOrchestrator>(backgroundApplicationScope, displayRepository) {
+) :
+    StatusBarPerDisplayStoreImpl<StatusBarOrchestrator>(
+        backgroundApplicationScope,
+        displayRepository,
+    ) {
 
     init {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
     }
 
     override fun createInstanceForDisplay(displayId: Int): StatusBarOrchestrator? {
@@ -79,21 +77,3 @@
         instance.stop()
     }
 }
-
-@Module
-interface MultiDisplayStatusBarOrchestratorStoreModule {
-
-    @Provides
-    @SysUISingleton
-    @IntoMap
-    @ClassKey(MultiDisplayStatusBarOrchestratorStore::class)
-    fun storeAsCoreStartable(
-        multiDisplayLazy: Lazy<MultiDisplayStatusBarOrchestratorStore>
-    ): CoreStartable {
-        return if (StatusBarConnectedDisplays.isEnabled) {
-            multiDisplayLazy.get()
-        } else {
-            CoreStartable.NOP
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt
index dfb3763..30c4ca5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/MultiDisplayStatusBarStarter.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.core
 
 import android.view.Display
-import android.view.IWindowManager
 import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.systemui.CoreStartable
 import com.android.systemui.dagger.SysUISingleton
@@ -44,28 +43,21 @@
     private val statusBarInitializerStore: StatusBarInitializerStore,
     private val privacyDotWindowControllerStore: PrivacyDotWindowControllerStore,
     private val lightBarControllerStore: LightBarControllerStore,
-    private val windowManager: IWindowManager,
 ) : CoreStartable {
 
     init {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
     }
 
     override fun start() {
         applicationScope.launch {
-            displayRepository.displays
+            displayRepository.displayIdsWithSystemDecorations
                 .pairwiseBy { previousDisplays, currentDisplays ->
                     currentDisplays - previousDisplays
                 }
-                .onStart { emit(displayRepository.displays.value) }
+                .onStart { emit(displayRepository.displayIdsWithSystemDecorations.value) }
                 .collect { newDisplays ->
-                    newDisplays.forEach {
-                        // TODO(b/393191204): Split navbar, status bar, etc. functionality
-                        // from WindowManager#shouldShowSystemDecors.
-                        if (windowManager.shouldShowSystemDecors(it.displayId)) {
-                            createAndStartComponentsForDisplay(it.displayId)
-                        }
-                    }
+                    newDisplays.forEach { createAndStartComponentsForDisplay(it) }
                 }
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/NewStatusBarIcons.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/NewStatusBarIcons.kt
index 402881d..03316d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/NewStatusBarIcons.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/NewStatusBarIcons.kt
@@ -49,7 +49,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConnectedDisplays.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConnectedDisplays.kt
index 06474b0..a58e00c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConnectedDisplays.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarConnectedDisplays.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
index de6cd07..48955cc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarInitializerStore.kt
@@ -20,11 +20,11 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.PerDisplayStore
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.display.data.repository.SingleDisplayStore
 import com.android.systemui.statusbar.data.repository.DarkIconDispatcherStore
 import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore
 import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryStore
+import com.android.systemui.statusbar.data.repository.StatusBarPerDisplayStoreImpl
 import com.android.systemui.statusbar.window.StatusBarWindowControllerStore
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
@@ -45,10 +45,13 @@
     private val darkIconDispatcherStore: DarkIconDispatcherStore,
 ) :
     StatusBarInitializerStore,
-    PerDisplayStoreImpl<StatusBarInitializer>(backgroundApplicationScope, displayRepository) {
+    StatusBarPerDisplayStoreImpl<StatusBarInitializer>(
+        backgroundApplicationScope,
+        displayRepository,
+    ) {
 
     init {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
     }
 
     override fun createInstanceForDisplay(displayId: Int): StatusBarInitializer? {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt
index 73ada54..c4c25c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarOrchestrator.kt
@@ -146,7 +146,7 @@
 
     /** Starts status bar orchestration. To be called when status bar is created. */
     fun start() {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
         startJob =
             coroutineScope
                 // Perform animations on the main thread to prevent crashes.
@@ -280,7 +280,7 @@
      * Called when the [StatusBarOrchestrator] should stop doing any work and clean up if needed.
      */
     fun stop() {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
         dumpManager.unregisterDumpable(dumpableName)
         startJob?.cancel()
         startJob = null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt
index 3c30f3c..25dace3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/core/StatusBarRootModernization.kt
@@ -52,7 +52,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
index 27d8151..9db2f4b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/StatusBarDataLayerModule.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerModule
 import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStoreModule
 import com.android.systemui.statusbar.data.repository.StatusBarModeRepositoryModule
+import com.android.systemui.statusbar.data.repository.StatusBarPerDisplayConfigurationStateModule
 import com.android.systemui.statusbar.data.repository.SystemEventChipAnimationControllerStoreModule
 import com.android.systemui.statusbar.phone.data.StatusBarPhoneDataLayerModule
 import dagger.Module
@@ -34,6 +35,7 @@
             LightBarControllerStoreModule::class,
             RemoteInputRepositoryModule::class,
             StatusBarConfigurationControllerModule::class,
+            StatusBarPerDisplayConfigurationStateModule::class,
             StatusBarContentInsetsProviderStoreModule::class,
             StatusBarModeRepositoryModule::class,
             StatusBarPhoneDataLayerModule::class,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt
index 041f3c8..f353c01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/DarkIconDispatcherStore.kt
@@ -24,7 +24,6 @@
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
 import com.android.systemui.display.data.repository.PerDisplayStore
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.display.data.repository.SingleDisplayStore
 import com.android.systemui.plugins.DarkIconDispatcher
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
@@ -59,10 +58,13 @@
     private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
 ) :
     SysuiDarkIconDispatcherStore,
-    PerDisplayStoreImpl<SysuiDarkIconDispatcher>(backgroundApplicationScope, displayRepository) {
+    StatusBarPerDisplayStoreImpl<SysuiDarkIconDispatcher>(
+        backgroundApplicationScope,
+        displayRepository,
+    ) {
 
     init {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
     }
 
     override fun createInstanceForDisplay(displayId: Int): SysuiDarkIconDispatcher? {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
index c629d10..3c0d6c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/LightBarControllerStore.kt
@@ -22,7 +22,6 @@
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.DisplayScopeRepository
 import com.android.systemui.display.data.repository.PerDisplayStore
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.statusbar.phone.LightBarController
 import com.android.systemui.statusbar.phone.LightBarControllerImpl
 import dagger.Binds
@@ -47,7 +46,10 @@
     private val darkIconDispatcherStore: DarkIconDispatcherStore,
 ) :
     LightBarControllerStore,
-    PerDisplayStoreImpl<LightBarController>(backgroundApplicationScope, displayRepository) {
+    StatusBarPerDisplayStoreImpl<LightBarController>(
+        backgroundApplicationScope,
+        displayRepository,
+    ) {
 
     override fun createInstanceForDisplay(displayId: Int): LightBarController? {
         val darkIconDispatcher = darkIconDispatcherStore.forDisplay(displayId) ?: return null
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt
index d48c94b..32dc840 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotViewControllerStore.kt
@@ -22,7 +22,6 @@
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.DisplayScopeRepository
 import com.android.systemui.display.data.repository.PerDisplayStore
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.display.data.repository.SingleDisplayStore
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.events.PrivacyDotViewController
@@ -50,7 +49,10 @@
     private val contentInsetsProviderStore: StatusBarContentInsetsProviderStore,
 ) :
     PrivacyDotViewControllerStore,
-    PerDisplayStoreImpl<PrivacyDotViewController>(backgroundApplicationScope, displayRepository) {
+    StatusBarPerDisplayStoreImpl<PrivacyDotViewController>(
+        backgroundApplicationScope,
+        displayRepository,
+    ) {
 
     override fun createInstanceForDisplay(displayId: Int): PrivacyDotViewController? {
         val configurationController =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt
index 86c3c48..7fc5e8a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/PrivacyDotWindowControllerStore.kt
@@ -25,7 +25,6 @@
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
 import com.android.systemui.display.data.repository.PerDisplayStore
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.events.PrivacyDotWindowController
 import dagger.Binds
@@ -52,10 +51,13 @@
     private val viewCaptureAwareWindowManagerFactory: ViewCaptureAwareWindowManager.Factory,
 ) :
     PrivacyDotWindowControllerStore,
-    PerDisplayStoreImpl<PrivacyDotWindowController>(backgroundApplicationScope, displayRepository) {
+    StatusBarPerDisplayStoreImpl<PrivacyDotWindowController>(
+        backgroundApplicationScope,
+        displayRepository,
+    ) {
 
     init {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
     }
 
     override fun createInstanceForDisplay(displayId: Int): PrivacyDotWindowController? {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt
index 38cea83..36b11ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarConfigurationControllerStore.kt
@@ -24,7 +24,6 @@
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
 import com.android.systemui.display.data.repository.PerDisplayStore
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.display.data.repository.SingleDisplayStore
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.phone.ConfigurationControllerImpl
@@ -53,13 +52,13 @@
     private val configurationControllerFactory: ConfigurationControllerImpl.Factory,
 ) :
     StatusBarConfigurationControllerStore,
-    PerDisplayStoreImpl<StatusBarConfigurationController>(
+    StatusBarPerDisplayStoreImpl<StatusBarConfigurationController>(
         backgroundApplicationScope,
         displayRepository,
     ) {
 
     init {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
     }
 
     override fun createInstanceForDisplay(displayId: Int): StatusBarConfigurationController? {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt
index 5ea1211..3cd4b5c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarContentInsetsProviderStore.kt
@@ -25,7 +25,6 @@
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
 import com.android.systemui.display.data.repository.PerDisplayStore
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.display.data.repository.SingleDisplayStore
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.layout.StatusBarContentInsetsProvider
@@ -54,7 +53,7 @@
     private val cameraProtectionLoaderFactory: CameraProtectionLoaderImpl.Factory,
 ) :
     StatusBarContentInsetsProviderStore,
-    PerDisplayStoreImpl<StatusBarContentInsetsProvider>(
+    StatusBarPerDisplayStoreImpl<StatusBarContentInsetsProvider>(
         backgroundApplicationScope,
         displayRepository,
     ) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
index 143e998..5980c9c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarModeRepositoryStore.kt
@@ -22,7 +22,6 @@
 import com.android.systemui.dagger.qualifiers.DisplayId
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.PerDisplayStore
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.core.StatusBarInitializer
 import com.android.systemui.statusbar.phone.fragment.dagger.HomeStatusBarComponent
@@ -48,13 +47,13 @@
     displayRepository: DisplayRepository,
 ) :
     StatusBarModeRepositoryStore,
-    PerDisplayStoreImpl<StatusBarModePerDisplayRepository>(
+    StatusBarPerDisplayStoreImpl<StatusBarModePerDisplayRepository>(
         backgroundApplicationScope,
         displayRepository,
     ) {
 
     init {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
     }
 
     override fun createInstanceForDisplay(displayId: Int): StatusBarModePerDisplayRepository {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayConfigurationStateRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayConfigurationStateRepository.kt
new file mode 100644
index 0000000..3168a22
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayConfigurationStateRepository.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.data.repository
+
+import android.view.WindowManager.LayoutParams.TYPE_STATUS_BAR
+import com.android.systemui.common.ui.ConfigurationState
+import com.android.systemui.common.ui.ConfigurationStateImpl
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
+import com.android.systemui.display.data.repository.PerDisplayInstanceProvider
+import com.android.systemui.display.data.repository.PerDisplayInstanceRepositoryImpl
+import com.android.systemui.display.data.repository.PerDisplayRepository
+import com.android.systemui.display.data.repository.SingleInstanceRepositoryImpl
+import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import dagger.Lazy
+import dagger.Module
+import dagger.Provides
+import javax.inject.Inject
+
+@SysUISingleton
+class StatusBarPerDisplayConfigurationStateProvider
+@Inject
+constructor(
+    private val displayWindowPropertiesRepository: DisplayWindowPropertiesRepository,
+    private val statusBarConfigurationControllerStore: StatusBarConfigurationControllerStore,
+    private val factory: ConfigurationStateImpl.Factory,
+) : PerDisplayInstanceProvider<ConfigurationState> {
+
+    override fun createInstance(displayId: Int): ConfigurationState? {
+        val displayWindowProperties =
+            displayWindowPropertiesRepository.get(displayId, TYPE_STATUS_BAR) ?: return null
+        val configController =
+            statusBarConfigurationControllerStore.forDisplay(displayId) ?: return null
+        return factory.create(displayWindowProperties.context, configController)
+    }
+}
+
+@Module
+object StatusBarPerDisplayConfigurationStateModule {
+
+    @Provides
+    @SysUISingleton
+    fun store(
+        instanceProvider: Lazy<StatusBarPerDisplayConfigurationStateProvider>,
+        factory: PerDisplayInstanceRepositoryImpl.Factory<ConfigurationState>,
+        defaultInstance: ConfigurationState,
+    ): PerDisplayRepository<ConfigurationState> {
+        val name = "ConfigurationState"
+        return if (StatusBarConnectedDisplays.isEnabled) {
+            factory.create(name, instanceProvider.get())
+        } else {
+            SingleInstanceRepositoryImpl(name, defaultInstance)
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayStoreImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayStoreImpl.kt
new file mode 100644
index 0000000..e873c02
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayStoreImpl.kt
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.data.repository
+
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.data.repository.PerDisplayStoreImpl
+import com.android.systemui.util.kotlin.pairwiseBy
+import kotlinx.coroutines.CoroutineScope
+
+/** [PerDisplayStoreImpl] for Status Bar related classes. */
+abstract class StatusBarPerDisplayStoreImpl<T>(
+    @Background private val backgroundApplicationScope: CoroutineScope,
+    private val displayRepository: DisplayRepository,
+) : PerDisplayStoreImpl<T>(backgroundApplicationScope, displayRepository) {
+
+    override fun start() {
+        val instanceType = instanceClass.simpleName
+        backgroundApplicationScope.launch("StatusBarPerDisplayStore#<$instanceType>start") {
+            displayRepository.displayIdsWithSystemDecorations
+                .pairwiseBy { previousDisplays, currentDisplays ->
+                    previousDisplays - currentDisplays
+                }
+                .collect { removedDisplayIds ->
+                    removedDisplayIds.forEach { removedDisplayId ->
+                        val removedInstance = perDisplayInstances.remove(removedDisplayId)
+                        removedInstance?.let { onDisplayRemovalAction(it) }
+                    }
+                }
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt
index ffc1255..7b9ea69 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/data/repository/SystemEventChipAnimationControllerStore.kt
@@ -23,7 +23,6 @@
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
 import com.android.systemui.display.data.repository.PerDisplayStore
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.events.SystemEventChipAnimationController
 import com.android.systemui.statusbar.events.SystemEventChipAnimationControllerImpl
@@ -53,13 +52,13 @@
     private val statusBarContentInsetsProviderStore: StatusBarContentInsetsProviderStore,
 ) :
     SystemEventChipAnimationControllerStore,
-    PerDisplayStoreImpl<SystemEventChipAnimationController>(
+    StatusBarPerDisplayStoreImpl<SystemEventChipAnimationController>(
         backgroundApplicationScope,
         displayRepository,
     ) {
 
     init {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
     }
 
     override fun createInstanceForDisplay(displayId: Int): SystemEventChipAnimationController? {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/MultiDisplaySystemEventChipAnimationController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/MultiDisplaySystemEventChipAnimationController.kt
index 4b9721e..b881c92 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/MultiDisplaySystemEventChipAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/MultiDisplaySystemEventChipAnimationController.kt
@@ -37,7 +37,7 @@
 ) : SystemEventChipAnimationController {
 
     init {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
     }
 
     override fun prepareChipAnimation(viewCreator: ViewCreator) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
index 63410d746..3200ca1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/PrivacyDotViewController.kt
@@ -190,7 +190,7 @@
     }
 
     override fun stop() {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
         contentInsetsProvider.removeCallback(insetsChangedListener)
         configurationController.removeCallback(configurationListener)
         stateController.removeCallback(statusBarStateListener)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/events/ui/view/BatteryStatusEventComposeChip.kt b/packages/SystemUI/src/com/android/systemui/statusbar/events/ui/view/BatteryStatusEventComposeChip.kt
index a90e3ff..05d3256 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/events/ui/view/BatteryStatusEventComposeChip.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/events/ui/view/BatteryStatusEventComposeChip.kt
@@ -54,7 +54,7 @@
         get() = composeInner
 
     init {
-        NewStatusBarIcons.assertInNewMode()
+        NewStatusBarIcons.unsafeAssertInNewMode()
 
         inflate(context, R.layout.status_bar_event_chip_compose, this)
         roundedContainer = requireViewById(R.id.rounded_container)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt
index 90f97df..ec65087 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModel.kt
@@ -17,51 +17,51 @@
 package com.android.systemui.statusbar.featurepods.media.ui.viewmodel
 
 import android.content.Context
+import androidx.compose.runtime.getValue
 import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
-import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.lifecycle.ExclusiveActivatable
+import com.android.systemui.lifecycle.Hydrator
 import com.android.systemui.statusbar.featurepods.media.domain.interactor.MediaControlChipInteractor
 import com.android.systemui.statusbar.featurepods.media.shared.model.MediaControlChipModel
 import com.android.systemui.statusbar.featurepods.popups.shared.model.HoverBehavior
 import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
 import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel
 import com.android.systemui.statusbar.featurepods.popups.ui.viewmodel.StatusBarPopupChipViewModel
-import javax.inject.Inject
-import kotlinx.coroutines.CoroutineScope
-import kotlinx.coroutines.flow.SharingStarted
-import kotlinx.coroutines.flow.StateFlow
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
 import kotlinx.coroutines.flow.map
-import kotlinx.coroutines.flow.stateIn
-import kotlinx.coroutines.launch
 
 /**
  * [StatusBarPopupChipViewModel] for a media control chip in the status bar. This view model is
  * responsible for converting the [MediaControlChipModel] to a [PopupChipModel] that can be used to
  * display a media control chip.
  */
-@SysUISingleton
 class MediaControlChipViewModel
-@Inject
+@AssistedInject
 constructor(
-    @Background private val backgroundScope: CoroutineScope,
     @Application private val applicationContext: Context,
     mediaControlChipInteractor: MediaControlChipInteractor,
-) : StatusBarPopupChipViewModel {
-
+) : StatusBarPopupChipViewModel, ExclusiveActivatable() {
+    private val hydrator: Hydrator = Hydrator("MediaControlChipViewModel.hydrator")
     /**
-     * A [StateFlow] of the current [PopupChipModel]. This flow emits a new [PopupChipModel]
+     * A snapshot [State] of the current [PopupChipModel]. This emits a new [PopupChipModel]
      * whenever the underlying [MediaControlChipModel] changes.
      */
-    override val chip: StateFlow<PopupChipModel> =
-        mediaControlChipInteractor.mediaControlChipModel
-            .map { mediaControlChipModel -> toPopupChipModel(mediaControlChipModel) }
-            .stateIn(
-                backgroundScope,
-                SharingStarted.WhileSubscribed(),
-                PopupChipModel.Hidden(PopupChipId.MediaControl),
-            )
+    override val chip: PopupChipModel by
+        hydrator.hydratedStateOf(
+            traceName = "chip",
+            initialValue = PopupChipModel.Hidden(PopupChipId.MediaControl),
+            source =
+                mediaControlChipInteractor.mediaControlChipModel.map { model ->
+                    toPopupChipModel(model)
+                },
+        )
+
+    override suspend fun onActivated(): Nothing {
+        hydrator.activate()
+    }
 
     private fun toPopupChipModel(model: MediaControlChipModel?): PopupChipModel {
         if (model == null || model.songName.isNullOrEmpty()) {
@@ -96,7 +96,12 @@
 
         return HoverBehavior.Button(
             icon = Icon.Loaded(drawable = icon, contentDescription = contentDescription),
-            onIconPressed = { backgroundScope.launch { action.run() } },
+            onIconPressed = { action.run() },
         )
     }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(): MediaControlChipViewModel
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/StatusBarPopupChips.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/StatusBarPopupChips.kt
index a9f72ff2..d1307aa 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/StatusBarPopupChips.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/StatusBarPopupChips.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipViewModel.kt
index 5712be3..38f2413 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipViewModel.kt
@@ -16,14 +16,14 @@
 
 package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel
 
+import com.android.systemui.lifecycle.Activatable
 import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipModel
-import kotlinx.coroutines.flow.StateFlow
 
 /**
  * Interface for a view model that knows the display requirements for a single type of status bar
  * popup chip.
  */
-interface StatusBarPopupChipViewModel {
-    /** A flow modeling the popup chip that should be shown (or not shown). */
-    val chip: StateFlow<PopupChipModel>
+interface StatusBarPopupChipViewModel : Activatable {
+    /** A snapshot [State] modeling the popup chip that should be shown (or not shown). */
+    val chip: PopupChipModel
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt
index 33bf90d..35f1a99 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModel.kt
@@ -21,7 +21,6 @@
 import androidx.compose.runtime.mutableStateOf
 import androidx.compose.runtime.setValue
 import com.android.systemui.lifecycle.ExclusiveActivatable
-import com.android.systemui.lifecycle.Hydrator
 import com.android.systemui.statusbar.featurepods.media.ui.viewmodel.MediaControlChipViewModel
 import com.android.systemui.statusbar.featurepods.popups.StatusBarPopupChips
 import com.android.systemui.statusbar.featurepods.popups.shared.model.PopupChipId
@@ -36,18 +35,17 @@
  */
 class StatusBarPopupChipsViewModel
 @AssistedInject
-constructor(mediaControlChip: MediaControlChipViewModel) : ExclusiveActivatable() {
-    private val hydrator: Hydrator = Hydrator("StatusBarPopupChipsViewModel.hydrator")
+constructor(mediaControlChipFactory: MediaControlChipViewModel.Factory) : ExclusiveActivatable() {
+
+    private val mediaControlChip by lazy { mediaControlChipFactory.create() }
 
     /** The ID of the current chip that is showing its popup, or `null` if no chip is shown. */
     private var currentShownPopupChipId by mutableStateOf<PopupChipId?>(null)
 
-    private val incomingPopupChipBundle: PopupChipBundle by
-        hydrator.hydratedStateOf(
-            traceName = "incomingPopupChipBundle",
-            initialValue = PopupChipBundle(),
-            source = mediaControlChip.chip.map { chip -> PopupChipBundle(media = chip) },
-        )
+    private val incomingPopupChipBundle: PopupChipBundle by derivedStateOf {
+        val mediaChip = mediaControlChip.chip
+        PopupChipBundle(media = mediaChip)
+    }
 
     val shownPopupChips: List<PopupChipModel.Shown> by derivedStateOf {
         if (StatusBarPopupChips.isEnabled) {
@@ -66,7 +64,7 @@
     }
 
     override suspend fun onActivated(): Nothing {
-        hydrator.activate()
+        mediaControlChip.activate()
     }
 
     private data class PopupChipBundle(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/headsup/shared/StatusBarNoHunBehavior.kt b/packages/SystemUI/src/com/android/systemui/statusbar/headsup/shared/StatusBarNoHunBehavior.kt
index c9024d9..7b1024c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/headsup/shared/StatusBarNoHunBehavior.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/headsup/shared/StatusBarNoHunBehavior.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/layout/StatusBarContentInsetsProvider.kt b/packages/SystemUI/src/com/android/systemui/statusbar/layout/StatusBarContentInsetsProvider.kt
index 9d5d87f..e588dd3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/layout/StatusBarContentInsetsProvider.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/layout/StatusBarContentInsetsProvider.kt
@@ -201,7 +201,7 @@
     }
 
     override fun stop() {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
         configurationController.removeCallback(this)
         dumpManager.unregisterDumpable(dumpableName)
         commandRegistry.unregisterCommand(commandName)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/layout/ui/viewmodel/StatusBarContentInsetsViewModelStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/layout/ui/viewmodel/StatusBarContentInsetsViewModelStore.kt
index d2dccc4..d7e9bb2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/layout/ui/viewmodel/StatusBarContentInsetsViewModelStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/layout/ui/viewmodel/StatusBarContentInsetsViewModelStore.kt
@@ -21,10 +21,10 @@
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.PerDisplayStore
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.display.data.repository.SingleDisplayStore
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore
+import com.android.systemui.statusbar.data.repository.StatusBarPerDisplayStoreImpl
 import dagger.Lazy
 import dagger.Module
 import dagger.Provides
@@ -45,7 +45,7 @@
     private val statusBarContentInsetsProviderStore: StatusBarContentInsetsProviderStore,
 ) :
     StatusBarContentInsetsViewModelStore,
-    PerDisplayStoreImpl<StatusBarContentInsetsViewModel>(
+    StatusBarPerDisplayStoreImpl<StatusBarContentInsetsViewModel>(
         backgroundApplicationScope,
         displayRepository,
     ) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
index 4053d06..8be9e41 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationClicker.java
@@ -124,8 +124,14 @@
         Notification notification = sbn.getNotification();
         if (notification.contentIntent != null || notification.fullScreenIntent != null
                 || row.getEntry().isBubble()) {
-            row.setBubbleClickListener(v ->
-                    mNotificationActivityStarter.onNotificationBubbleIconClicked(row.getEntry()));
+            if (NotificationBundleUi.isEnabled()) {
+                row.setBubbleClickListener(
+                        v -> row.getEntryAdapter().onNotificationBubbleIconClicked());
+            } else {
+                row.setBubbleClickListener(v ->
+                        mNotificationActivityStarter.onNotificationBubbleIconClicked(
+                                row.getEntry()));
+            }
             row.setOnClickListener(this);
             row.setOnDragSuccessListener(mOnDragSuccessListener);
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt
index 0a24d7a..68c13af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/PhysicsPropertyAnimator.kt
@@ -88,8 +88,8 @@
         @JvmStatic
         fun createDefaultSpring(): SpringForce {
             return SpringForce()
-                .setStiffness(380f) // MEDIUM LOW STIFFNESS
-                .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) // LOW BOUNCINESS
+                .setStiffness(380f)
+                .setDampingRatio(0.68f);
         }
 
         @JvmStatic
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
index 6dd44a1..41353b9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntry.java
@@ -45,8 +45,6 @@
  */
 public class BundleEntry extends PipelineEntry {
 
-    private final BundleEntryAdapter mEntryAdapter;
-
     // TODO(b/394483200): move NotificationEntry's implementation to PipelineEntry?
     private final MutableStateFlow<Boolean> mSensitive = StateFlowKt.MutableStateFlow(false);
 
@@ -55,7 +53,6 @@
 
     public BundleEntry(String key) {
         super(key);
-        mEntryAdapter = new BundleEntryAdapter();
     }
 
     @Nullable
@@ -86,126 +83,9 @@
         return false;
     }
 
-    @VisibleForTesting
-    public BundleEntryAdapter getEntryAdapter() {
-        return mEntryAdapter;
-    }
-
-    public class BundleEntryAdapter implements EntryAdapter {
-
-        /**
-         * TODO (b/394483200): convert to PipelineEntry.ROOT_ENTRY when pipeline is migrated?
-         */
-        @Override
-        public GroupEntry getParent() {
-            return GroupEntry.ROOT_ENTRY;
-        }
-
-        @Override
-        public boolean isTopLevelEntry() {
-            return true;
-        }
-
-        @NonNull
-        @Override
-        public String getKey() {
-            return mKey;
-        }
-
-        @Override
-        @Nullable
-        public ExpandableNotificationRow getRow() {
-            return mRow;
-        }
-
-        @Override
-        public boolean isGroupRoot() {
-            return true;
-        }
-
-        @Override
-        public StateFlow<Boolean> isSensitive() {
-            return BundleEntry.this.mSensitive;
-        }
-
-        @Override
-        public boolean isClearable() {
-            // TODO(b/394483200): check whether all of the children are clearable, when implemented
-            return true;
-        }
-
-        @Override
-        public int getTargetSdk() {
-            return Build.VERSION_CODES.CUR_DEVELOPMENT;
-        }
-
-        @Override
-        public String getSummarization() {
-            return null;
-        }
-
-        @Override
-        public int getContrastedColor(Context context, boolean isLowPriority, int backgroundColor) {
-            return Notification.COLOR_DEFAULT;
-        }
-
-        @Override
-        public boolean canPeek() {
-            return false;
-        }
-
-        @Override
-        public long getWhen() {
-            return 0;
-        }
-
-        @Override
-        public IconPack getIcons() {
-            // TODO(b/396446620): implement bundle icons
-            return null;
-        }
-
-        @Override
-        public boolean isColorized() {
-            return false;
-        }
-
-        @Override
-        @Nullable
-        public StatusBarNotification getSbn() {
-            return null;
-        }
-
-        @Override
-        public boolean canDragAndDrop() {
-            return false;
-        }
-
-        @Override
-        public boolean isBubbleCapable() {
-            return false;
-        }
-
-        @Override
-        @Nullable
-        public String getStyle() {
-            return null;
-        }
-
-        @Override
-        public int getSectionBucket() {
-            return mBucket;
-        }
-
-        @Override
-        public boolean isAmbient() {
-            return false;
-        }
-
-        @Override
-        public boolean isFullScreenCapable() {
-            return false;
-        }
+    @Nullable
+    public ExpandableNotificationRow getRow() {
+        return mRow;
     }
 
     public static final List<BundleEntry> ROOT_BUNDLES = List.of(
@@ -213,4 +93,8 @@
             new BundleEntry(SOCIAL_MEDIA_ID),
             new BundleEntry(NEWS_ID),
             new BundleEntry(RECS_ID));
+
+    public MutableStateFlow<Boolean> isSensitive() {
+        return mSensitive;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt
new file mode 100644
index 0000000..64db9df
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/BundleEntryAdapter.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.collection
+
+import android.app.Notification
+import android.content.Context
+import android.os.Build
+import android.service.notification.StatusBarNotification
+import com.android.systemui.statusbar.notification.icon.IconPack
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import kotlinx.coroutines.flow.StateFlow
+
+class BundleEntryAdapter(val entry: BundleEntry) : EntryAdapter {
+    /** TODO (b/394483200): convert to PipelineEntry.ROOT_ENTRY when pipeline is migrated? */
+    override fun getParent(): GroupEntry {
+        return GroupEntry.ROOT_ENTRY
+    }
+
+    override fun isTopLevelEntry(): Boolean {
+        return true
+    }
+
+    override fun getKey(): String {
+        return entry.key
+    }
+
+    override fun getRow(): ExpandableNotificationRow? {
+        return entry.row
+    }
+
+    override fun isGroupRoot(): Boolean {
+        return true
+    }
+
+    override fun isSensitive(): StateFlow<Boolean> {
+        return entry.isSensitive
+    }
+
+    override fun isClearable(): Boolean {
+        // TODO(b/394483200): check whether all of the children are clearable, when implemented
+        return true
+    }
+
+    override fun getTargetSdk(): Int {
+        return Build.VERSION_CODES.CUR_DEVELOPMENT
+    }
+
+    override fun getSummarization(): String? {
+        return null
+    }
+
+    override fun getContrastedColor(
+        context: Context?,
+        isLowPriority: Boolean,
+        backgroundColor: Int,
+    ): Int {
+        return Notification.COLOR_DEFAULT
+    }
+
+    override fun canPeek(): Boolean {
+        return false
+    }
+
+    override fun getWhen(): Long {
+        return 0
+    }
+
+    override fun getIcons(): IconPack? {
+        // TODO(b/396446620): implement bundle icons
+        return null
+    }
+
+    override fun isColorized(): Boolean {
+        return false
+    }
+
+    override fun getSbn(): StatusBarNotification? {
+        return null
+    }
+
+    override fun canDragAndDrop(): Boolean {
+        return false
+    }
+
+    override fun isBubbleCapable(): Boolean {
+        return false
+    }
+
+    override fun getStyle(): String? {
+        return null
+    }
+
+    override fun getSectionBucket(): Int {
+        return entry.bucket
+    }
+
+    override fun isAmbient(): Boolean {
+        return false
+    }
+
+    override fun isFullScreenCapable(): Boolean {
+        return false
+    }
+
+    override fun onNotificationBubbleIconClicked() {
+        // do nothing. these cannot be a bubble
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
index 307a957..0e75b60 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapter.java
@@ -50,7 +50,7 @@
     /**
      * Gets the view that this entry is backing.
      */
-    @NonNull
+    @Nullable
     ExpandableNotificationRow getRow();
 
     /**
@@ -135,5 +135,10 @@
     default boolean isFullScreenCapable() {
         return false;
     }
+
+    /**
+     * Process a click on a notification bubble icon
+     */
+    void onNotificationBubbleIconClicked();
 }
 
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactory.kt
similarity index 67%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactory.kt
index 9b7cd70..b7a84dd 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactory.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,8 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.statusbar.notification.collection
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+/** Creates an appropriate EntryAdapter for the entry type given */
+interface EntryAdapterFactory {
+    fun create(entry: PipelineEntry): EntryAdapter
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt
new file mode 100644
index 0000000..779c25a
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/EntryAdapterFactoryImpl.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.collection
+
+import androidx.annotation.VisibleForTesting
+import com.android.internal.logging.MetricsLogger
+import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
+import javax.inject.Inject
+
+/** Creates an appropriate EntryAdapter for the entry type given */
+class EntryAdapterFactoryImpl
+@Inject
+constructor(
+    private val notificationActivityStarter: NotificationActivityStarter,
+    private val metricsLogger: MetricsLogger,
+    private val peopleNotificationIdentifier: PeopleNotificationIdentifier,
+    private val iconStyleProvider: NotificationIconStyleProvider,
+    private val visualStabilityCoordinator: VisualStabilityCoordinator,
+) : EntryAdapterFactory {
+    override fun create(entry: PipelineEntry): EntryAdapter {
+        return if (entry is NotificationEntry) {
+            NotificationEntryAdapter(
+                notificationActivityStarter,
+                metricsLogger,
+                peopleNotificationIdentifier,
+                iconStyleProvider,
+                visualStabilityCoordinator,
+                entry,
+            )
+        } else {
+            BundleEntryAdapter((entry as BundleEntry))
+        }
+    }
+
+    @VisibleForTesting
+    fun getNotificationActivityStarter() : NotificationActivityStarter {
+        return notificationActivityStarter
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
index b19ba3a..3d8ba7f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntry.java
@@ -109,7 +109,6 @@
     private final String mKey;
     private StatusBarNotification mSbn;
     private Ranking mRanking;
-    private final NotifEntryAdapter mEntryAdapter;
 
     /*
      * Bookkeeping members
@@ -270,141 +269,6 @@
         mKey = sbn.getKey();
         setSbn(sbn);
         setRanking(ranking);
-        mEntryAdapter = new NotifEntryAdapter();
-    }
-
-    public class NotifEntryAdapter implements EntryAdapter {
-        @Override
-        public PipelineEntry getParent() {
-            return NotificationEntry.this.getParent();
-        }
-
-        @Override
-        public boolean isTopLevelEntry() {
-            return getParent() != null
-                    && (getParent() == ROOT_ENTRY || ROOT_BUNDLES.contains(getParent()));
-        }
-
-        @Override
-        public String getKey() {
-            return NotificationEntry.this.getKey();
-        }
-
-        @Override
-        public ExpandableNotificationRow getRow() {
-            return NotificationEntry.this.getRow();
-        }
-
-        @Override
-        public boolean isGroupRoot() {
-            if (isTopLevelEntry() || getParent() == null) {
-                return false;
-            }
-            if (NotificationEntry.this.getParent() instanceof GroupEntry parentGroupEntry) {
-                return parentGroupEntry.getSummary() == NotificationEntry.this;
-            }
-            return false;
-        }
-
-        @Override
-        public StateFlow<Boolean> isSensitive() {
-            return NotificationEntry.this.isSensitive();
-        }
-
-        @Override
-        public boolean isClearable() {
-            return NotificationEntry.this.isClearable();
-        }
-
-        @Override
-        public int getTargetSdk() {
-            return NotificationEntry.this.targetSdk;
-        }
-
-        @Override
-        public String getSummarization() {
-            return getRanking().getSummarization();
-        }
-
-        @Override
-        public void prepareForInflation() {
-            getSbn().clearPackageContext();
-        }
-
-        @Override
-        public int getContrastedColor(Context context, boolean isLowPriority, int backgroundColor) {
-            return NotificationEntry.this.getContrastedColor(
-                    context, isLowPriority, backgroundColor);
-        }
-
-        @Override
-        public boolean canPeek() {
-            return isStickyAndNotDemoted();
-        }
-
-        @Override
-        public long getWhen() {
-            return getSbn().getNotification().getWhen();
-        }
-
-        @Override
-        public IconPack getIcons() {
-            return NotificationEntry.this.getIcons();
-        }
-
-        @Override
-        public boolean isColorized() {
-            return getSbn().getNotification().isColorized();
-        }
-
-        @Override
-        @Nullable
-        public StatusBarNotification getSbn() {
-            return NotificationEntry.this.getSbn();
-        }
-
-        @Override
-        public boolean canDragAndDrop() {
-            boolean canBubble = canBubble();
-            Notification notif = getSbn().getNotification();
-            PendingIntent dragIntent = notif.contentIntent != null ? notif.contentIntent
-                    : notif.fullScreenIntent;
-            if (dragIntent != null && dragIntent.isActivity() && !canBubble) {
-                return true;
-            }
-            return false;
-        }
-
-        @Override
-        public boolean isBubbleCapable() {
-            return NotificationEntry.this.isBubble();
-        }
-
-        @Override
-        @Nullable
-        public String getStyle() {
-            return getNotificationStyle();
-        }
-
-        @Override
-        public int getSectionBucket() {
-            return mBucket;
-        }
-
-        @Override
-        public boolean isAmbient() {
-            return mRanking.isAmbient();
-        }
-
-        @Override
-        public boolean isFullScreenCapable() {
-            return getSbn().getNotification().fullScreenIntent != null;
-        }
-
-    }
-
-    public EntryAdapter getEntryAdapter() {
-        return mEntryAdapter;
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt
new file mode 100644
index 0000000..0ff2dd7
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/NotificationEntryAdapter.kt
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.collection
+
+import android.content.Context
+import android.service.notification.StatusBarNotification
+import com.android.internal.logging.MetricsLogger
+import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
+import com.android.systemui.statusbar.notification.icon.IconPack
+import com.android.systemui.statusbar.notification.people.PeopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
+import kotlinx.coroutines.flow.StateFlow
+
+class NotificationEntryAdapter(
+    private val notificationActivityStarter: NotificationActivityStarter,
+    private val metricsLogger: MetricsLogger,
+    private val peopleNotificationIdentifier: PeopleNotificationIdentifier,
+    private val iconStyleProvider: NotificationIconStyleProvider,
+    private val visualStabilityCoordinator: VisualStabilityCoordinator,
+    private val entry: NotificationEntry,
+) : EntryAdapter {
+
+    override fun getParent(): PipelineEntry? {
+        return entry.parent
+    }
+
+    override fun isTopLevelEntry(): Boolean {
+        return parent != null &&
+            (parent === GroupEntry.ROOT_ENTRY || BundleEntry.ROOT_BUNDLES.contains(parent))
+    }
+
+    override fun getKey(): String {
+        return entry.key
+    }
+
+    override fun getRow(): ExpandableNotificationRow {
+        return entry.row
+    }
+
+    override fun isGroupRoot(): Boolean {
+        if (isTopLevelEntry || parent == null) {
+            return false
+        }
+        return (entry.parent as? GroupEntry)?.summary == entry
+    }
+
+    override fun isSensitive(): StateFlow<Boolean> {
+        return entry.isSensitive
+    }
+
+    override fun isClearable(): Boolean {
+        return entry.isClearable
+    }
+
+    override fun getTargetSdk(): Int {
+        return entry.targetSdk
+    }
+
+    override fun getSummarization(): String? {
+        return entry.ranking?.summarization
+    }
+
+    override fun prepareForInflation() {
+        entry.sbn.clearPackageContext()
+    }
+
+    override fun getContrastedColor(
+        context: Context?,
+        isLowPriority: Boolean,
+        backgroundColor: Int,
+    ): Int {
+        return entry.getContrastedColor(context, isLowPriority, backgroundColor)
+    }
+
+    override fun canPeek(): Boolean {
+        return entry.isStickyAndNotDemoted
+    }
+
+    override fun getWhen(): Long {
+        return entry.sbn.notification.getWhen()
+    }
+
+    override fun getIcons(): IconPack {
+        return entry.icons
+    }
+
+    override fun isColorized(): Boolean {
+        return entry.sbn.notification.isColorized
+    }
+
+    override fun getSbn(): StatusBarNotification {
+        return entry.sbn
+    }
+
+    override fun canDragAndDrop(): Boolean {
+        val canBubble: Boolean = entry.canBubble()
+        val notif = entry.sbn.notification
+        val dragIntent =
+            if (notif.contentIntent != null) notif.contentIntent else notif.fullScreenIntent
+        if (dragIntent != null && dragIntent.isActivity && !canBubble) {
+            return true
+        }
+        return false
+    }
+
+    override fun isBubbleCapable(): Boolean {
+        return entry.isBubble
+    }
+
+    override fun getStyle(): String? {
+        return entry.notificationStyle
+    }
+
+    override fun getSectionBucket(): Int {
+        return entry.bucket
+    }
+
+    override fun isAmbient(): Boolean {
+        return entry.ranking.isAmbient
+    }
+
+    override fun isFullScreenCapable(): Boolean {
+        return entry.sbn.notification.fullScreenIntent != null
+    }
+
+    override fun onNotificationBubbleIconClicked() {
+        notificationActivityStarter.onNotificationBubbleIconClicked(entry)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
index 611e0ef..fdb8cd8 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/HeadsUpCoordinator.kt
@@ -27,10 +27,10 @@
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.notification.NotifPipelineFlags
 import com.android.systemui.statusbar.notification.collection.GroupEntry
-import com.android.systemui.statusbar.notification.collection.PipelineEntry
 import com.android.systemui.statusbar.notification.collection.NotifCollection
 import com.android.systemui.statusbar.notification.collection.NotifPipeline
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
+import com.android.systemui.statusbar.notification.collection.PipelineEntry
 import com.android.systemui.statusbar.notification.collection.coordinator.dagger.CoordinatorScope
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifComparator
 import com.android.systemui.statusbar.notification.collection.listbuilder.pluggable.NotifPromoter
@@ -125,7 +125,7 @@
      * Must be run on the main thread.
      */
     private fun onPromotedNotificationChipTapEvent(key: String) {
-        StatusBarNotifChips.assertInNewMode()
+        StatusBarNotifChips.unsafeAssertInNewMode()
 
         val entry = notifCollection.getEntry(key)
         if (entry == null) {
@@ -459,7 +459,12 @@
                 } else {
                     if (posted.isHeadsUpEntry) {
                         // We don't want this to be interrupting anymore, let's remove it
-                        hunMutator.removeNotification(posted.key, false /*removeImmediately*/)
+                        // If the notification is pinned by the user, the only way a user can un-pin
+                        // it is by tapping the status bar notification chip. Since that's a clear
+                        // user action, we should remove the HUN immediately instead of waiting for
+                        // any sort of minimum timeout.
+                        val shouldRemoveImmediately = posted.isPinnedByUser
+                        hunMutator.removeNotification(posted.key, shouldRemoveImmediately)
                     } else {
                         // Don't let the bind finish
                         cancelHeadsUpBind(posted.entry)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt
index a0e44bf..cf78812 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/StabilizeHeadsUpGroup.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
index c5ae875..0d4207b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupExpansionManagerImpl.java
@@ -162,7 +162,7 @@
 
     @Override
     public boolean isGroupExpanded(EntryAdapter entry) {
-        NotificationBundleUi.assertInNewMode();
+        NotificationBundleUi.unsafeAssertInNewMode();
         ExpandableNotificationRow parent = entry.getRow().getNotificationParent();
         return mExpandedCollections.contains(entry)
                 || (parent != null && mExpandedCollections.contains(parent.getEntryAdapter()));
@@ -170,7 +170,7 @@
 
     @Override
     public void setGroupExpanded(EntryAdapter groupRoot, boolean expanded) {
-        NotificationBundleUi.assertInNewMode();
+        NotificationBundleUi.unsafeAssertInNewMode();
         if (!groupRoot.isAttached()) {
             if (expanded) {
                 Log.wtf(TAG, "Cannot expand group that is not attached");
@@ -192,7 +192,7 @@
 
     @Override
     public boolean toggleGroupExpansion(EntryAdapter groupRoot) {
-        NotificationBundleUi.assertInNewMode();
+        NotificationBundleUi.unsafeAssertInNewMode();
         setGroupExpanded(groupRoot, !isGroupExpanded(groupRoot));
         return isGroupExpanded(groupRoot);
     }
@@ -231,7 +231,7 @@
     }
 
     private void sendOnGroupExpandedChange(EntryAdapter entry, boolean expanded) {
-        NotificationBundleUi.assertInNewMode();
+        NotificationBundleUi.unsafeAssertInNewMode();
         for (OnGroupExpansionChangeListener listener : mOnGroupChangeListeners) {
             listener.onGroupExpansionChange(entry.getRow(), expanded);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
index aec0d70..66a4f9f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerImpl.java
@@ -59,7 +59,7 @@
 
     @Override
     public boolean isGroupRoot(@NonNull EntryAdapter entry) {
-        NotificationBundleUi.assertInNewMode();
+        NotificationBundleUi.unsafeAssertInNewMode();
         return entry.isGroupRoot();
     }
 
@@ -85,7 +85,7 @@
 
     @Override
     public boolean isChildInGroup(@NonNull EntryAdapter entry) {
-        NotificationBundleUi.assertInNewMode();
+        NotificationBundleUi.unsafeAssertInNewMode();
         // An entry is a child if it's not a group root or top level entry, but it is attached.
         return entry.isAttached() && !entry.isGroupRoot() && !entry.isTopLevelEntry();
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
index 53d5dbc..ef3da94 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/dagger/NotificationsModule.java
@@ -37,6 +37,8 @@
 import com.android.systemui.statusbar.notification.NotificationActivityStarter;
 import com.android.systemui.statusbar.notification.NotificationLaunchAnimatorControllerProvider;
 import com.android.systemui.statusbar.notification.VisibilityLocationProvider;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactory;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl;
 import com.android.systemui.statusbar.notification.collection.NotifInflaterImpl;
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStore;
 import com.android.systemui.statusbar.notification.collection.NotifLiveDataStoreImpl;
@@ -340,4 +342,8 @@
             return MagneticNotificationRowManager.getEmpty();
         }
     }
+
+    /** Provides an instance of {@link EntryAdapterFactory} */
+    @Binds
+    EntryAdapterFactory provideEntryAdapterFactory(EntryAdapterFactoryImpl impl);
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/shared/ModesEmptyShadeFix.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/shared/ModesEmptyShadeFix.kt
index f1fc275..52bf894 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/shared/ModesEmptyShadeFix.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/shared/ModesEmptyShadeFix.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt
index 7e6c605..9bb9b9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/emptyshade/ui/viewmodel/EmptyShadeViewModel.kt
@@ -124,7 +124,7 @@
     }
 
     val footer: FooterMessageViewModel by lazy {
-        ModesEmptyShadeFix.assertInNewMode()
+        ModesEmptyShadeFix.unsafeAssertInNewMode()
         FooterMessageViewModel(
             messageId = R.string.unlock_to_see_notif_text,
             iconId = R.drawable.ic_friction_lock_closed,
@@ -133,7 +133,7 @@
     }
 
     val onClick: Flow<SettingsIntent> by lazy {
-        ModesEmptyShadeFix.assertInNewMode()
+        ModesEmptyShadeFix.unsafeAssertInNewMode()
         combine(
                 zenModeInteractor.modesHidingNotifications,
                 notificationSettingsInteractor.isNotificationHistoryEnabled,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/shared/NotifRedesignFooter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/shared/NotifRedesignFooter.kt
index 0307d90..90faa4d 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/shared/NotifRedesignFooter.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/footer/shared/NotifRedesignFooter.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt
index 8eca166..c401d82 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/AvalancheController.kt
@@ -16,7 +16,6 @@
 package com.android.systemui.statusbar.notification.headsup
 
 import android.os.Handler
-import android.util.Log
 import androidx.annotation.VisibleForTesting
 import com.android.internal.logging.UiEvent
 import com.android.internal.logging.UiEventLogger
@@ -24,9 +23,9 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
 import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.notification.headsup.HeadsUpManagerImpl.HeadsUpEntry
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun
-import com.android.systemui.util.Compile
 import java.io.PrintWriter
 import javax.inject.Inject
 
@@ -155,6 +154,7 @@
         } else if (entry in nextMap) {
             outcome = "update next"
             nextMap[entry]?.add(runnable)
+            checkNextPinnedByUser(entry)?.let { outcome = "$outcome & $it" }
         } else if (headsUpEntryShowing == null) {
             outcome = "show now"
             showNow(entry, arrayListOf(runnable))
@@ -166,17 +166,22 @@
             outcome = "add next"
             addToNext(entry, runnable)
 
-            // Shorten headsUpEntryShowing display time
-            val nextIndex = nextList.indexOf(entry)
-            val isOnlyNextEntry = nextIndex == 0 && nextList.size == 1
-            if (isOnlyNextEntry) {
-                // HeadsUpEntry.updateEntry recursively calls AvalancheController#update
-                // and goes to the isShowing case above
-                headsUpEntryShowing!!.updateEntry(
-                    /* updatePostTime= */ false,
-                    /* updateEarliestRemovalTime= */ false,
-                    /* reason= */ "shorten duration of previously-last HUN",
-                )
+            val nextIsPinnedByUserResult = checkNextPinnedByUser(entry)
+            if (nextIsPinnedByUserResult != null) {
+                outcome = "$outcome & $nextIsPinnedByUserResult"
+            } else {
+                // Shorten headsUpEntryShowing display time
+                val nextIndex = nextList.indexOf(entry)
+                val isOnlyNextEntry = nextIndex == 0 && nextList.size == 1
+                if (isOnlyNextEntry) {
+                    // HeadsUpEntry.updateEntry recursively calls AvalancheController#update
+                    // and goes to the isShowing case above
+                    headsUpEntryShowing!!.updateEntry(
+                        /* updatePostTime= */ false,
+                        /* updateEarliestRemovalTime= */ false,
+                        /* reason= */ "shorten duration of previously-last HUN",
+                    )
+                }
             }
         }
         outcome += getStateStr()
@@ -190,6 +195,28 @@
     }
 
     /**
+     * Checks if the given entry is requesting [PinnedStatus.PinnedByUser] status and makes the
+     * correct updates if needed.
+     *
+     * @return a string representing the outcome, or null if nothing changed.
+     */
+    private fun checkNextPinnedByUser(entry: HeadsUpEntry): String? {
+        if (
+            StatusBarNotifChips.isEnabled &&
+                entry.requestedPinnedStatus == PinnedStatus.PinnedByUser
+        ) {
+            val string = "next is PinnedByUser"
+            headsUpEntryShowing?.updateEntry(
+                /* updatePostTime= */ false,
+                /* updateEarliestRemovalTime= */ false,
+                /* reason= */ string,
+            )
+            return string
+        }
+        return null
+    }
+
+    /**
      * Run or ignore Runnable for given HeadsUpEntry. If entry was never shown, ignore and delete
      * all Runnables associated with that entry.
      */
@@ -243,19 +270,22 @@
             outcome = "remove showing. ${getStateStr()}"
         } else {
             runnable.run()
-            outcome = "run runnable for untracked HUN " +
+            outcome =
+                "run runnable for untracked HUN " +
                     "(was dropped or shown when AC was disabled). ${getStateStr()}"
         }
         headsUpManagerLogger.logAvalancheDelete(caller, isEnabled(), getKey(entry), outcome)
     }
 
     /**
-     * Returns duration based on
+     * Returns how much longer the given entry should show based on:
      * 1) Whether HeadsUpEntry is the last one tracked by AvalancheController
-     * 2) The priority of the top HUN in the next batch Used by
-     *    BaseHeadsUpManager.HeadsUpEntry.calculateFinishTime to shorten display duration.
+     * 2) The priority of the top HUN in the next batch
+     *
+     * Used by [HeadsUpManagerImpl.HeadsUpEntry]'s finishTimeCalculator to shorten display duration.
      */
-    fun getDurationMs(entry: HeadsUpEntry?, autoDismissMs: Int): Int {
+    fun getDuration(entry: HeadsUpEntry?, autoDismissMsValue: Int): RemainingDuration {
+        val autoDismissMs = RemainingDuration.UpdatedDuration(autoDismissMsValue)
         if (!isEnabled()) {
             // Use default duration, like we did before AvalancheController existed
             return autoDismissMs
@@ -273,7 +303,11 @@
         val thisKey = getKey(entry)
         if (entryList.isEmpty()) {
             headsUpManagerLogger.logAvalancheDuration(
-                thisKey, autoDismissMs, "No avalanche HUNs, use default", nextKey = "")
+                thisKey,
+                autoDismissMs,
+                "No avalanche HUNs, use default",
+                nextKey = "",
+            )
             return autoDismissMs
         }
         // entryList.indexOf(entry) returns -1 even when the entry is in entryList
@@ -285,28 +319,64 @@
         }
         if (thisEntryIndex == -1) {
             headsUpManagerLogger.logAvalancheDuration(
-                thisKey, autoDismissMs, "Untracked entry, use default", nextKey = "")
+                thisKey,
+                autoDismissMs,
+                "Untracked entry, use default",
+                nextKey = "",
+            )
             return autoDismissMs
         }
         val nextEntryIndex = thisEntryIndex + 1
         if (nextEntryIndex >= entryList.size) {
             headsUpManagerLogger.logAvalancheDuration(
-                thisKey, autoDismissMs, "Last entry, use default", nextKey = "")
+                thisKey,
+                autoDismissMs,
+                "Last entry, use default",
+                nextKey = "",
+            )
             return autoDismissMs
         }
         val nextEntry = entryList[nextEntryIndex]
         val nextKey = getKey(nextEntry)
+
+        if (
+            StatusBarNotifChips.isEnabled &&
+                nextEntry.requestedPinnedStatus == PinnedStatus.PinnedByUser
+        ) {
+            return RemainingDuration.HideImmediately.also {
+                headsUpManagerLogger.logAvalancheDuration(
+                    thisKey,
+                    duration = it,
+                    "next is PinnedByUser",
+                    nextKey,
+                )
+            }
+        }
         if (nextEntry.compareNonTimeFields(entry) == -1) {
-            headsUpManagerLogger.logAvalancheDuration(
-                thisKey, 500, "LOWER priority than next: ", nextKey)
-            return 500
+            return RemainingDuration.UpdatedDuration(500).also {
+                headsUpManagerLogger.logAvalancheDuration(
+                    thisKey,
+                    duration = it,
+                    "LOWER priority than next: ",
+                    nextKey,
+                )
+            }
         } else if (nextEntry.compareNonTimeFields(entry) == 0) {
-            headsUpManagerLogger.logAvalancheDuration(
-                thisKey, 1000, "SAME priority as next: ", nextKey)
-            return 1000
+            return RemainingDuration.UpdatedDuration(1000).also {
+                headsUpManagerLogger.logAvalancheDuration(
+                    thisKey,
+                    duration = it,
+                    "SAME priority as next: ",
+                    nextKey,
+                )
+            }
         } else {
             headsUpManagerLogger.logAvalancheDuration(
-                thisKey, autoDismissMs, "HIGHER priority than next: ", nextKey)
+                thisKey,
+                autoDismissMs,
+                "HIGHER priority than next: ",
+                nextKey,
+            )
             return autoDismissMs
         }
     }
@@ -377,11 +447,11 @@
     }
 
     private fun showNext() {
-        headsUpManagerLogger.logAvalancheStage("show next",  key = "")
+        headsUpManagerLogger.logAvalancheStage("show next", key = "")
         headsUpEntryShowing = null
 
         if (nextList.isEmpty()) {
-            headsUpManagerLogger.logAvalancheStage("no more",  key = "")
+            headsUpManagerLogger.logAvalancheStage("no more", key = "")
             previousHunKey = ""
             return
         }
@@ -432,10 +502,12 @@
 
     private fun getStateStr(): String {
         return "\n[AC state]" +
-                "\nshow: ${getKey(headsUpEntryShowing)}" +
-                "\nprevious: $previousHunKey" +
-                "\n$nextStr" +
-                "\n[HeadsUpManagerImpl.mHeadsUpEntryMap] " + baseEntryMapStr() + "\n"
+            "\nshow: ${getKey(headsUpEntryShowing)}" +
+            "\nprevious: $previousHunKey" +
+            "\n$nextStr" +
+            "\n[HeadsUpManagerImpl.mHeadsUpEntryMap] " +
+            baseEntryMapStr() +
+            "\n"
     }
 
     private val nextStr: String
@@ -447,7 +519,7 @@
             // This should never happen
             val nextMapStr = nextMap.keys.joinToString("\n ") { getKey(it) }
             return "next list (${nextList.size}):\n $nextListStr" +
-                    "\nnext map (${nextMap.size}):\n $nextMapStr"
+                "\nnext map (${nextMap.size}):\n $nextMapStr"
         }
 
     fun getKey(entry: HeadsUpEntry?): String {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimationEvent.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimationEvent.kt
new file mode 100644
index 0000000..ab84896
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimationEvent.kt
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.headsup
+
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
+
+/** Models the data needed for a heads-up notification animation. */
+data class HeadsUpAnimationEvent(
+    /** The row corresponding to the heads-up notification. */
+    val row: ExpandableNotificationRow,
+    /**
+     * True if this notification should do a appearance animation, false if this notification should
+     * do a disappear animation.
+     */
+    val isHeadsUpAppearance: Boolean,
+    /** True if the status bar is showing a chip corresponding to this notification. */
+    val hasStatusBarChip: Boolean,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimator.kt
index f9bd805..2f2d80a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpAnimator.kt
@@ -17,21 +17,27 @@
 package com.android.systemui.statusbar.notification.headsup
 
 import android.content.Context
+import com.android.internal.policy.SystemBarUtils
 import com.android.systemui.res.R
+import com.android.systemui.statusbar.ui.SystemBarUtilsProxy
 
 /**
  * A class shared between [StackScrollAlgorithm] and [StackStateAnimator] to ensure all heads up
  * animations use the same animation values.
+ *
+ * @param systemBarUtilsProxy optional utility class to provide the status bar height. Typically
+ *   null in production code and non-null in tests.
  */
-class HeadsUpAnimator(context: Context) {
+class HeadsUpAnimator(context: Context, private val systemBarUtilsProxy: SystemBarUtilsProxy?) {
     init {
-        NotificationsHunSharedAnimationValues.assertInNewMode()
+        NotificationsHunSharedAnimationValues.unsafeAssertInNewMode()
     }
 
     var headsUpAppearHeightBottom: Int = 0
     var stackTopMargin: Int = 0
 
     private var headsUpAppearStartAboveScreen = context.fetchHeadsUpAppearStartAboveScreen()
+    private var statusBarHeight = fetchStatusBarHeight(context)
 
     /**
      * Returns the Y translation for a heads-up notification animation.
@@ -40,14 +46,20 @@
      * animation. For a disappear animation, the returned Y translation should be the ending value
      * of the animation.
      */
-    fun getHeadsUpYTranslation(isHeadsUpFromBottom: Boolean): Int {
-        NotificationsHunSharedAnimationValues.assertInNewMode()
+    fun getHeadsUpYTranslation(isHeadsUpFromBottom: Boolean, hasStatusBarChip: Boolean): Int {
+        if (NotificationsHunSharedAnimationValues.isUnexpectedlyInLegacyMode()) return 0
 
         if (isHeadsUpFromBottom) {
             // start from or end at the bottom of the screen
             return headsUpAppearHeightBottom + headsUpAppearStartAboveScreen
         }
 
+        if (hasStatusBarChip) {
+            // If this notification is also represented by a chip in the status bar, we don't want
+            // any HUN transitions to obscure that chip.
+            return statusBarHeight - stackTopMargin
+        }
+
         // start from or end at the top of the screen
         return -stackTopMargin - headsUpAppearStartAboveScreen
     }
@@ -55,9 +67,15 @@
     /** Should be invoked when resource values may have changed. */
     fun updateResources(context: Context) {
         headsUpAppearStartAboveScreen = context.fetchHeadsUpAppearStartAboveScreen()
+        statusBarHeight = fetchStatusBarHeight(context)
     }
 
     private fun Context.fetchHeadsUpAppearStartAboveScreen(): Int {
         return this.resources.getDimensionPixelSize(R.dimen.heads_up_appear_y_above_screen)
     }
+
+    private fun fetchStatusBarHeight(context: Context): Int {
+        return systemBarUtilsProxy?.getStatusBarHeight()
+            ?: SystemBarUtils.getStatusBarHeight(context)
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
index 5157e7a..ca94655 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerImpl.java
@@ -46,7 +46,6 @@
 import com.android.systemui.shade.domain.interactor.ShadeInteractor;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
-import com.android.systemui.statusbar.notification.collection.EntryAdapter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.coordinator.HeadsUpCoordinator;
 import com.android.systemui.statusbar.notification.collection.provider.OnReorderingAllowedListener;
@@ -320,15 +319,17 @@
 
         mLogger.logShowNotificationRequest(entry, isPinnedByUser);
 
+        PinnedStatus requestedPinnedStatus =
+                isPinnedByUser
+                        ? PinnedStatus.PinnedByUser
+                        : PinnedStatus.PinnedBySystem;
+        headsUpEntry.setRequestedPinnedStatus(requestedPinnedStatus);
+
         Runnable runnable = () -> {
             mLogger.logShowNotification(entry, isPinnedByUser);
 
             // Add new entry and begin managing it
             mHeadsUpEntryMap.put(entry.getKey(), headsUpEntry);
-            PinnedStatus requestedPinnedStatus =
-                    isPinnedByUser
-                            ? PinnedStatus.PinnedByUser
-                            : PinnedStatus.PinnedBySystem;
             onEntryAdded(headsUpEntry, requestedPinnedStatus);
             // TODO(b/328390331) move accessibility events to the view layer
             entry.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_CONTENT_CHANGED);
@@ -1096,7 +1097,7 @@
     @Override
     public void setExpanded(@NonNull String entryKey, @NonNull ExpandableNotificationRow row,
             boolean expanded) {
-        NotificationBundleUi.assertInNewMode();
+        NotificationBundleUi.unsafeAssertInNewMode();
         HeadsUpEntry headsUpEntry = getHeadsUpEntry(entryKey);
         if (headsUpEntry != null && row.getPinnedStatus().isPinned()) {
             headsUpEntry.setExpanded(expanded);
@@ -1289,10 +1290,17 @@
         @Nullable private Runnable mCancelRemoveRunnable;
 
         private boolean mGutsShownPinned;
+        /** The *current* pinned status of this HUN. */
         private final MutableStateFlow<PinnedStatus> mPinnedStatus =
                 StateFlowKt.MutableStateFlow(PinnedStatus.NotPinned);
 
         /**
+         * The *requested* pinned status of this HUN. {@link AvalancheController} uses this value to
+         * know if the current HUN needs to be removed so that a pinned-by-user HUN can show.
+         */
+        private PinnedStatus mRequestedPinnedStatus = PinnedStatus.NotPinned;
+
+        /**
          * If the time this entry has been on was extended
          */
         private boolean extended;
@@ -1352,6 +1360,20 @@
             }
         }
 
+        /** Sets what pinned status this HUN is requesting. */
+        void setRequestedPinnedStatus(PinnedStatus pinnedStatus) {
+            if (!StatusBarNotifChips.isEnabled() && pinnedStatus == PinnedStatus.PinnedByUser) {
+                Log.w(TAG, "PinnedByUser status not allowed if StatusBarNotifChips is disabled");
+                mRequestedPinnedStatus = PinnedStatus.NotPinned;
+            } else {
+                mRequestedPinnedStatus = pinnedStatus;
+            }
+        }
+
+        PinnedStatus getRequestedPinnedStatus() {
+            return mRequestedPinnedStatus;
+        }
+
         @VisibleForTesting
         void setRowPinnedStatus(PinnedStatus pinnedStatus) {
             if (mEntry != null) mEntry.setRowPinnedStatus(pinnedStatus);
@@ -1410,11 +1432,29 @@
             }
 
             FinishTimeUpdater finishTimeCalculator = () -> {
-                final long finishTime = calculateFinishTime();
+                RemainingDuration remainingDuration =
+                        mAvalancheController.getDuration(this, mAutoDismissTime);
+
+                if (remainingDuration instanceof RemainingDuration.HideImmediately) {
+                    /* Check if */ StatusBarNotifChips.isUnexpectedlyInLegacyMode();
+                    return 0;
+                }
+
+                int remainingTimeoutMs;
+                if (isStickyForSomeTime()) {
+                    remainingTimeoutMs = mStickyForSomeTimeAutoDismissTime;
+                } else {
+                    remainingTimeoutMs =
+                            ((RemainingDuration.UpdatedDuration) remainingDuration).getDuration();
+                }
+                final long duration = getRecommendedHeadsUpTimeoutMs(remainingTimeoutMs);
+                final long timeoutTimestamp =
+                        mPostTime + duration + (extended ? mExtensionTime : 0);
+
                 final long now = mSystemClock.elapsedRealtime();
                 return NotificationThrottleHun.isEnabled()
-                        ? Math.max(finishTime, mEarliestRemovalTime) - now
-                        : Math.max(finishTime - now, mMinimumDisplayTimeDefault);
+                        ? Math.max(timeoutTimestamp, mEarliestRemovalTime) - now
+                        : Math.max(timeoutTimestamp - now, mMinimumDisplayTimeDefault);
             };
             scheduleAutoRemovalCallback(finishTimeCalculator, "updateEntry (not sticky)");
 
@@ -1696,21 +1736,6 @@
         }
 
         /**
-         * @return When the notification should auto-dismiss itself, based on
-         * {@link SystemClock#elapsedRealtime()}
-         */
-        private long calculateFinishTime() {
-            int requestedTimeOutMs;
-            if (isStickyForSomeTime()) {
-                requestedTimeOutMs = mStickyForSomeTimeAutoDismissTime;
-            } else {
-                requestedTimeOutMs = mAvalancheController.getDurationMs(this, mAutoDismissTime);
-            }
-            final long duration = getRecommendedHeadsUpTimeoutMs(requestedTimeOutMs);
-            return mPostTime + duration + (extended ? mExtensionTime : 0);
-        }
-
-        /**
          * Get user-preferred or default timeout duration. The larger one will be returned.
          * @return milliseconds before auto-dismiss
          */
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt
index 388d357..00b05cb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/HeadsUpManagerLogger.kt
@@ -106,13 +106,23 @@
         )
     }
 
-    fun logAvalancheDuration(thisKey: String, duration: Int, reason: String, nextKey: String) {
+    fun logAvalancheDuration(
+        thisKey: String,
+        duration: RemainingDuration,
+        reason: String,
+        nextKey: String,
+    ) {
+        val durationMs =
+            when (duration) {
+                is RemainingDuration.UpdatedDuration -> duration.duration
+                is RemainingDuration.HideImmediately -> 0
+            }
         buffer.log(
             TAG,
             INFO,
             {
                 str1 = thisKey
-                int1 = duration
+                int1 = durationMs
                 str2 = reason
                 str3 = nextKey
             },
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/NotificationsHunSharedAnimationValues.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/NotificationsHunSharedAnimationValues.kt
index ca9d498..f52d351 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/NotificationsHunSharedAnimationValues.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/NotificationsHunSharedAnimationValues.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/RemainingDuration.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/RemainingDuration.kt
new file mode 100644
index 0000000..fd7f4e8
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/headsup/RemainingDuration.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.headsup
+
+/** Models how much longer a HUN should be displayed. */
+sealed interface RemainingDuration {
+    /** This HUN should be hidden immediately, regardless of any minimum time enforcements. */
+    data object HideImmediately : RemainingDuration
+
+    /** This HUN should hide after [duration] milliseconds have occurred. */
+    data class UpdatedDuration(val duration: Int) : RemainingDuration
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
index c512b43..294b8d3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/IconManager.kt
@@ -90,12 +90,12 @@
         ConcurrentHashMap<String, Job>()
 
     fun addIconsUpdateListener(listener: OnIconUpdateRequiredListener) {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
         onIconUpdateRequiredListeners += listener
     }
 
     fun removeIconsUpdateListener(listener: OnIconUpdateRequiredListener) {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
         onIconUpdateRequiredListeners -= listener
     }
 
@@ -140,7 +140,7 @@
      */
     fun createSbIconView(context: Context, entry: NotificationEntry): StatusBarIconView =
         traceSection("IconManager.createSbIconView") {
-            StatusBarConnectedDisplays.assertInNewMode()
+            StatusBarConnectedDisplays.unsafeAssertInNewMode()
 
             val sbIcon = iconBuilder.createIconView(entry, context)
             sbIcon.scaleType = ImageView.ScaleType.CENTER_INSIDE
@@ -200,7 +200,7 @@
     /** Update the [StatusBarIconView] for the given [NotificationEntry]. */
     fun updateSbIcon(entry: NotificationEntry, iconView: StatusBarIconView) =
         traceSection("IconManager.updateSbIcon") {
-            StatusBarConnectedDisplays.assertInNewMode()
+            StatusBarConnectedDisplays.unsafeAssertInNewMode()
 
             val (normalIconDescriptor, _) = getIconDescriptors(entry)
             val notificationContentDescription =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerStatusBarViewBinder.kt
index aa81ebf..147a5af 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/icon/ui/viewbinder/NotificationIconContainerStatusBarViewBinder.kt
@@ -18,11 +18,10 @@
 
 import android.view.Display
 import androidx.lifecycle.lifecycleScope
-import com.android.app.tracing.coroutines.launchTraced as launch
 import com.android.app.tracing.traceSection
 import com.android.systemui.common.ui.ConfigurationState
+import com.android.systemui.display.data.repository.PerDisplayRepository
 import com.android.systemui.lifecycle.repeatWhenAttached
-import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.notification.collection.NotifCollection
 import com.android.systemui.statusbar.notification.icon.ui.viewbinder.NotificationIconContainerViewBinder.IconViewStore
 import com.android.systemui.statusbar.notification.icon.ui.viewmodel.NotificationIconContainerStatusBarViewModel
@@ -37,7 +36,8 @@
 @Inject
 constructor(
     private val viewModel: NotificationIconContainerStatusBarViewModel,
-    @ShadeDisplayAware private val configuration: ConfigurationState,
+    private val configurationStateRepository: PerDisplayRepository<ConfigurationState>,
+    private val defaultConfigurationState: ConfigurationState,
     private val systemBarUtilsState: SystemBarUtilsState,
     private val failureTracker: StatusBarIconViewBindingFailureTracker,
     private val defaultDisplayViewStore: StatusBarNotificationIconViewStore,
@@ -56,12 +56,14 @@
                             lifecycleScope.launch { it.activate() }
                         }
                     }
+                val configurationState: ConfigurationState =
+                    configurationStateRepository[displayId] ?: defaultConfigurationState
                 lifecycleScope.launch {
                     NotificationIconContainerViewBinder.bind(
                         displayId = displayId,
                         view = view,
                         viewModel = viewModel,
-                        configuration = configuration,
+                        configuration = configurationState,
                         systemBarUtilsState = systemBarUtilsState,
                         failureTracker = failureTracker,
                         viewStore = viewStore,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUi.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUi.kt
index 6324219..da59a40 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUi.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUi.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiAod.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiAod.kt
index fa1f32c..c6e3da1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiAod.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiAod.kt
@@ -49,7 +49,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiForceExpanded.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiForceExpanded.kt
index cb0d674..adeddde 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiForceExpanded.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationUiForceExpanded.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt
index 4bc6854..ec4ee45 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/AODPromotedNotificationInteractor.kt
@@ -19,7 +19,6 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
-import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style
 import com.android.systemui.util.kotlin.FlowDumperImpl
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
@@ -34,10 +33,7 @@
 ) : FlowDumperImpl(dumpManager) {
     /** The content to show as the promoted notification on AOD */
     val content: Flow<PromotedNotificationContentModel?> =
-        promotedNotificationsInteractor.topPromotedNotificationContent
+        promotedNotificationsInteractor.aodPromotedNotification
 
-    val isPresent: Flow<Boolean> =
-        content
-            .map { (it != null) && (it.style != Style.Ineligible) }
-            .dumpWhileCollecting("isPresent")
+    val isPresent: Flow<Boolean> = content.map { it != null }.dumpWhileCollecting("isPresent")
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt
index 1015cfb..1abd48c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/promoted/domain/interactor/PromotedNotificationsInteractor.kt
@@ -22,6 +22,8 @@
 import com.android.systemui.statusbar.chips.notification.domain.interactor.StatusBarNotificationChipsInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
 import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel
+import com.android.systemui.statusbar.notification.promoted.shared.model.PromotedNotificationContentModel.Style.Ineligible
+import com.android.systemui.statusbar.notification.shared.ActiveNotificationModel
 import com.android.systemui.statusbar.phone.ongoingcall.shared.model.OngoingCallModel
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -83,13 +85,13 @@
             .map { list -> list.firstNotNullOfOrNull { it.promotedContent } }
             .distinctUntilNewInstance()
 
-    /** This is the top-most promoted notification, which should avoid regular changing. */
-    val topPromotedNotificationContent: Flow<PromotedNotificationContentModel?> =
+    /** This is the AOD promoted notification, which should avoid regular changing. */
+    val aodPromotedNotification: Flow<PromotedNotificationContentModel?> =
         combine(
                 topPromotedChipNotification,
                 activeNotificationsInteractor.topLevelRepresentativeNotifications,
             ) { topChipNotif, topLevelNotifs ->
-                topChipNotif ?: topLevelNotifs.firstNotNullOfOrNull { it.promotedContent }
+                topChipNotif?.takeIfAodEligible() ?: topLevelNotifs.firstAodEligibleOrNull()
             }
             // #equals() can be a bit expensive on this object, but this flow will regularly try to
             // emit the same immutable instance over and over, so just prevent that.
@@ -105,6 +107,16 @@
             .distinctUntilChanged()
             .flowOn(backgroundDispatcher)
 
+    private fun List<ActiveNotificationModel>.firstAodEligibleOrNull():
+        PromotedNotificationContentModel? {
+        return this.firstNotNullOfOrNull { it.promotedContent?.takeIfAodEligible() }
+    }
+
+    private fun PromotedNotificationContentModel.takeIfAodEligible():
+        PromotedNotificationContentModel? {
+        return this.takeUnless { it.style == Ineligible }
+    }
+
     /**
      * Returns flow where all subsequent repetitions of the same object instance are filtered out.
      */
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 3ef1fd2..68ad4fa 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
@@ -99,6 +99,7 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.StatusBarIconView;
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
 import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.FeedbackIcon;
@@ -110,6 +111,8 @@
 import com.android.systemui.statusbar.notification.SourceType;
 import com.android.systemui.statusbar.notification.collection.EntryAdapter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.collection.NotificationEntryAdapter;
+import com.android.systemui.statusbar.notification.collection.PipelineEntry;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
@@ -120,6 +123,7 @@
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiForceExpanded;
 import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.row.shared.LockscreenOtpRedaction;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.BundleHeaderViewModelImpl;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationCompactMessagingTemplateViewWrapper;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.notification.shared.NotificationAddXOnHoverToDismiss;
@@ -179,6 +183,7 @@
     private boolean mIsFaded;
 
     private boolean mIsPromotedOngoing = false;
+    private boolean mHasStatusBarChipDuringHeadsUpAnimation = false;
 
     @Nullable
     public ImageModelIndex mImageModelIndex = null;
@@ -426,7 +431,7 @@
                 onExpansionChanged(true /* userAction */, wasExpanded);
             }
         } else if (mEnableNonGroupedNotificationExpand) {
-            if (v.isAccessibilityFocused()) {
+            if (v != null && v.isAccessibilityFocused()) {
                 mPrivateLayout.setFocusOnVisibilityChange();
             }
             boolean nowExpanded;
@@ -947,7 +952,7 @@
 
     @Nullable
     public EntryAdapter getEntryAdapter() {
-        NotificationBundleUi.assertInNewMode();
+        NotificationBundleUi.unsafeAssertInNewMode();
         return mEntryAdapter;
     }
 
@@ -1679,14 +1684,12 @@
             view.setBackgroundTintColor(color);
         }
         if (notificationRowTransparency() && mBackgroundNormal != null) {
-            if (NotificationBundleUi.isEnabled()) {
-                mBackgroundNormal.setBgIsColorized(
-                        usesTransparentBackground() && mEntryAdapter.isColorized());
+            if (NotificationBundleUi.isEnabled() && mEntryAdapter != null) {
+                mBackgroundNormal.setBgIsColorized(mEntryAdapter.isColorized());
             } else {
                 if (mEntry != null) {
                     mBackgroundNormal.setBgIsColorized(
-                            usesTransparentBackground()
-                                    && mEntry.getSbn().getNotification().isColorized());
+                            mEntry.getSbn().getNotification().isColorized());
                 }
             }
         }
@@ -1816,6 +1819,22 @@
         );
     }
 
+    /**
+     * Init the bundle header view. The ComposeView is initialized within with the passed viewModel.
+     * This can only be init once and not in conjunction with any other header view.
+     */
+    public void initBundleHeader(@NonNull BundleHeaderViewModelImpl bundleHeaderViewModel) {
+        if (NotificationBundleUi.isUnexpectedlyInLegacyMode()) return;
+        NotificationChildrenContainer childrenContainer = getChildrenContainerNonNull();
+        bundleHeaderViewModel.setOnExpandClickListener(mExpandClickListener);
+
+        childrenContainer.initBundleHeader(bundleHeaderViewModel);
+
+        if (TransparentHeaderFix.isEnabled()) {
+            updateBackgroundForGroupState();
+        }
+    }
+
     public void setHeadsUpAnimatingAway(boolean headsUpAnimatingAway) {
         boolean wasAboveShelf = isAboveShelf();
         boolean changed = headsUpAnimatingAway != mHeadsupDisappearRunning;
@@ -2074,7 +2093,7 @@
      */
     public ExpandableNotificationRow(Context context, AttributeSet attrs, UserHandle user) {
         this(context, attrs, userContextForEntry(context, user));
-        NotificationBundleUi.assertInNewMode();
+        NotificationBundleUi.unsafeAssertInNewMode();
     }
 
     /**
@@ -2122,7 +2141,8 @@
      * Initialize row.
      */
     public void initialize(
-            NotificationEntry entry,
+            EntryAdapter entryAdapter,
+            PipelineEntry entry,
             RemoteInputViewSubcomponent.Factory rivSubcomponentFactory,
             String appName,
             @NonNull String notificationKey,
@@ -2150,11 +2170,11 @@
             NotificationRebindingTracker notificationRebindingTracker) {
 
         if (NotificationBundleUi.isEnabled()) {
+            mEntryAdapter = entryAdapter;
             // TODO (b/395857098): remove when all usages are migrated
-            mEntryAdapter = entry.getEntryAdapter();
-            mEntry = entry;
+            mEntry = (NotificationEntry) entry;
         } else {
-            mEntry = entry;
+            mEntry = (NotificationEntry) entry;
         }
         mAppName = appName;
         mRebindingTracker = notificationRebindingTracker;
@@ -2943,6 +2963,30 @@
         setExpandable(!mIsPromotedOngoing);
     }
 
+    /**
+     * Sets whether the status bar is showing a chip corresponding to this notification.
+     *
+     * Only set when this notification's heads-up status changes since that's the only time it's
+     * relevant.
+     */
+    public void setHasStatusBarChipDuringHeadsUpAnimation(boolean hasStatusBarChip) {
+        if (StatusBarNotifChips.isUnexpectedlyInLegacyMode()) {
+            return;
+        }
+        mHasStatusBarChipDuringHeadsUpAnimation = hasStatusBarChip;
+    }
+
+    /**
+     * Returns true if the status bar is showing a chip corresponding to this notification during a
+     * heads-up appear or disappear animation.
+     *
+     * Note that this value is only set when this notification's heads-up status changes since
+     * that's the only time it's relevant.
+     */
+    public boolean hasStatusBarChipDuringHeadsUpAnimation() {
+        return StatusBarNotifChips.isEnabled() && mHasStatusBarChipDuringHeadsUpAnimation;
+    }
+
     @Override
     public void setClipToActualHeight(boolean clipToActualHeight) {
         super.setClipToActualHeight(clipToActualHeight || isUserLocked());
@@ -3022,7 +3066,6 @@
 
         mUserLocked = userLocked;
         mPrivateLayout.setUserExpanding(userLocked);
-        mPublicLayout.setUserExpanding(userLocked);
         // This is intentionally not guarded with mIsSummaryWithChildren since we might have had
         // children but not anymore.
         if (mChildrenContainer != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
index 02e8f49..ac55930 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowController.java
@@ -45,7 +45,11 @@
 import com.android.systemui.statusbar.SmartReplyController;
 import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.FeedbackIcon;
-import com.android.systemui.statusbar.notification.collection.NotificationEntry;
+import com.android.systemui.statusbar.notification.NotificationActivityStarter;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactory;
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl;
+import com.android.systemui.statusbar.notification.collection.PipelineEntry;
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator;
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
 import com.android.systemui.statusbar.notification.collection.render.GroupMembershipManager;
@@ -56,6 +60,7 @@
 import com.android.systemui.statusbar.notification.row.dagger.AppName;
 import com.android.systemui.statusbar.notification.row.dagger.NotificationKey;
 import com.android.systemui.statusbar.notification.row.dagger.NotificationRowScope;
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider;
 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
 import com.android.systemui.statusbar.notification.stack.NotificationChildrenContainerLogger;
 import com.android.systemui.statusbar.notification.stack.NotificationListContainer;
@@ -118,8 +123,8 @@
     private final IStatusBarService mStatusBarService;
     private final UiEventLogger mUiEventLogger;
     private final MSDLPlayer mMSDLPlayer;
-
     private final NotificationSettingsController mSettingsController;
+    private final EntryAdapterFactory mEntryAdapterFactory;
 
     @VisibleForTesting
     final NotificationSettingsController.Listener mSettingsListener =
@@ -285,7 +290,8 @@
             IStatusBarService statusBarService,
             UiEventLogger uiEventLogger,
             MSDLPlayer msdlPlayer,
-            NotificationRebindingTracker notificationRebindingTracker) {
+            NotificationRebindingTracker notificationRebindingTracker,
+            EntryAdapterFactory entryAdapterFactory) {
         mView = view;
         mListContainer = listContainer;
         mRemoteInputViewSubcomponentFactory = rivSubcomponentFactory;
@@ -322,14 +328,16 @@
         mStatusBarService = statusBarService;
         mUiEventLogger = uiEventLogger;
         mMSDLPlayer = msdlPlayer;
+        mEntryAdapterFactory = entryAdapterFactory;
     }
 
     /**
      * Initialize the controller.
      */
-    public void init(NotificationEntry entry) {
+    public void init(PipelineEntry entry) {
         mActivatableNotificationViewController.init();
         mView.initialize(
+                mEntryAdapterFactory.create(entry),
                 entry,
                 mRemoteInputViewSubcomponentFactory,
                 mAppName,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
index 7713580..d02f636 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/MagicActionBackgroundDrawable.kt
@@ -42,14 +42,6 @@
 
     private val buttonShape = Path()
     // Color and style
-    private val bgPaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
-        val bgColor =
-            context.getColor(
-                com.android.internal.R.color.materialColorPrimaryContainer
-            )
-        color = bgColor
-        style = Paint.Style.FILL
-    }
     private val outlinePaint = Paint(Paint.ANTI_ALIAS_FLAG).apply {
         val outlineColor =
             context.getColor(
@@ -99,7 +91,6 @@
         canvas.save()
         // Draw background
         canvas.clipPath(buttonShape)
-        canvas.drawPath(buttonShape, bgPaint)
         // Apply gradient to outline
         canvas.drawPath(buttonShape, outlinePaint)
         updateGradient(boundsF)
@@ -128,13 +119,11 @@
     }
 
     override fun setAlpha(alpha: Int) {
-        bgPaint.alpha = alpha
         outlinePaint.alpha = alpha
         invalidateSelf()
     }
 
     override fun setColorFilter(colorFilter: ColorFilter?) {
-        bgPaint.colorFilter = colorFilter
         outlinePaint.colorFilter = colorFilter
         invalidateSelf()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
index daa598b..51569c1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationContentInflater.java
@@ -57,7 +57,6 @@
 import com.android.systemui.statusbar.notification.InflationException;
 import com.android.systemui.statusbar.notification.NmSummarizationUiFlag;
 import com.android.systemui.statusbar.notification.NotificationUtils;
-import com.android.systemui.statusbar.notification.collection.EntryAdapter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationContentExtractor;
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiForceExpanded;
@@ -441,8 +440,12 @@
             NotificationRowContentBinderLogger logger) {
         return TraceUtils.trace("NotificationContentInflater.createRemoteViews", () -> {
             InflationProgress result = new InflationProgress();
+
+            // inflating the contracted view is the legacy invalidation trigger
+            boolean reinflating = (reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0;
             // create an image inflater
-            result.mRowImageInflater = RowImageInflater.newInstance(row.mImageModelIndex);
+            result.mRowImageInflater = RowImageInflater.newInstance(row.mImageModelIndex,
+                    reinflating);
 
             if ((reInflateFlags & FLAG_CONTENT_VIEW_CONTRACTED) != 0) {
                 logger.logAsyncTaskProgress(row.getLoggingKey(), "creating contracted remote view");
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
index 3586078..482b315 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/NotificationRowContentBinderImpl.kt
@@ -499,7 +499,10 @@
             logger.logAsyncTaskProgress(entry.logKey, "loading RON images")
             inflationProgress.rowImageInflater.loadImagesSynchronously(packageContext)
 
-            logger.logAsyncTaskProgress(entry.logKey, "getting row image resolver (on wrong thread!)")
+            logger.logAsyncTaskProgress(
+                entry.logKey,
+                "getting row image resolver (on wrong thread!)",
+            )
             val imageResolver = row.imageResolver
             // wait for image resolver to finish preloading
             logger.logAsyncTaskProgress(entry.logKey, "waiting for preloaded images")
@@ -685,13 +688,17 @@
             logger: NotificationRowContentBinderLogger,
         ): InflationProgress {
             val rowImageInflater =
-                RowImageInflater.newInstance(previousIndex = row.mImageModelIndex)
+                RowImageInflater.newInstance(
+                    previousIndex = row.mImageModelIndex,
+                    // inflating the contracted view is the legacy invalidation trigger
+                    reinflating = reInflateFlags and FLAG_CONTENT_VIEW_CONTRACTED != 0,
+                )
 
             val promotedContent =
                 if (PromotedNotificationContentModel.featureFlagEnabled()) {
                     logger.logAsyncTaskProgress(
                         entry.logKey,
-                        "extracting promoted notification content"
+                        "extracting promoted notification content",
                     )
                     val imageModelProvider = rowImageInflater.useForContentModel()
                     promotedNotificationContentExtractor
@@ -750,7 +757,7 @@
                 ) {
                     logger.logAsyncTaskProgress(
                         entry.logKey,
-                        "inflating public single line view model"
+                        "inflating public single line view model",
                     )
                     if (bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT) {
                         SingleLineViewInflater.inflateSingleLineViewModel(
@@ -852,18 +859,12 @@
                     } else null
                 val expanded =
                     if (reInflateFlags and FLAG_CONTENT_VIEW_EXPANDED != 0) {
-                        logger.logAsyncTaskProgress(
-                            row.loggingKey,
-                            "creating expanded remote view",
-                        )
+                        logger.logAsyncTaskProgress(row.loggingKey, "creating expanded remote view")
                         createExpandedView(builder, bindParams.isMinimized)
                     } else null
                 val headsUp =
                     if (reInflateFlags and FLAG_CONTENT_VIEW_HEADS_UP != 0) {
-                        logger.logAsyncTaskProgress(
-                            row.loggingKey,
-                            "creating heads up remote view",
-                        )
+                        logger.logAsyncTaskProgress(row.loggingKey, "creating heads up remote view")
                         val isHeadsUpCompact = headsUpStyleProvider.shouldApplyCompactStyle()
                         if (isHeadsUpCompact) {
                             builder.createCompactHeadsUpContentView()
@@ -873,10 +874,7 @@
                     } else null
                 val public =
                     if (reInflateFlags and FLAG_CONTENT_VIEW_PUBLIC != 0) {
-                        logger.logAsyncTaskProgress(
-                            row.loggingKey,
-                            "creating public remote view"
-                        )
+                        logger.logAsyncTaskProgress(row.loggingKey, "creating public remote view")
                         if (
                             LockscreenOtpRedaction.isEnabled &&
                                 bindParams.redactionType == REDACTION_TYPE_SENSITIVE_CONTENT
@@ -1142,7 +1140,7 @@
                             override fun setResultView(v: View) {
                                 logger.logAsyncTaskProgress(
                                     entry.logKey,
-                                    "group header view applied"
+                                    "group header view applied",
                                 )
                                 result.inflatedGroupHeaderView = v as NotificationHeaderView?
                             }
@@ -1198,7 +1196,7 @@
                         }
                     logger.logAsyncTaskProgress(
                         entry.logKey,
-                        "applying low priority group header view"
+                        "applying low priority group header view",
                     )
                     applyRemoteView(
                         inflationExecutor = inflationExecutor,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowImageInflater.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowImageInflater.kt
index 95ef60f..7bac17f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowImageInflater.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/RowImageInflater.kt
@@ -83,9 +83,9 @@
         inline fun featureFlagEnabled() = PromotedNotificationUiAod.isEnabled
 
         @JvmStatic
-        fun newInstance(previousIndex: ImageModelIndex?): RowImageInflater =
+        fun newInstance(previousIndex: ImageModelIndex?, reinflating: Boolean): RowImageInflater =
             if (featureFlagEnabled()) {
-                RowImageInflaterImpl(previousIndex)
+                RowImageInflaterImpl(previousIndex, reinflating)
             } else {
                 RowImageInflaterStub
             }
@@ -110,7 +110,8 @@
     override fun getNewImageIndex(): ImageModelIndex? = null
 }
 
-class RowImageInflaterImpl(private val previousIndex: ImageModelIndex?) : RowImageInflater {
+class RowImageInflaterImpl(private val previousIndex: ImageModelIndex?, val reinflating: Boolean) :
+    RowImageInflater {
     private val providedImages = mutableListOf<LazyImage>()
 
     /**
@@ -139,10 +140,15 @@
                     // ensure all entries are stored
                     providedImages.add(newImage)
                     // load the image result from the index into our new object
-                    previousIndex?.findImage(iconData, sizeClass, transform)?.let {
-                        // copy the result into our new object
-                        newImage.result = it
-                    }
+                    previousIndex
+                        // skip the cached image when we are "reinflating" to avoid stale content
+                        // being displayed from the same URI after the app updated the notif
+                        ?.takeUnless { reinflating }
+                        ?.findImage(iconData, sizeClass, transform)
+                        ?.let {
+                            // copy the result into our new object
+                            newImage.result = it
+                        }
                 }
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/BundleHeaderViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/BundleHeaderViewModel.kt
new file mode 100644
index 0000000..d02ae43
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/ui/viewmodel/BundleHeaderViewModel.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.row.ui.viewmodel
+
+import android.graphics.drawable.Drawable
+import android.view.View
+import androidx.compose.animation.core.tween
+import androidx.compose.material3.ExperimentalMaterial3ExpressiveApi
+import androidx.compose.material3.MotionScheme
+import androidx.compose.runtime.getValue
+import androidx.compose.runtime.mutableStateOf
+import androidx.compose.runtime.setValue
+import androidx.compose.ui.unit.dp
+import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
+import com.android.compose.animation.scene.SceneTransitionLayoutState
+import com.android.compose.animation.scene.transitions
+import com.android.systemui.notifications.ui.composable.row.BundleHeader
+import kotlinx.coroutines.CoroutineScope
+
+interface BundleHeaderViewModel {
+    val titleText: String
+    val numberOfChildren: Int?
+    val bundleIcon: Drawable?
+    val previewIcons: List<Drawable>
+
+    val state: SceneTransitionLayoutState
+
+    val hasUnreadMessages: Boolean
+    val backgroundDrawable: Drawable?
+
+    fun onHeaderClicked(scope: CoroutineScope)
+}
+
+class BundleHeaderViewModelImpl : BundleHeaderViewModel {
+    override var titleText by mutableStateOf("")
+    override var numberOfChildren by mutableStateOf<Int?>(1)
+    override var hasUnreadMessages by mutableStateOf(true)
+    override var bundleIcon by mutableStateOf<Drawable?>(null)
+    override var previewIcons by mutableStateOf(listOf<Drawable>())
+    override var backgroundDrawable by mutableStateOf<Drawable?>(null)
+
+    var onExpandClickListener: View.OnClickListener? = null
+
+    @OptIn(ExperimentalMaterial3ExpressiveApi::class)
+    override var state: MutableSceneTransitionLayoutState =
+        MutableSceneTransitionLayoutState(
+            BundleHeader.Scenes.Collapsed,
+            MotionScheme.standard(),
+            transitions {
+                from(BundleHeader.Scenes.Collapsed, to = BundleHeader.Scenes.Expanded) {
+                    spec = tween(500)
+                    translate(BundleHeader.Elements.PreviewIcon3, x = 32.dp)
+                    translate(BundleHeader.Elements.PreviewIcon2, x = 16.dp)
+                    fade(BundleHeader.Elements.PreviewIcon1)
+                    fade(BundleHeader.Elements.PreviewIcon2)
+                    fade(BundleHeader.Elements.PreviewIcon3)
+                }
+            },
+        )
+
+    override fun onHeaderClicked(scope: CoroutineScope) {
+        val targetScene =
+            when (state.currentScene) {
+                BundleHeader.Scenes.Collapsed -> BundleHeader.Scenes.Expanded
+                BundleHeader.Scenes.Expanded -> BundleHeader.Scenes.Collapsed
+                else -> error("Unknown Scene")
+            }
+        state.setTargetScene(targetScene, scope)
+
+        onExpandClickListener?.onClick(null)
+        hasUnreadMessages = false
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
index 4146a94..8176d2a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/row/wrapper/NotificationTemplateViewWrapper.java
@@ -211,14 +211,28 @@
             rightIconLP.setMarginEnd(horizontalMargin);
             mRightIcon.setLayoutParams(rightIconLP);
 
+            // if there is no title and topline view, there is nothing to adjust.
+            if (mNotificationTopLine == null && mTitle == null) {
+                return;
+            }
+
             // align top line view to start of the right icon.
             final int iconSize = mView.getResources().getDimensionPixelSize(
                 com.android.internal.R.dimen.notification_right_icon_size);
             final int marginEnd = 2 * horizontalMargin + iconSize;
-            mNotificationTopLine.setHeaderTextMarginEnd(marginEnd);
+            final boolean isTitleInTopLine;
+            // set margin end for the top line view if it exists
+            if (mNotificationTopLine != null) {
+                mNotificationTopLine.setHeaderTextMarginEnd(marginEnd);
+                isTitleInTopLine = mNotificationTopLine.isTitlePresent();
+            } else {
+                isTitleInTopLine = false;
+            }
 
+            // Margin is to be applied to the title only when it is in the body,
+            // but not in the title.
             // title has too much margin on the right, so we need to reduce it
-            if (mTitle != null) {
+            if (!isTitleInTopLine && mTitle != null) {
                 final ViewGroup.MarginLayoutParams titleLP =
                     (ViewGroup.MarginLayoutParams) mTitle.getLayoutParams();
                 titleLP.setMarginEnd(marginEnd);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationBundleUi.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationBundleUi.kt
index 7237231..37212a3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationBundleUi.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/shared/NotificationBundleUi.kt
@@ -49,7 +49,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
@@ -57,4 +59,4 @@
      */
     @JvmStatic
     inline fun assertInLegacyMode() = RefactorFlagUtils.assertInLegacyMode(isEnabled, FLAG_NAME)
-}
\ No newline at end of file
+}
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 e830d18..315d37e 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
@@ -39,9 +39,11 @@
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
+import androidx.compose.ui.platform.ComposeView;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.widget.NotificationExpandButton;
+import com.android.systemui.notifications.ui.composable.row.BundleHeaderKt;
 import com.android.systemui.res.R;
 import com.android.systemui.scene.shared.flag.SceneContainerFlag;
 import com.android.systemui.statusbar.CrossFadeHelper;
@@ -58,6 +60,7 @@
 import com.android.systemui.statusbar.notification.row.HybridNotificationView;
 import com.android.systemui.statusbar.notification.row.shared.AsyncGroupHeaderViewInflation;
 import com.android.systemui.statusbar.notification.row.shared.AsyncHybridViewInflation;
+import com.android.systemui.statusbar.notification.row.ui.viewmodel.BundleHeaderViewModelImpl;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper;
 import com.android.systemui.statusbar.notification.row.wrapper.NotificationViewWrapper;
 import com.android.systemui.statusbar.notification.shared.NotificationBundleUi;
@@ -119,6 +122,13 @@
      */
     private boolean mEnableShadowOnChildNotifications;
 
+    /**
+     * This view is only set when this NCC is a bundle. If this view is set, all other header
+     * view variants have to be null.
+     */
+    private ComposeView mBundleHeaderView;
+    private BundleHeaderViewModelImpl mBundleHeaderViewModel;
+
     private NotificationHeaderView mGroupHeader;
     private NotificationHeaderViewWrapper mGroupHeaderWrapper;
     private NotificationHeaderView mMinimizedGroupHeader;
@@ -189,6 +199,9 @@
                     R.dimen.notification_children_container_top_padding);
             mHeaderHeight = mCollapsedHeaderMargin + mAdditionalExpandedHeaderMargin;
         }
+        if (mBundleHeaderView != null) {
+            initBundleDimens();
+        }
         mCollapsedBottomPadding = res.getDimensionPixelOffset(
                 R.dimen.notification_children_collapsed_bottom_padding);
         mEnableShadowOnChildNotifications =
@@ -244,6 +257,10 @@
                     mMinimizedGroupHeader.getMeasuredWidth(),
                     mMinimizedGroupHeader.getMeasuredHeight());
         }
+        if (mBundleHeaderView != null) {
+            mBundleHeaderView.layout(0, 0, mBundleHeaderView.getMeasuredWidth(),
+                    mBundleHeaderView.getMeasuredHeight());
+        }
     }
 
     @Override
@@ -295,6 +312,9 @@
         if (mMinimizedGroupHeader != null) {
             mMinimizedGroupHeader.measure(widthMeasureSpec, headerHeightSpec);
         }
+        if (mBundleHeaderView != null) {
+            mBundleHeaderView.measure(widthMeasureSpec, headerHeightSpec);
+        }
 
         setMeasuredDimension(width, height);
         Trace.endSection();
@@ -489,6 +509,28 @@
     }
 
     /**
+     * Init the bundle header view. The ComposeView is initialized within with the passed viewModel.
+     * This can only be init once and not in conjunction with any other header view.
+     */
+    public void initBundleHeader(@NonNull BundleHeaderViewModelImpl viewModel) {
+        if (NotificationBundleUi.isUnexpectedlyInLegacyMode()) return;
+        if (mBundleHeaderView != null) return;
+        initBundleDimens();
+
+        mBundleHeaderViewModel = viewModel;
+        mBundleHeaderView = BundleHeaderKt.createComposeView(mBundleHeaderViewModel, getContext());
+        addView(mBundleHeaderView);
+        invalidate();
+    }
+
+    private void initBundleDimens() {
+        NotificationBundleUi.unsafeAssertInNewMode();
+        mCollapsedHeaderMargin = mHeaderHeight;
+        mAdditionalExpandedHeaderMargin = 0;
+        mCollapsedBottomPadding = 0;
+    }
+
+    /**
      * Set the group header view
      * @param headerView view to set
      * @param onClickListener OnClickListener of the header view
@@ -1311,6 +1353,17 @@
                 mGroupHeader.setHeaderBackgroundDrawable(null);
             }
         }
+        if (mBundleHeaderView != null) {
+            if (expanded) {
+                ColorDrawable cd = new ColorDrawable();
+                cd.setColor(mContainingNotification.calculateBgColor());
+                // TODO(b/389839492): The backgroundDrawable needs an outline like in the original:
+                //  setOutlineProvider(mProvider);
+                mBundleHeaderViewModel.setBackgroundDrawable(cd);
+            } else {
+                mBundleHeaderViewModel.setBackgroundDrawable(null);
+            }
+        }
     }
 
     public int getMaxContentHeight() {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 1a17b8e..c2c271b 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -104,6 +104,7 @@
 import com.android.systemui.shade.TouchLogger;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarState;
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.headsup.shared.StatusBarNoHunBehavior;
 import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.FakeShadowView;
@@ -117,6 +118,7 @@
 import com.android.systemui.statusbar.notification.emptyshade.shared.ModesEmptyShadeFix;
 import com.android.systemui.statusbar.notification.emptyshade.ui.view.EmptyShadeView;
 import com.android.systemui.statusbar.notification.footer.ui.view.FooterView;
+import com.android.systemui.statusbar.notification.headsup.HeadsUpAnimationEvent;
 import com.android.systemui.statusbar.notification.headsup.HeadsUpAnimator;
 import com.android.systemui.statusbar.notification.headsup.HeadsUpTouchHelper;
 import com.android.systemui.statusbar.notification.headsup.HeadsUpUtil;
@@ -139,6 +141,7 @@
 import com.android.systemui.statusbar.phone.HeadsUpAppearanceController;
 import com.android.systemui.statusbar.policy.ScrollAdapter;
 import com.android.systemui.statusbar.policy.SplitShadeStateController;
+import com.android.systemui.statusbar.ui.SystemBarUtilsProxy;
 import com.android.systemui.util.Assert;
 import com.android.systemui.util.ColorUtilKt;
 import com.android.systemui.util.DumpUtilsKt;
@@ -351,10 +354,11 @@
     private final int[] mTempInt2 = new int[2];
     private final HashSet<Runnable> mAnimationFinishedRunnables = new HashSet<>();
     private final HashSet<ExpandableView> mClearTransientViewsWhenFinished = new HashSet<>();
-    private final HashSet<Pair<ExpandableNotificationRow, Boolean>> mHeadsUpChangeAnimations
-            = new HashSet<>();
+    private final Map<ExpandableNotificationRow, HeadsUpAnimationEvent> mHeadsUpChangeAnimations
+            = new HashMap<>();
     private boolean mForceNoOverlappingRendering;
-    private final ArrayList<Pair<ExpandableNotificationRow, Boolean>> mTmpList = new ArrayList<>();
+    private final ArrayList<ExpandableNotificationRow> mTmpHeadsUpChangeAnimations =
+            new ArrayList<>();
     private boolean mAnimationRunning;
     private final ViewTreeObserver.OnPreDrawListener mRunningAnimationUpdater
             = new ViewTreeObserver.OnPreDrawListener() {
@@ -673,7 +677,7 @@
         mExpandHelper.setScrollAdapter(mScrollAdapter);
 
         if (NotificationsHunSharedAnimationValues.isEnabled()) {
-            mHeadsUpAnimator = new HeadsUpAnimator(context);
+            mHeadsUpAnimator = new HeadsUpAnimator(context, /* systemBarUtilsProxy= */ null);
         } else {
             mHeadsUpAnimator = null;
         }
@@ -1286,7 +1290,9 @@
     @Override
     public void setHeadsUpBottom(float headsUpBottom) {
         if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
-        if (mAmbientState.getHeadsUpBottom() != headsUpBottom) {
+        if (NotificationsHunSharedAnimationValues.isEnabled()) {
+            mHeadsUpAnimator.setHeadsUpAppearHeightBottom(Math.round(headsUpBottom));
+        } else if (mAmbientState.getHeadsUpBottom() != headsUpBottom) {
             mAmbientState.setHeadsUpBottom(headsUpBottom);
             mStateAnimator.setHeadsUpAppearHeightBottom(Math.round(headsUpBottom));
         }
@@ -3074,20 +3080,20 @@
      */
     private boolean removeRemovedChildFromHeadsUpChangeAnimations(View child) {
         boolean hasAddEvent = false;
-        for (Pair<ExpandableNotificationRow, Boolean> eventPair : mHeadsUpChangeAnimations) {
-            ExpandableNotificationRow row = eventPair.first;
-            boolean isHeadsUp = eventPair.second;
+        for (HeadsUpAnimationEvent event : mHeadsUpChangeAnimations.values()) {
+            ExpandableNotificationRow row = event.getRow();
+            boolean isHeadsUp = event.isHeadsUpAppearance();
             if (child == row) {
-                mTmpList.add(eventPair);
+                mTmpHeadsUpChangeAnimations.add(event.getRow());
                 hasAddEvent |= isHeadsUp;
             }
         }
         if (hasAddEvent) {
             // This child was just added lets remove all events.
-            mHeadsUpChangeAnimations.removeAll(mTmpList);
+            mTmpHeadsUpChangeAnimations.forEach((row) -> mHeadsUpChangeAnimations.remove(row));
             ((ExpandableNotificationRow) child).setHeadsUpAnimatingAway(false);
         }
-        mTmpList.clear();
+        mTmpHeadsUpChangeAnimations.clear();
         return hasAddEvent && mAddedHeadsUpChildren.contains(child);
     }
 
@@ -3373,9 +3379,9 @@
     }
 
     private void generateHeadsUpAnimationEvents() {
-        for (Pair<ExpandableNotificationRow, Boolean> eventPair : mHeadsUpChangeAnimations) {
-            ExpandableNotificationRow row = eventPair.first;
-            boolean isHeadsUp = eventPair.second;
+        for (HeadsUpAnimationEvent headsUpEvent : mHeadsUpChangeAnimations.values()) {
+            ExpandableNotificationRow row = headsUpEvent.getRow();
+            boolean isHeadsUp = headsUpEvent.isHeadsUpAppearance();
             if (isHeadsUp != row.isHeadsUp()) {
                 // For cases where we have a heads up showing and appearing again we shouldn't
                 // do the animations at all.
@@ -3433,6 +3439,10 @@
             }
             AnimationEvent event = new AnimationEvent(row, type);
             event.headsUpFromBottom = onBottom;
+
+            boolean hasStatusBarChip =
+                    StatusBarNotifChips.isEnabled() && headsUpEvent.getHasStatusBarChip();
+            event.headsUpHasStatusBarChip = hasStatusBarChip;
             // TODO(b/283084712) remove this and update the HUN filters at creation
             event.filter.animateHeight = false;
             mAnimationEvents.add(event);
@@ -5068,10 +5078,11 @@
         mAnimationFinishedRunnables.add(runnable);
     }
 
-    public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
+    public void generateHeadsUpAnimation(
+            NotificationEntry entry, boolean isHeadsUp, boolean hasStatusBarChip) {
         SceneContainerFlag.assertInLegacyMode();
         ExpandableNotificationRow row = entry.getHeadsUpAnimationView();
-        generateHeadsUpAnimation(row, isHeadsUp);
+        generateHeadsUpAnimation(row, isHeadsUp, hasStatusBarChip);
     }
 
     /**
@@ -5080,8 +5091,11 @@
      *
      * @param row to animate
      * @param isHeadsUp true for appear, false for disappear animations
+     * @param hasStatusBarChip true if the status bar is currently displaying a chip for the given
+     *                         notification
      */
-    public void generateHeadsUpAnimation(ExpandableNotificationRow row, boolean isHeadsUp) {
+    public void generateHeadsUpAnimation(
+            ExpandableNotificationRow row, boolean isHeadsUp, boolean hasStatusBarChip) {
         boolean addAnimation =
                 mAnimationsEnabled && (isHeadsUp || mHeadsUpGoingAwayAnimationsAllowed);
         if (NotificationThrottleHun.isEnabled()) {
@@ -5096,19 +5110,26 @@
                             : " isSeenInShade=" + row.getEntry().isSeenInShade()
                                     + " row=" + row.getKey())
                     + " mIsExpanded=" + mIsExpanded
-                    + " isHeadsUp=" + isHeadsUp);
+                    + " isHeadsUp=" + isHeadsUp
+                    + " hasStatusBarChip=" + hasStatusBarChip);
         }
+
         if (addAnimation) {
             // If we're hiding a HUN we just started showing THIS FRAME, then remove that event,
             // and do not add the disappear event either.
-            if (!isHeadsUp && mHeadsUpChangeAnimations.remove(new Pair<>(row, true))) {
+            boolean showingHunThisFrame =
+                    mHeadsUpChangeAnimations.containsKey(row)
+                            && mHeadsUpChangeAnimations.get(row).isHeadsUpAppearance();
+            if (!isHeadsUp && showingHunThisFrame) {
+                mHeadsUpChangeAnimations.remove(row);
                 if (SPEW) {
                     Log.v(TAG, "generateHeadsUpAnimation: previous hun appear animation cancelled");
                 }
                 logHunAnimationSkipped(row, "previous hun appear animation cancelled");
                 return;
             }
-            mHeadsUpChangeAnimations.add(new Pair<>(row, isHeadsUp));
+            mHeadsUpChangeAnimations.put(
+                    row, new HeadsUpAnimationEvent(row, isHeadsUp, hasStatusBarChip));
             mNeedsAnimation = true;
             if (!mIsExpanded && !mWillExpand && !isHeadsUp) {
                 row.setHeadsUpAnimatingAway(true);
@@ -5116,6 +5137,9 @@
                     setHeadsUpAnimatingAway(true);
                 }
             }
+            if (StatusBarNotifChips.isEnabled()) {
+                row.setHasStatusBarChipDuringHeadsUpAnimation(hasStatusBarChip);
+            }
             requestChildrenUpdate();
         }
     }
@@ -6469,30 +6493,50 @@
         static AnimationFilter[] FILTERS = new AnimationFilter[]{
 
                 // ANIMATION_TYPE_ADD
-                new AnimationFilter()
-                        .animateAlpha()
-                        .animateHeight()
-                        .animateTopInset()
-                        .animateY()
-                        .animateZ()
-                        .hasDelays(),
+                physicalNotificationMovement()
+                        ? new AnimationFilter()
+                                .animateAlpha()
+                                .animateHeight()
+                                .animateTopInset()
+                                .animateY()
+                                .animateZ()
+                        : new AnimationFilter()
+                                .animateAlpha()
+                                .animateHeight()
+                                .animateTopInset()
+                                .animateY()
+                                .animateZ()
+                                .hasDelays(),
 
                 // ANIMATION_TYPE_REMOVE
-                new AnimationFilter()
-                        .animateAlpha()
-                        .animateHeight()
-                        .animateTopInset()
-                        .animateY()
-                        .animateZ()
-                        .hasDelays(),
+                physicalNotificationMovement()
+                        ? new AnimationFilter()
+                                .animateAlpha()
+                                .animateHeight()
+                                .animateTopInset()
+                                .animateY()
+                                .animateZ()
+                        : new AnimationFilter()
+                                .animateAlpha()
+                                .animateHeight()
+                                .animateTopInset()
+                                .animateY()
+                                .animateZ()
+                                .hasDelays(),
 
                 // ANIMATION_TYPE_REMOVE_SWIPED_OUT
-                new AnimationFilter()
-                        .animateHeight()
-                        .animateTopInset()
-                        .animateY()
-                        .animateZ()
-                        .hasDelays(),
+                physicalNotificationMovement()
+                        ? new AnimationFilter()
+                                .animateHeight()
+                                .animateTopInset()
+                                .animateY()
+                                .animateZ()
+                        : new AnimationFilter()
+                                .animateHeight()
+                                .animateTopInset()
+                                .animateY()
+                                .animateZ()
+                                .hasDelays(),
 
                 // ANIMATION_TYPE_TOP_PADDING_CHANGED
                 new AnimationFilter()
@@ -6682,6 +6726,7 @@
         final long length;
         View viewAfterChangingView;
         boolean headsUpFromBottom;
+        boolean headsUpHasStatusBarChip;
 
         AnimationEvent(ExpandableView view, int type) {
             this(view, type, LENGTHS[type]);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
index 124e6f5..bb3abc1 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java
@@ -92,6 +92,7 @@
 import com.android.systemui.statusbar.RemoteInputController;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.notification.ColorUpdateLogger;
 import com.android.systemui.statusbar.notification.DynamicPrivacyController;
 import com.android.systemui.statusbar.notification.LaunchAnimationParameters;
@@ -325,6 +326,14 @@
      */
     private float mMaxAlphaForGlanceableHub = 1.0f;
 
+    /**
+     * A list of keys for the visible status bar chips.
+     *
+     * Note that this list can contain both notification keys, as well as keys for other types of
+     * chips like screen recording.
+     */
+    private List<String> mVisibleStatusBarChipKeys = new ArrayList<>();
+
     private final NotificationListViewBinder mViewBinder;
 
     private void updateResources() {
@@ -1580,8 +1589,16 @@
         return mView.getFirstChildNotGone();
     }
 
+    /** Sets the list of keys that have currently visible status bar chips. */
+    public void updateStatusBarChipKeys(List<String> visibleStatusBarChipKeys) {
+        mVisibleStatusBarChipKeys = visibleStatusBarChipKeys;
+    }
+
     public void generateHeadsUpAnimation(NotificationEntry entry, boolean isHeadsUp) {
-        mView.generateHeadsUpAnimation(entry, isHeadsUp);
+        boolean hasStatusBarChip =
+                StatusBarNotifChips.isEnabled()
+                        && mVisibleStatusBarChipKeys.contains(entry.getKey());
+        mView.generateHeadsUpAnimation(entry, isHeadsUp, hasStatusBarChip);
     }
 
     public void setMaxTopPadding(int padding) {
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 4e91680..fcb63df 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
@@ -409,12 +409,12 @@
 
             if (counter != null) {
                 if (NotificationBundleUi.isEnabled) {
-                    val entry = (currentNotification as? ExpandableNotificationRow)?.entry
-                    counter.incrementForBucket(entry?.bucket)
-                } else {
                     val entryAdapter =
                         (currentNotification as? ExpandableNotificationRow)?.entryAdapter
                     counter.incrementForBucket(entryAdapter?.sectionBucket)
+                } else {
+                    val entry = (currentNotification as? ExpandableNotificationRow)?.entry
+                    counter.incrementForBucket(entry?.bucket)
                 }
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index 4effb76..d23a4c6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -1059,7 +1059,9 @@
                             shouldHunAppearFromBottom(ambientState, childState);
                     if (NotificationsHunSharedAnimationValues.isEnabled()) {
                         int yTranslation =
-                                mHeadsUpAnimator.getHeadsUpYTranslation(shouldHunAppearFromBottom);
+                                mHeadsUpAnimator.getHeadsUpYTranslation(
+                                        shouldHunAppearFromBottom,
+                                        row.hasStatusBarChipDuringHeadsUpAnimation());
                         childState.setYTranslation(yTranslation);
                     } else {
                         if (shouldHunAppearFromBottom) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
index 19abfa8..5414318 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackStateAnimator.java
@@ -38,6 +38,7 @@
 import com.android.systemui.res.R;
 import com.android.systemui.shared.clocks.AnimatableClockView;
 import com.android.systemui.statusbar.NotificationShelf;
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.notification.PhysicsPropertyAnimator;
 import com.android.systemui.statusbar.notification.headsup.HeadsUpAnimator;
 import com.android.systemui.statusbar.notification.headsup.NotificationsHunSharedAnimationValues;
@@ -289,6 +290,10 @@
             long delayPerElement = ANIMATION_DELAY_PER_ELEMENT_INTERRUPTING;
             switch (event.animationType) {
                 case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_ADD: {
+                    if (physicalNotificationMovement()) {
+                        // We don't want any delays when adding anymore
+                        continue;
+                    }
                     int ownIndex = viewState.notGoneIndex;
                     int changingIndex =
                             ((ExpandableView) (event.mChangingView)).getViewState().notGoneIndex;
@@ -302,6 +307,10 @@
                 case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE_SWIPED_OUT:
                     delayPerElement = ANIMATION_DELAY_PER_ELEMENT_MANUAL;
                 case NotificationStackScrollLayout.AnimationEvent.ANIMATION_TYPE_REMOVE: {
+                    if (physicalNotificationMovement()) {
+                        // We don't want any delays when removing anymore
+                        continue;
+                    }
                     int ownIndex = viewState.notGoneIndex;
                     boolean noNextView = event.viewAfterChangingView == null;
                     ExpandableView viewAfterChangingView = noNextView
@@ -552,7 +561,9 @@
                 mHeadsUpAppearChildren.add(changingView);
 
                 mTmpState.copyFrom(changingView.getViewState());
-                mTmpState.setYTranslation(getHeadsUpYTranslationStart(event.headsUpFromBottom));
+                mTmpState.setYTranslation(
+                        getHeadsUpYTranslationStart(
+                                event.headsUpFromBottom, event.headsUpHasStatusBarChip));
                 // set the height and the initial position
                 mTmpState.applyToView(changingView);
                 mAnimationProperties.setCustomInterpolator(View.TRANSLATION_Y,
@@ -664,7 +675,9 @@
                     // StackScrollAlgorithm cannot find this view because it has been removed
                     // from the NSSL. To correctly translate the view to the top or bottom of
                     // the screen (where it animated from), we need to update its translation.
-                    mTmpState.setYTranslation(getHeadsUpYTranslationStart(event.headsUpFromBottom));
+                    mTmpState.setYTranslation(
+                            getHeadsUpYTranslationStart(
+                                    event.headsUpFromBottom, event.headsUpHasStatusBarChip));
                     endRunnable = changingView::removeFromTransientContainer;
                 }
 
@@ -735,9 +748,9 @@
         return needsCustomAnimation;
     }
 
-    private float getHeadsUpYTranslationStart(boolean headsUpFromBottom) {
+    private float getHeadsUpYTranslationStart(boolean headsUpFromBottom, boolean hasStatusBarChip) {
         if (NotificationsHunSharedAnimationValues.isEnabled()) {
-            return mHeadsUpAnimator.getHeadsUpYTranslation(headsUpFromBottom);
+            return mHeadsUpAnimator.getHeadsUpYTranslation(headsUpFromBottom, hasStatusBarChip);
         }
 
         if (headsUpFromBottom) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
index 10b665d..facb894 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationListViewBinder.kt
@@ -33,6 +33,7 @@
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.shade.ShadeDisplayAware
 import com.android.systemui.statusbar.NotificationShelf
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.notification.NotificationActivityStarter
 import com.android.systemui.statusbar.notification.collection.render.SectionHeaderController
 import com.android.systemui.statusbar.notification.dagger.SilentHeader
@@ -133,6 +134,14 @@
                     }
                 }
 
+                if (StatusBarNotifChips.isEnabled) {
+                    launch {
+                        viewModel.visibleStatusBarChipKeys.collect { keys ->
+                            viewController.updateStatusBarChipKeys(keys)
+                        }
+                    }
+                }
+
                 launch { bindLogger(view) }
             }
         }
@@ -231,7 +240,7 @@
         emptyShadeViewModel: EmptyShadeViewModel,
         parentView: NotificationStackScrollLayout,
     ) {
-        ModesEmptyShadeFix.assertInNewMode()
+        ModesEmptyShadeFix.unsafeAssertInNewMode()
         // The empty shade needs to be re-inflated every time the theme or the font size
         // changes.
         configuration
@@ -269,7 +278,7 @@
         emptyShadeView: EmptyShadeView,
         emptyShadeViewModel: EmptyShadeViewModel,
     ): Unit = coroutineScope {
-        ModesEmptyShadeFix.assertInNewMode()
+        ModesEmptyShadeFix.unsafeAssertInNewMode()
         launch {
             emptyShadeView.repeatWhenAttachedToWindow {
                 EmptyShadeViewBinder.bind(
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
index 5ed1889..c1eb70e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModel.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel
 import com.android.systemui.statusbar.domain.interactor.RemoteInputInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.ActiveNotificationsInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.HeadsUpNotificationInteractor
@@ -56,6 +57,7 @@
 constructor(
     val shelf: NotificationShelfViewModel,
     val hideListViewModel: HideListViewModel,
+    val ongoingActivityChipsViewModel: OngoingActivityChipsViewModel,
     val footerViewModelFactory: FooterViewModel.Factory,
     val emptyShadeViewModelFactory: EmptyShadeViewModel.Factory,
     val logger: Optional<NotificationLoggerViewModel>,
@@ -364,6 +366,14 @@
         }
     }
 
+    /**
+     * A list of keys for the visible status bar chips.
+     *
+     * Note that this list can contain both notification keys, as well as keys for other types of
+     * chips like screen recording.
+     */
+    val visibleStatusBarChipKeys = ongoingActivityChipsViewModel.visibleChipKeys
+
     // TODO(b/325936094) use it for the text displayed in the StatusBar
     fun headsUpRow(key: HeadsUpRowKey): HeadsUpRowViewModel =
         HeadsUpRowViewModel(headsUpNotificationInteractor.headsUpRow(key))
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 a277597..c1aa5f1 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
@@ -266,7 +266,7 @@
         combine(shadeModeInteractor.shadeMode, shadeInteractor.qsExpansion) { shadeMode, qsExpansion
                 ->
                 when (shadeMode) {
-                    is ShadeMode.Dual -> false
+                    is ShadeMode.Dual,
                     is ShadeMode.Split -> true
                     is ShadeMode.Single -> qsExpansion < 0.5f
                 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt
index feb7409..bc53314 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinder.kt
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar.notification.ui.viewbinder
 
+import com.android.app.tracing.coroutines.launchTraced as launch
+import com.android.systemui.statusbar.chips.ui.viewmodel.OngoingActivityChipsViewModel
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.shared.HeadsUpRowKey
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
@@ -27,20 +29,29 @@
 import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
-import com.android.app.tracing.coroutines.launchTraced as launch
 
 class HeadsUpNotificationViewBinder
 @Inject
-constructor(private val viewModel: NotificationListViewModel) {
+constructor(
+    private val viewModel: NotificationListViewModel,
+    private val ongoingActivityChipsViewModel: OngoingActivityChipsViewModel,
+) {
     suspend fun bindHeadsUpNotifications(parentView: NotificationStackScrollLayout): Unit =
         coroutineScope {
             launch {
                 var previousKeys = emptySet<HeadsUpRowKey>()
-                combine(viewModel.pinnedHeadsUpRowKeys, viewModel.activeHeadsUpRowKeys, ::Pair)
+                combine(
+                        viewModel.pinnedHeadsUpRowKeys,
+                        viewModel.activeHeadsUpRowKeys,
+                        ongoingActivityChipsViewModel.visibleChipKeys,
+                        ::Triple,
+                    )
                     .sample(viewModel.headsUpAnimationsEnabled, ::Pair)
                     .collect { (newKeys, animationsEnabled) ->
                         val pinned = newKeys.first
                         val all = newKeys.second
+                        val statusBarChips: List<String> = newKeys.third
+
                         val added = all.union(pinned) - previousKeys
                         val removed = previousKeys - pinned
                         previousKeys = pinned
@@ -48,15 +59,23 @@
 
                         if (animationsEnabled) {
                             added.forEach { key ->
+                                val row = obtainView(key)
+                                val hasStatusBarChip = statusBarChips.contains(row.entry.key)
                                 parentView.generateHeadsUpAnimation(
-                                    obtainView(key),
+                                    row,
                                     /* isHeadsUp = */ true,
+                                    hasStatusBarChip,
                                 )
                             }
                             removed.forEach { key ->
                                 val row = obtainView(key)
+                                val hasStatusBarChip = statusBarChips.contains(row.entry.key)
                                 if (!parentView.isBeingDragged()) {
-                                    parentView.generateHeadsUpAnimation(row, /* isHeadsUp= */ false)
+                                    parentView.generateHeadsUpAnimation(
+                                        row,
+                                        /* isHeadsUp= */ false,
+                                        hasStatusBarChip,
+                                    )
                                 }
                                 row.markHeadsUpSeen()
                             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
index 2ae38dd4..616bab6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/AutoHideControllerStore.kt
@@ -22,9 +22,9 @@
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
 import com.android.systemui.display.data.repository.PerDisplayStore
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.display.data.repository.SingleDisplayStore
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
+import com.android.systemui.statusbar.data.repository.StatusBarPerDisplayStoreImpl
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 
@@ -41,10 +41,13 @@
     private val autoHideControllerFactory: AutoHideControllerImpl.Factory,
 ) :
     AutoHideControllerStore,
-    PerDisplayStoreImpl<AutoHideController>(backgroundApplicationScope, displayRepository) {
+    StatusBarPerDisplayStoreImpl<AutoHideController>(
+        backgroundApplicationScope,
+        displayRepository,
+    ) {
 
     init {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
     }
 
     override fun createInstanceForDisplay(displayId: Int): AutoHideController? {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index face1c7..fc721bf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -109,6 +109,7 @@
 import com.android.systemui.CoreStartable;
 import com.android.systemui.DejankUtils;
 import com.android.systemui.EventLogTags;
+import com.android.systemui.Flags;
 import com.android.systemui.InitController;
 import com.android.systemui.Prefs;
 import com.android.systemui.accessibility.floatingmenu.AccessibilityFloatingMenuController;
@@ -3183,12 +3184,27 @@
             new ActivityTransitionAnimator.Listener() {
                 @Override
                 public void onTransitionAnimationStart() {
-                    mKeyguardViewMediator.setBlursDisabledForAppLaunch(true);
+                    if (!Flags.notificationShadeBlur() || !Flags.moveTransitionAnimationLayer()) {
+                        mKeyguardViewMediator.setBlursDisabledForAppLaunch(true);
+                    }
+                }
+
+                @Override
+                public void onTransitionAnimationProgress(float linearProgress) {
+                    if (Flags.notificationShadeBlur() && Flags.moveTransitionAnimationLayer()) {
+                        mNotificationShadeDepthControllerLazy.get()
+                                .onTransitionAnimationProgress(linearProgress);
+                    }
                 }
 
                 @Override
                 public void onTransitionAnimationEnd() {
-                    mKeyguardViewMediator.setBlursDisabledForAppLaunch(false);
+                    if (Flags.notificationShadeBlur() && Flags.moveTransitionAnimationLayer()) {
+                        mNotificationShadeDepthControllerLazy.get()
+                                .onTransitionAnimationEnd();
+                    } else {
+                        mKeyguardViewMediator.setBlursDisabledForAppLaunch(false);
+                    }
                 }
             };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
index 323b7d8..ba55700 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/dagger/StatusBarPhoneModule.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.core.CommandQueueInitializer
 import com.android.systemui.statusbar.core.MultiDisplayStatusBarInitializerStore
+import com.android.systemui.statusbar.core.MultiDisplayStatusBarOrchestratorStore
 import com.android.systemui.statusbar.core.MultiDisplayStatusBarStarter
 import com.android.systemui.statusbar.core.SingleDisplayStatusBarInitializerStore
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
@@ -197,5 +198,19 @@
                 CoreStartable.NOP
             }
         }
+
+        @Provides
+        @SysUISingleton
+        @IntoMap
+        @ClassKey(MultiDisplayStatusBarOrchestratorStore::class)
+        fun orchestratorStoreAsCoreStartable(
+            multiDisplayLazy: Lazy<MultiDisplayStatusBarOrchestratorStore>
+        ): CoreStartable {
+            return if (StatusBarConnectedDisplays.isEnabled) {
+                multiDisplayLazy.get()
+            } else {
+                CoreStartable.NOP
+            }
+        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
index c541cff..d8d6979 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/fragment/CollapsedStatusBarFragment.java
@@ -875,7 +875,7 @@
     }
 
     private void showSecondaryOngoingActivityChip(boolean animate) {
-        StatusBarNotifChips.assertInNewMode();
+        StatusBarNotifChips.unsafeAssertInNewMode();
         StatusBarRootModernization.assertInLegacyMode();
         animateShow(mSecondaryOngoingActivityChip, animate);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt
index b77e8f2..0ac8717 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/StatusBarChipsModernization.kt
@@ -52,7 +52,9 @@
      * the flag is not enabled to ensure that the refactor author catches issues in testing.
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt
index d53cbab..342adc6 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractor.kt
@@ -65,12 +65,12 @@
      */
     val batteryAttributionType =
         combine(isCharging, powerSave, isBatteryDefenderEnabled) { charging, powerSave, defend ->
-            if (charging) {
-                BatteryAttributionModel.Charging
-            } else if (powerSave) {
+            if (powerSave) {
                 BatteryAttributionModel.PowerSave
             } else if (defend) {
                 BatteryAttributionModel.Defend
+            } else if (charging) {
+                BatteryAttributionModel.Charging
             } else {
                 null
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
index c71162a..2952850 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/dagger/StatusBarPipelineModule.kt
@@ -18,7 +18,9 @@
 
 import android.net.wifi.WifiManager
 import com.android.systemui.CoreStartable
+import com.android.systemui.Flags
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.kairos.ExperimentalKairosApi
 import com.android.systemui.log.LogBuffer
 import com.android.systemui.log.LogBufferFactory
 import com.android.systemui.log.table.TableLogBuffer
@@ -35,9 +37,15 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepositoryImpl
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryKairosAdapter
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileRepositorySwitcher
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileRepositorySwitcherKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoModeMobileConnectionDataSourceKairosImpl
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionRepositoryKairosFactoryImpl
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryKairosImpl
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractor
 import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorImpl
+import com.android.systemui.statusbar.pipeline.mobile.domain.interactor.MobileIconsInteractorKairosImpl
 import com.android.systemui.statusbar.pipeline.mobile.ui.MobileUiAdapter
 import com.android.systemui.statusbar.pipeline.mobile.ui.viewmodel.MobileIconsViewModel
 import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
@@ -74,9 +82,20 @@
 import dagger.multibindings.IntoMap
 import java.util.function.Supplier
 import javax.inject.Named
+import javax.inject.Provider
 import kotlinx.coroutines.flow.Flow
 
-@Module
+@OptIn(ExperimentalKairosApi::class)
+@Module(
+    includes =
+        [
+            DemoModeMobileConnectionDataSourceKairosImpl.Module::class,
+            MobileRepositorySwitcherKairos.Module::class,
+            MobileConnectionsRepositoryKairosImpl.Module::class,
+            MobileConnectionRepositoryKairosFactoryImpl.Module::class,
+            MobileConnectionsRepositoryKairosAdapter.Module::class,
+        ]
+)
 abstract class StatusBarPipelineModule {
     @Binds
     abstract fun airplaneModeRepository(impl: AirplaneModeRepositoryImpl): AirplaneModeRepository
@@ -117,11 +136,6 @@
 
     @Binds abstract fun wifiInteractor(impl: WifiInteractorImpl): WifiInteractor
 
-    @Binds
-    abstract fun mobileConnectionsRepository(
-        impl: MobileRepositorySwitcher
-    ): MobileConnectionsRepository
-
     @Binds abstract fun userSetupRepository(impl: UserSetupRepositoryImpl): UserSetupRepository
 
     @Binds abstract fun mobileMappingsProxy(impl: MobileMappingsProxyImpl): MobileMappingsProxy
@@ -135,9 +149,6 @@
     ): SubscriptionManagerProxy
 
     @Binds
-    abstract fun mobileIconsInteractor(impl: MobileIconsInteractorImpl): MobileIconsInteractor
-
-    @Binds
     @IntoMap
     @ClassKey(MobileUiAdapter::class)
     abstract fun bindFeature(impl: MobileUiAdapter): CoreStartable
@@ -158,6 +169,30 @@
     companion object {
 
         @Provides
+        fun mobileIconsInteractor(
+            impl: Provider<MobileIconsInteractorImpl>,
+            kairosImpl: Provider<MobileIconsInteractorKairosImpl>,
+        ): MobileIconsInteractor {
+            return if (Flags.statusBarMobileIconKairos()) {
+                kairosImpl.get()
+            } else {
+                impl.get()
+            }
+        }
+
+        @Provides
+        fun mobileConnectionsRepository(
+            impl: Provider<MobileRepositorySwitcher>,
+            kairosImpl: Provider<MobileConnectionsRepositoryKairosAdapter>,
+        ): MobileConnectionsRepository {
+            return if (Flags.statusBarMobileIconKairos()) {
+                kairosImpl.get()
+            } else {
+                impl.get()
+            }
+        }
+
+        @Provides
         @SysUISingleton
         fun provideRealWifiRepository(
             wifiManager: WifiManager?,
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ethernet/shared/StatusBarSignalPolicyRefactorEthernet.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ethernet/shared/StatusBarSignalPolicyRefactorEthernet.kt
index 48747df..b2d314c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ethernet/shared/StatusBarSignalPolicyRefactorEthernet.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/ethernet/shared/StatusBarSignalPolicyRefactorEthernet.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryKairos.kt
new file mode 100644
index 0000000..2e79626
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionRepositoryKairos.kt
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import android.telephony.CellSignalStrength
+import android.telephony.TelephonyManager
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.State
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+
+/**
+ * Every mobile line of service can be identified via a [SubscriptionInfo] object. We set up a
+ * repository for each individual, tracked subscription via [MobileConnectionsRepository], and this
+ * repository is responsible for setting up a [TelephonyManager] object tied to its subscriptionId
+ *
+ * There should only ever be one [MobileConnectionRepository] per subscription, since
+ * [TelephonyManager] limits the number of callbacks that can be registered per process.
+ *
+ * This repository should have all of the relevant information for a single line of service, which
+ * eventually becomes a single icon in the status bar.
+ */
+@ExperimentalKairosApi
+interface MobileConnectionRepositoryKairos {
+    /** The subscriptionId that this connection represents */
+    val subId: Int
+
+    /** The carrierId for this connection. See [TelephonyManager.getSimCarrierId] */
+    val carrierId: State<Int>
+
+    /** Reflects the value from the carrier config INFLATE_SIGNAL_STRENGTH for this connection */
+    val inflateSignalStrength: State<Boolean>
+
+    /** Carrier config KEY_SHOW_5G_SLICE_ICON_BOOL for this connection */
+    val allowNetworkSliceIndicator: State<Boolean>
+
+    /**
+     * The table log buffer created for this connection. Will have the name "MobileConnectionLog
+     * [subId]"
+     */
+    val tableLogBuffer: TableLogBuffer
+
+    /** True if the [android.telephony.ServiceState] says this connection is emergency calls only */
+    val isEmergencyOnly: State<Boolean>
+
+    /** True if [android.telephony.ServiceState] says we are roaming */
+    val isRoaming: State<Boolean>
+
+    /**
+     * See [android.telephony.ServiceState.getOperatorAlphaShort], this value is defined as the
+     * current registered operator name in short alphanumeric format. In some cases this name might
+     * be preferred over other methods of calculating the network name
+     */
+    val operatorAlphaShort: State<String?>
+
+    /**
+     * TODO (b/263167683): Clarify this field
+     *
+     * This check comes from [com.android.settingslib.Utils.isInService]. It is intended to be a
+     * mapping from a ServiceState to a notion of connectivity. Notably, it will consider a
+     * connection to be in-service if either the voice registration state is IN_SERVICE or the data
+     * registration state is IN_SERVICE and NOT IWLAN.
+     */
+    val isInService: State<Boolean>
+
+    /**
+     * True if this subscription is actively connected to a non-terrestrial network and false
+     * otherwise. Reflects [android.telephony.ServiceState.isUsingNonTerrestrialNetwork].
+     *
+     * Notably: This value reflects that this subscription is **currently** using a non-terrestrial
+     * network, because some subscriptions can switch between terrestrial and non-terrestrial
+     * networks. [SubscriptionModel.isExclusivelyNonTerrestrial] reflects whether a subscription is
+     * configured to exclusively connect to non-terrestrial networks. [isNonTerrestrial] can change
+     * during the lifetime of a subscription but [SubscriptionModel.isExclusivelyNonTerrestrial]
+     * will stay constant.
+     */
+    val isNonTerrestrial: State<Boolean>
+
+    /** True if [android.telephony.SignalStrength] told us that this connection is using GSM */
+    val isGsm: State<Boolean>
+
+    /**
+     * There is still specific logic in the pipeline that calls out CDMA level explicitly. This
+     * field is not completely orthogonal to [primaryLevel], because CDMA could be primary.
+     */
+    // @IntRange(from = 0, to = 4)
+    val cdmaLevel: State<Int>
+
+    /** [android.telephony.SignalStrength]'s concept of the overall signal level */
+    // @IntRange(from = 0, to = 4)
+    val primaryLevel: State<Int>
+
+    /**
+     * This level can be used to reflect the signal strength when in carrier roaming NTN mode
+     * (carrier-based satellite)
+     */
+    val satelliteLevel: State<Int>
+
+    /** The current data connection state. See [DataConnectionState] */
+    val dataConnectionState: State<DataConnectionState>
+
+    /** The current data activity direction. See [DataActivityModel] */
+    val dataActivityDirection: State<DataActivityModel>
+
+    /** True if there is currently a carrier network change in process */
+    val carrierNetworkChangeActive: State<Boolean>
+
+    /**
+     * [resolvedNetworkType] is the [TelephonyDisplayInfo.getOverrideNetworkType] if it exists or
+     * [TelephonyDisplayInfo.getNetworkType]. This is used to look up the proper network type icon
+     */
+    val resolvedNetworkType: State<ResolvedNetworkType>
+
+    /** The total number of levels. Used with [SignalDrawable]. */
+    val numberOfLevels: State<Int>
+
+    /** Observable tracking [TelephonyManager.isDataConnectionAllowed] */
+    val dataEnabled: State<Boolean>
+
+    /**
+     * See [TelephonyManager.getCdmaEnhancedRoamingIndicatorDisplayNumber]. This bit only matters if
+     * the connection type is CDMA.
+     *
+     * True if the Enhanced Roaming Indicator (ERI) display number is not [TelephonyManager.ERI_OFF]
+     */
+    val cdmaRoaming: State<Boolean>
+
+    /** The service provider name for this network connection, or the default name. */
+    val networkName: State<NetworkNameModel>
+
+    /**
+     * The service provider name for this network connection, or the default name.
+     *
+     * TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
+     *   provided is identical
+     */
+    val carrierName: State<NetworkNameModel>
+
+    /**
+     * True if this type of connection is allowed while airplane mode is on, and false otherwise.
+     */
+    val isAllowedDuringAirplaneMode: State<Boolean>
+
+    /**
+     * True if this network has NET_CAPABILITIY_PRIORITIZE_LATENCY, and can be considered to be a
+     * network slice
+     */
+    val hasPrioritizedNetworkCapabilities: State<Boolean>
+
+    /**
+     * True if this connection is in emergency callback mode.
+     *
+     * @see [TelephonyManager.getEmergencyCallbackMode]
+     */
+    val isInEcmMode: State<Boolean>
+
+    companion object {
+        /** The default number of levels to use for [numberOfLevels]. */
+        val DEFAULT_NUM_LEVELS = CellSignalStrength.getNumSignalStrengthLevels()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKairos.kt
new file mode 100644
index 0000000..79bfb6e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKairos.kt
@@ -0,0 +1,122 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionManager
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.MobileMappings
+import com.android.settingslib.mobile.MobileMappings.Config
+import com.android.systemui.kairos.Events
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.Incremental
+import com.android.systemui.kairos.State
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+
+/**
+ * Repo for monitoring the complete active subscription info list, to be consumed and filtered based
+ * on various policy
+ */
+@ExperimentalKairosApi
+interface MobileConnectionsRepositoryKairos {
+
+    /** All active mobile connections. */
+    val mobileConnectionsBySubId: Incremental<Int, MobileConnectionRepositoryKairos>
+
+    /** Observable list of current mobile subscriptions */
+    val subscriptions: State<Collection<SubscriptionModel>>
+
+    /**
+     * Observable for the subscriptionId of the current mobile data connection. Null if we don't
+     * have a valid subscription id
+     */
+    val activeMobileDataSubscriptionId: State<Int?>
+
+    /** Repo that tracks the current [activeMobileDataSubscriptionId] */
+    val activeMobileDataRepository: State<MobileConnectionRepositoryKairos?>
+
+    /**
+     * Observable event for when the active data sim switches but the group stays the same. E.g.,
+     * CBRS switching would trigger this
+     */
+    val activeSubChangedInGroupEvent: Events<Unit>
+
+    /** Tracks [SubscriptionManager.getDefaultDataSubscriptionId]. `null` if there is no default. */
+    val defaultDataSubId: State<Int?>
+
+    /**
+     * True if the default network connection is a mobile-like connection and false otherwise.
+     *
+     * This is typically shown by having [android.net.NetworkCapabilities.TRANSPORT_CELLULAR], but
+     * there are edge cases (like carrier merged wifi) that could also result in the default
+     * connection being mobile-like.
+     */
+    val mobileIsDefault: State<Boolean>
+
+    /**
+     * True if the device currently has a carrier merged connection.
+     *
+     * See [CarrierMergedConnectionRepository] for more info.
+     */
+    val hasCarrierMergedConnection: State<Boolean>
+
+    /** True if the default network connection is validated and false otherwise. */
+    val defaultConnectionIsValidated: State<Boolean>
+
+    /**
+     * [Config] is an object that tracks relevant configuration flags for a given subscription ID.
+     * In the case of [MobileMappings], it's hard-coded to check the default data subscription's
+     * config, so this will apply to every icon that we care about.
+     *
+     * Relevant bits in the config are things like
+     * [CarrierConfigManager.KEY_SHOW_4G_FOR_LTE_DATA_ICON_BOOL]
+     *
+     * This flow will produce whenever the default data subscription or the carrier config changes.
+     */
+    val defaultDataSubRatConfig: State<Config>
+
+    /** The icon mapping from network type to [MobileIconGroup] for the default subscription */
+    val defaultMobileIconMapping: State<Map<String, MobileIconGroup>>
+
+    /** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */
+    val defaultMobileIconGroup: State<MobileIconGroup>
+
+    /**
+     * Can the device make emergency calls using the device-based service state? This field is only
+     * useful when all known active subscriptions are OOS and not emergency call capable.
+     *
+     * Specifically, this checks every [ServiceState] of the device, and looks for any that report
+     * [ServiceState.isEmergencyOnly].
+     *
+     * This is an eager flow, and re-evaluates whenever ACTION_SERVICE_STATE is sent for subId = -1.
+     */
+    val isDeviceEmergencyCallCapable: State<Boolean>
+
+    /**
+     * If any active SIM on the device is in
+     * [android.telephony.TelephonyManager.SIM_STATE_PIN_REQUIRED] or
+     * [android.telephony.TelephonyManager.SIM_STATE_PUK_REQUIRED] or
+     * [android.telephony.TelephonyManager.SIM_STATE_PERM_DISABLED]
+     */
+    val isAnySimSecure: State<Boolean>
+
+    /**
+     * Checks if any subscription has [android.telephony.TelephonyManager.getEmergencyCallbackMode]
+     * == true
+     */
+    val isInEcmMode: State<Boolean>
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKairosAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKairosAdapter.kt
new file mode 100644
index 0000000..64144d9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileConnectionsRepositoryKairosAdapter.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import android.content.Context
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileMappings
+import com.android.systemui.Flags
+import com.android.systemui.KairosActivatable
+import com.android.systemui.KairosBuilder
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosNetwork
+import com.android.systemui.kairos.buildSpec
+import com.android.systemui.kairos.combine
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.mapValues
+import com.android.systemui.kairos.toColdConflatedFlow
+import com.android.systemui.kairosBuilder
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionRepositoryKairosAdapter
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
+import dagger.Provides
+import dagger.multibindings.ElementsIntoSet
+import javax.inject.Inject
+import javax.inject.Provider
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.stateIn
+
+@ExperimentalKairosApi
+@SysUISingleton
+class MobileConnectionsRepositoryKairosAdapter
+@Inject
+constructor(
+    private val kairosRepo: MobileConnectionsRepositoryKairos,
+    private val kairosNetwork: KairosNetwork,
+    @Application scope: CoroutineScope,
+    connectivityRepository: ConnectivityRepository,
+    context: Context,
+    carrierConfigRepo: CarrierConfigRepository,
+) : MobileConnectionsRepository, KairosBuilder by kairosBuilder() {
+    override val subscriptions: StateFlow<List<SubscriptionModel>> =
+        kairosRepo.subscriptions
+            .map { it.toList() }
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), emptyList())
+
+    override val activeMobileDataSubscriptionId: StateFlow<Int?> =
+        kairosRepo.activeMobileDataSubscriptionId
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    private val reposBySubIdK = buildIncremental {
+        kairosRepo.mobileConnectionsBySubId
+            .mapValues { (subId, repo) ->
+                buildSpec {
+                    MobileConnectionRepositoryKairosAdapter(
+                        kairosRepo = repo,
+                        carrierConfig = carrierConfigRepo.getOrCreateConfigForSubId(subId),
+                    )
+                }
+            }
+            .applyLatestSpecForKey()
+    }
+
+    private val reposBySubId =
+        reposBySubIdK
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.Eagerly, emptyMap())
+
+    override val activeMobileDataRepository: StateFlow<MobileConnectionRepository?> =
+        combine(kairosRepo.activeMobileDataSubscriptionId, reposBySubIdK) { id, repos -> repos[id] }
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    override val activeSubChangedInGroupEvent: Flow<Unit> =
+        kairosRepo.activeSubChangedInGroupEvent.toColdConflatedFlow(kairosNetwork)
+
+    override val defaultDataSubId: StateFlow<Int?> =
+        kairosRepo.defaultDataSubId
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    override val mobileIsDefault: StateFlow<Boolean> =
+        kairosRepo.mobileIsDefault
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                connectivityRepository.defaultConnections.value.mobile.isDefault,
+            )
+
+    override val hasCarrierMergedConnection: Flow<Boolean> =
+        kairosRepo.hasCarrierMergedConnection.toColdConflatedFlow(kairosNetwork)
+
+    override val defaultConnectionIsValidated: StateFlow<Boolean> =
+        kairosRepo.defaultConnectionIsValidated
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                connectivityRepository.defaultConnections.value.isValidated,
+            )
+
+    override fun getRepoForSubId(subId: Int): MobileConnectionRepository =
+        reposBySubId.value[subId] ?: error("Unknown subscription id: $subId")
+
+    override val defaultDataSubRatConfig: StateFlow<MobileMappings.Config> =
+        kairosRepo.defaultDataSubRatConfig
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                MobileMappings.Config.readConfig(context),
+            )
+
+    override val defaultMobileIconMapping: Flow<Map<String, SignalIcon.MobileIconGroup>> =
+        kairosRepo.defaultMobileIconMapping.toColdConflatedFlow(kairosNetwork)
+
+    override val defaultMobileIconGroup: Flow<SignalIcon.MobileIconGroup> =
+        kairosRepo.defaultMobileIconGroup.toColdConflatedFlow(kairosNetwork)
+
+    override val isDeviceEmergencyCallCapable: StateFlow<Boolean> =
+        kairosRepo.isDeviceEmergencyCallCapable
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.Eagerly, false)
+
+    override val isAnySimSecure: StateFlow<Boolean> =
+        kairosRepo.isAnySimSecure
+            .toColdConflatedFlow(kairosNetwork)
+            .stateIn(scope, SharingStarted.Eagerly, false)
+
+    override fun getIsAnySimSecure(): Boolean = isAnySimSecure.value
+
+    override suspend fun isInEcmMode(): Boolean =
+        kairosNetwork.transact { kairosRepo.isInEcmMode.sample() }
+
+    @dagger.Module
+    object Module {
+        @Provides
+        @ElementsIntoSet
+        fun kairosActivatable(
+            impl: Provider<MobileConnectionsRepositoryKairosAdapter>
+        ): Set<@JvmSuppressWildcards KairosActivatable> =
+            if (Flags.statusBarMobileIconKairos()) setOf(impl.get()) else emptySet()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
index 66587c7..caf4bf5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcher.kt
@@ -48,9 +48,9 @@
  * something like this:
  * ```
  * RealRepository
- *                 │
- *                 ├──►RepositorySwitcher──►RealInteractor──►RealViewModel
- *                 │
+ *       │
+ *       ├──►RepositorySwitcher──►RealInteractor──►RealViewModel
+ *       │
  * DemoRepository
  * ```
  *
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairos.kt
new file mode 100644
index 0000000..1f5b849
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileRepositorySwitcherKairos.kt
@@ -0,0 +1,171 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import android.os.Bundle
+import androidx.annotation.VisibleForTesting
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileMappings
+import com.android.systemui.Flags
+import com.android.systemui.KairosActivatable
+import com.android.systemui.KairosBuilder
+import com.android.systemui.activated
+import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.demomode.DemoMode
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.kairos.Events
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.Incremental
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.flatMap
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.switchEvents
+import com.android.systemui.kairos.switchIncremental
+import com.android.systemui.kairosBuilder
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryKairosImpl
+import dagger.Binds
+import dagger.Provides
+import dagger.multibindings.ElementsIntoSet
+import javax.inject.Inject
+import javax.inject.Provider
+import kotlinx.coroutines.channels.awaitClose
+
+/**
+ * A provider for the [MobileConnectionsRepository] interface that can choose between the Demo and
+ * Prod concrete implementations at runtime. It works by defining a base flow, [activeRepo], which
+ * switches based on the latest information from [DemoModeController], and switches every flow in
+ * the interface to point to the currently-active provider. This allows us to put the demo mode
+ * interface in its own repository, completely separate from the real version, while still using all
+ * of the prod implementations for the rest of the pipeline (interactors and onward). Looks
+ * something like this:
+ * ```
+ * RealRepository
+ *       │
+ *       ├──►RepositorySwitcher──►RealInteractor──►RealViewModel
+ *       │
+ * DemoRepository
+ * ```
+ *
+ * NOTE: because the UI layer for mobile icons relies on a nested-repository structure, it is likely
+ * that we will have to drain the subscription list whenever demo mode changes. Otherwise if a real
+ * subscription list [1] is replaced with a demo subscription list [1], the view models will not see
+ * a change (due to `distinctUntilChanged`) and will not refresh their data providers to the demo
+ * implementation.
+ */
+@ExperimentalKairosApi
+@SysUISingleton
+class MobileRepositorySwitcherKairos
+@Inject
+constructor(
+    private val realRepository: MobileConnectionsRepositoryKairosImpl,
+    private val demoRepositoryFactory: DemoMobileConnectionsRepositoryKairos.Factory,
+    demoModeController: DemoModeController,
+) : MobileConnectionsRepositoryKairos, KairosBuilder by kairosBuilder() {
+
+    private val isDemoMode: State<Boolean> = buildState {
+        conflatedCallbackFlow {
+                val callback =
+                    object : DemoMode {
+                        override fun dispatchDemoCommand(command: String?, args: Bundle?) {
+                            // Nothing, we just care about on/off
+                        }
+
+                        override fun onDemoModeStarted() {
+                            trySend(true)
+                        }
+
+                        override fun onDemoModeFinished() {
+                            trySend(false)
+                        }
+                    }
+
+                demoModeController.addCallback(callback)
+                awaitClose { demoModeController.removeCallback(callback) }
+            }
+            .toState(demoModeController.isInDemoMode)
+    }
+
+    // Convenient definition flow for the currently active repo (based on demo mode or not)
+    @VisibleForTesting
+    val activeRepo: State<MobileConnectionsRepositoryKairos> = buildState {
+        isDemoMode.mapLatestBuild { demoMode ->
+            if (demoMode) {
+                activated { demoRepositoryFactory.create() }
+            } else {
+                realRepository
+            }
+        }
+    }
+
+    override val mobileConnectionsBySubId: Incremental<Int, MobileConnectionRepositoryKairos> =
+        activeRepo.map { it.mobileConnectionsBySubId }.switchIncremental()
+
+    override val subscriptions: State<Collection<SubscriptionModel>> =
+        activeRepo.flatMap { it.subscriptions }
+
+    override val activeMobileDataSubscriptionId: State<Int?> =
+        activeRepo.flatMap { it.activeMobileDataSubscriptionId }
+
+    override val activeMobileDataRepository: State<MobileConnectionRepositoryKairos?> =
+        activeRepo.flatMap { it.activeMobileDataRepository }
+
+    override val activeSubChangedInGroupEvent: Events<Unit> =
+        activeRepo.map { it.activeSubChangedInGroupEvent }.switchEvents()
+
+    override val defaultDataSubRatConfig: State<MobileMappings.Config> =
+        activeRepo.flatMap { it.defaultDataSubRatConfig }
+
+    override val defaultMobileIconMapping: State<Map<String, SignalIcon.MobileIconGroup>> =
+        activeRepo.flatMap { it.defaultMobileIconMapping }
+
+    override val defaultMobileIconGroup: State<SignalIcon.MobileIconGroup> =
+        activeRepo.flatMap { it.defaultMobileIconGroup }
+
+    override val isDeviceEmergencyCallCapable: State<Boolean> =
+        activeRepo.flatMap { it.isDeviceEmergencyCallCapable }
+
+    override val isAnySimSecure: State<Boolean> = activeRepo.flatMap { it.isAnySimSecure }
+
+    override val defaultDataSubId: State<Int?> = activeRepo.flatMap { it.defaultDataSubId }
+
+    override val mobileIsDefault: State<Boolean> = activeRepo.flatMap { it.mobileIsDefault }
+
+    override val hasCarrierMergedConnection: State<Boolean> =
+        activeRepo.flatMap { it.hasCarrierMergedConnection }
+
+    override val defaultConnectionIsValidated: State<Boolean> =
+        activeRepo.flatMap { it.defaultConnectionIsValidated }
+
+    override val isInEcmMode: State<Boolean> = activeRepo.flatMap { it.isInEcmMode }
+
+    @dagger.Module
+    interface Module {
+        @Binds fun bindImpl(impl: MobileRepositorySwitcherKairos): MobileConnectionsRepositoryKairos
+
+        companion object {
+            @Provides
+            @ElementsIntoSet
+            fun kairosActivatable(
+                impl: Provider<MobileRepositorySwitcherKairos>
+            ): Set<@JvmSuppressWildcards KairosActivatable> =
+                if (Flags.statusBarMobileIconKairos()) setOf(impl.get()) else emptySet()
+        }
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepositoryKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepositoryKairos.kt
new file mode 100644
index 0000000..a244feb
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionRepositoryKairos.kt
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
+
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.TelephonyManager
+import com.android.settingslib.SignalIcon
+import com.android.systemui.KairosBuilder
+import com.android.systemui.kairos.Events
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.TransactionScope
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.mapCheap
+import com.android.systemui.kairos.mergeLeft
+import com.android.systemui.kairos.stateOf
+import com.android.systemui.kairos.util.Either
+import com.android.systemui.kairos.util.Either.First
+import com.android.systemui.kairos.util.Either.Second
+import com.android.systemui.kairos.util.firstOrNull
+import com.android.systemui.kairosBuilder
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile as FakeMobileEvent
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepositoryKairos.Companion.COL_CARRIER_ID
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepositoryKairos.Companion.COL_CARRIER_NETWORK_CHANGE
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepositoryKairos.Companion.COL_CDMA_LEVEL
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepositoryKairos.Companion.COL_IS_IN_SERVICE
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepositoryKairos.Companion.COL_IS_NTN
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepositoryKairos.Companion.COL_OPERATOR
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepositoryKairos.Companion.COL_PRIMARY_LEVEL
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepositoryKairos.Companion.COL_ROAMING
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepositoryKairos.Companion.COL_SATELLITE_LEVEL
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel.CarrierMerged as FakeCarrierMergedEvent
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/**
+ * Demo version of [MobileConnectionRepository]. Note that this class shares all of its flows using
+ * [SharingStarted.WhileSubscribed()] to give the same semantics as using a regular
+ * [MutableStateFlow] while still logging all of the inputs in the same manor as the production
+ * repos.
+ */
+@ExperimentalKairosApi
+class DemoMobileConnectionRepositoryKairos(
+    override val subId: Int,
+    override val tableLogBuffer: TableLogBuffer,
+    mobileEvents: Events<FakeMobileEvent>,
+    carrierMergedResetEvents: Events<Any?>,
+    wifiEvents: Events<FakeCarrierMergedEvent>,
+    private val mobileMappingsReverseLookup: State<Map<SignalIcon.MobileIconGroup, String>>,
+) : MobileConnectionRepositoryKairos, KairosBuilder by kairosBuilder() {
+
+    private val initialState =
+        FakeMobileEvent(
+            level = null,
+            dataType = null,
+            subId = subId,
+            carrierId = null,
+            activity = null,
+            carrierNetworkChange = false,
+            roaming = false,
+            name = DEMO_CARRIER_NAME,
+        )
+
+    private val lastMobileEvent: State<FakeMobileEvent> = buildState {
+        mobileEvents.holdState(initialState)
+    }
+
+    private val lastEvent: State<Either<FakeMobileEvent, FakeCarrierMergedEvent>> = buildState {
+        mergeLeft(
+                mobileEvents.mapCheap { First(it) },
+                wifiEvents.mapCheap { Second(it) },
+                carrierMergedResetEvents.mapCheap { First(lastMobileEvent.sample()) },
+            )
+            .holdState(First(initialState))
+    }
+
+    override val carrierId: State<Int> =
+        lastEvent
+            .map { it.firstOrNull()?.carrierId ?: INVALID_SUBSCRIPTION_ID }
+            .also {
+                onActivated {
+                    logDiffsForTable(
+                        intState = it,
+                        tableLogBuffer = tableLogBuffer,
+                        columnName = COL_CARRIER_ID,
+                    )
+                }
+            }
+
+    override val inflateSignalStrength: State<Boolean> = buildState {
+        mobileEvents
+            .map { ev -> ev.inflateStrength }
+            .holdState(false)
+            .also { logDiffsForTable(it, tableLogBuffer, "", columnName = "inflate") }
+    }
+
+    // I don't see a reason why we would turn the config off for demo mode.
+    override val allowNetworkSliceIndicator: State<Boolean> = stateOf(true)
+
+    // TODO(b/261029387): not yet supported
+    override val isEmergencyOnly: State<Boolean> = stateOf(false)
+
+    override val isRoaming: State<Boolean> =
+        lastEvent
+            .map { it.firstOrNull()?.roaming ?: false }
+            .also { onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_ROAMING) } }
+
+    override val operatorAlphaShort: State<String?> =
+        lastEvent
+            .map { it.firstOrNull()?.name }
+            .also {
+                onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_OPERATOR) }
+            }
+
+    override val isInService: State<Boolean> =
+        lastEvent
+            .map {
+                when (it) {
+                    is First -> it.value.level?.let { level -> level > 0 } ?: false
+                    is Second -> true
+                }
+            }
+            .also {
+                onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_IS_IN_SERVICE) }
+            }
+
+    override val isNonTerrestrial: State<Boolean> = buildState {
+        mobileEvents
+            .map { it.ntn }
+            .holdState(false)
+            .also { logDiffsForTable(it, tableLogBuffer, columnName = COL_IS_NTN) }
+    }
+
+    // TODO(b/261029387): not yet supported
+    override val isGsm: State<Boolean> = stateOf(false)
+
+    override val cdmaLevel: State<Int> =
+        lastEvent
+            .map {
+                when (it) {
+                    is First -> it.value.level ?: 0
+                    is Second -> it.value.level
+                }
+            }
+            .also {
+                onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_CDMA_LEVEL) }
+            }
+
+    override val primaryLevel: State<Int> =
+        lastEvent
+            .map {
+                when (it) {
+                    is First -> it.value.level ?: 0
+                    is Second -> it.value.level
+                }
+            }
+            .also {
+                onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_PRIMARY_LEVEL) }
+            }
+
+    override val satelliteLevel: State<Int> =
+        stateOf(0).also {
+            onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_SATELLITE_LEVEL) }
+        }
+
+    // TODO(b/261029387): not yet supported
+    override val dataConnectionState: State<DataConnectionState> =
+        buildState {
+                mergeLeft(mobileEvents, wifiEvents)
+                    .map { DataConnectionState.Connected }
+                    .holdState(DataConnectionState.Disconnected)
+            }
+            .also {
+                onActivated {
+                    logDiffsForTable(diffableState = it, tableLogBuffer = tableLogBuffer)
+                }
+            }
+
+    override val dataActivityDirection: State<DataActivityModel> =
+        lastEvent
+            .map {
+                val activity =
+                    when (it) {
+                        is First -> it.value.activity ?: TelephonyManager.DATA_ACTIVITY_NONE
+                        is Second -> it.value.activity
+                    }
+                activity.toMobileDataActivityModel()
+            }
+            .also { onActivated { logDiffsForTable(it, tableLogBuffer, columnPrefix = "") } }
+
+    override val carrierNetworkChangeActive: State<Boolean> =
+        lastEvent
+            .map { it.firstOrNull()?.carrierNetworkChange ?: false }
+            .also {
+                onActivated {
+                    logDiffsForTable(it, tableLogBuffer, columnName = COL_CARRIER_NETWORK_CHANGE)
+                }
+            }
+
+    override val resolvedNetworkType: State<ResolvedNetworkType> = buildState {
+        lastEvent
+            .mapTransactionally {
+                it.firstOrNull()?.dataType?.let { resolvedNetworkTypeForIconGroup(it) }
+                    ?: ResolvedNetworkType.CarrierMergedNetworkType
+            }
+            .also { logDiffsForTable(it, tableLogBuffer, columnPrefix = "") }
+    }
+
+    override val numberOfLevels: State<Int> =
+        inflateSignalStrength.map { shouldInflate ->
+            if (shouldInflate) DEFAULT_NUM_LEVELS + 1 else DEFAULT_NUM_LEVELS
+        }
+
+    override val dataEnabled: State<Boolean> = stateOf(true)
+
+    override val cdmaRoaming: State<Boolean> = lastEvent.map { it.firstOrNull()?.roaming ?: false }
+
+    override val networkName: State<NetworkNameModel.IntentDerived> =
+        lastEvent.map {
+            NetworkNameModel.IntentDerived(it.firstOrNull()?.name ?: CARRIER_MERGED_NAME)
+        }
+
+    override val carrierName: State<NetworkNameModel.SubscriptionDerived> =
+        lastEvent.map {
+            NetworkNameModel.SubscriptionDerived(
+                it.firstOrNull()?.let { event -> "${event.name} ${event.subId}" }
+                    ?: CARRIER_MERGED_NAME
+            )
+        }
+
+    override val isAllowedDuringAirplaneMode: State<Boolean> = lastEvent.map { it is Second }
+
+    override val hasPrioritizedNetworkCapabilities: State<Boolean> =
+        lastEvent.map { it.firstOrNull()?.slice ?: false }
+
+    override val isInEcmMode: State<Boolean> = stateOf(false)
+
+    private fun TransactionScope.resolvedNetworkTypeForIconGroup(
+        iconGroup: SignalIcon.MobileIconGroup?
+    ) = DefaultNetworkType(mobileMappingsReverseLookup.sample()[iconGroup] ?: "dis")
+
+    companion object {
+        private const val DEMO_CARRIER_NAME = "Demo Carrier"
+        private const val CARRIER_MERGED_NAME = "Carrier Merged Network"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryKairos.kt
new file mode 100644
index 0000000..925ee54
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoMobileConnectionsRepositoryKairos.kt
@@ -0,0 +1,255 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
+
+import android.content.Context
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.SubscriptionManager.PROFILE_CLASS_UNSET
+import android.util.Log
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileMappings
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.KairosBuilder
+import com.android.systemui.activated
+import com.android.systemui.kairos.BuildScope
+import com.android.systemui.kairos.Events
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.GroupedEvents
+import com.android.systemui.kairos.Incremental
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.TransactionScope
+import com.android.systemui.kairos.asIncremental
+import com.android.systemui.kairos.buildSpec
+import com.android.systemui.kairos.combine
+import com.android.systemui.kairos.emptyEvents
+import com.android.systemui.kairos.filter
+import com.android.systemui.kairos.filterIsInstance
+import com.android.systemui.kairos.groupBy
+import com.android.systemui.kairos.groupByKey
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.mapCheap
+import com.android.systemui.kairos.mapNotNull
+import com.android.systemui.kairos.mapValues
+import com.android.systemui.kairos.mergeLeft
+import com.android.systemui.kairos.stateOf
+import com.android.systemui.kairosBuilder
+import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.FullMobileConnectionRepository.Factory.Companion.MOBILE_CONNECTION_BUFFER_SIZE
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.model.FakeWifiEventModel
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+
+/** This repository vends out data based on demo mode commands */
+@ExperimentalKairosApi
+class DemoMobileConnectionsRepositoryKairos
+@AssistedInject
+constructor(
+    mobileDataSource: DemoModeMobileConnectionDataSourceKairos,
+    private val wifiDataSource: DemoModeWifiDataSource,
+    context: Context,
+    private val logFactory: TableLogBufferFactory,
+) : MobileConnectionsRepositoryKairos, KairosBuilder by kairosBuilder() {
+
+    @AssistedFactory
+    fun interface Factory {
+        fun create(): DemoMobileConnectionsRepositoryKairos
+    }
+
+    private val wifiEvents: Events<FakeWifiEventModel?> = buildEvents {
+        wifiDataSource.wifiEvents.toEvents()
+    }
+
+    private val mobileEventsWithSubId: Events<Pair<Int, FakeNetworkEventModel>> =
+        mobileDataSource.mobileEvents.mapNotNull { event ->
+            event?.let { (event.subId ?: lastSeenSubId.sample())?.let { it to event } }
+        }
+
+    private val mobileEventsBySubId: GroupedEvents<Int, FakeNetworkEventModel> =
+        mobileEventsWithSubId.map { mapOf(it) }.groupByKey()
+
+    private val carrierMergedEvents: Events<FakeWifiEventModel.CarrierMerged> =
+        wifiEvents.filterIsInstance<FakeWifiEventModel.CarrierMerged>()
+
+    private val wifiEventsBySubId: GroupedEvents<Int, FakeWifiEventModel.CarrierMerged> =
+        carrierMergedEvents.groupBy { it.subscriptionId }
+
+    private val lastSeenSubId: State<Int?> = buildState {
+        mergeLeft(
+                mobileEventsWithSubId.mapCheap { it.first },
+                carrierMergedEvents.mapCheap { it.subscriptionId },
+            )
+            .holdState(null)
+    }
+
+    private val activeCarrierMergedSubscription: State<Int?> = buildState {
+        mergeLeft(
+                carrierMergedEvents.mapCheap { it.subscriptionId },
+                wifiEvents
+                    .filter {
+                        it is FakeWifiEventModel.Wifi || it is FakeWifiEventModel.WifiDisabled
+                    }
+                    .map { null },
+            )
+            .holdState(null)
+    }
+
+    private val activeMobileSubscriptions: State<Set<Int>> = buildState {
+        mobileDataSource.mobileEvents
+            .mapNotNull { event ->
+                when (event) {
+                    null -> null
+                    is Mobile -> event.subId?.let { subId -> { subs: Set<Int> -> subs + subId } }
+                    is MobileDisabled ->
+                        (event.subId ?: maybeGetOnlySubIdForRemoval())?.let { subId ->
+                            { subs: Set<Int> -> subs - subId }
+                        }
+                }
+            }
+            .foldState(emptySet()) { f, s -> f(s) }
+    }
+
+    private val subscriptionIds: State<Set<Int>> =
+        combine(activeMobileSubscriptions, activeCarrierMergedSubscription) { mobile, carrierMerged
+            ->
+            carrierMerged?.let { mobile + carrierMerged } ?: mobile
+        }
+
+    private val subscriptionsById: State<Map<Int, SubscriptionModel>> =
+        subscriptionIds.map { subs ->
+            subs.associateWith { subId ->
+                SubscriptionModel(
+                    subscriptionId = subId,
+                    isOpportunistic = false,
+                    carrierName = DEFAULT_CARRIER_NAME,
+                    profileClass = PROFILE_CLASS_UNSET,
+                )
+            }
+        }
+
+    override val subscriptions: State<Collection<SubscriptionModel>> =
+        subscriptionsById.map { it.values }
+
+    private fun TransactionScope.maybeGetOnlySubIdForRemoval(): Int? {
+        val subIds = activeMobileSubscriptions.sample()
+        return if (subIds.size == 1) {
+            subIds.first()
+        } else {
+            Log.d(
+                TAG,
+                "processDisabledMobileState: Unable to infer subscription to " +
+                    "disable. Specify subId using '-e slot <subId>'. " +
+                    "Known subIds: [${subIds.joinToString(",")}]",
+            )
+            null
+        }
+    }
+
+    private val reposBySubId: Incremental<Int, DemoMobileConnectionRepositoryKairos> =
+        buildIncremental {
+            subscriptionsById
+                .asIncremental()
+                .mapValues { (id, _) -> buildSpec { newRepo(id) } }
+                .applyLatestSpecForKey()
+        }
+
+    // TODO(b/261029387): add a command for this value
+    override val activeMobileDataSubscriptionId: State<Int> =
+        // For now, active is just the first in the list
+        subscriptions.map { infos ->
+            infos.firstOrNull()?.subscriptionId ?: INVALID_SUBSCRIPTION_ID
+        }
+
+    override val activeMobileDataRepository: State<DemoMobileConnectionRepositoryKairos?> =
+        combine(activeMobileDataSubscriptionId, reposBySubId) { subId, repoMap -> repoMap[subId] }
+
+    // TODO(b/261029387): consider adding a demo command for this
+    override val activeSubChangedInGroupEvent: Events<Unit> = emptyEvents
+
+    /** Demo mode doesn't currently support modifications to the mobile mappings */
+    override val defaultDataSubRatConfig: State<MobileMappings.Config> =
+        stateOf(MobileMappings.Config.readConfig(context))
+
+    override val defaultMobileIconGroup: State<SignalIcon.MobileIconGroup> =
+        stateOf(TelephonyIcons.THREE_G)
+
+    // TODO(b/339023069): demo command for device-based emergency calls state
+    override val isDeviceEmergencyCallCapable: State<Boolean> = stateOf(false)
+
+    override val isAnySimSecure: State<Boolean> = stateOf(false)
+
+    override val defaultMobileIconMapping: State<Map<String, SignalIcon.MobileIconGroup>> =
+        stateOf(TelephonyIcons.ICON_NAME_TO_ICON)
+
+    /**
+     * In order to maintain compatibility with the old demo mode shell command API, reverse the
+     * [MobileMappings] lookup from (NetworkType: String -> Icon: MobileIconGroup), so that we can
+     * parse the string from the command line into a preferred icon group, and send _a_ valid
+     * network type for that icon through the pipeline.
+     *
+     * Note: collisions don't matter here, because the data source (the command line) only cares
+     * about the resulting icon, not the underlying network type.
+     */
+    private val mobileMappingsReverseLookup: State<Map<SignalIcon.MobileIconGroup, String>> =
+        defaultMobileIconMapping.map { networkToIconMap -> networkToIconMap.reverse() }
+
+    private fun <K, V> Map<K, V>.reverse() = entries.associate { (k, v) -> v to k }
+
+    // TODO(b/261029387): add a command for this value
+    override val defaultDataSubId: State<Int?> = stateOf(null)
+
+    // TODO(b/261029387): not yet supported
+    override val mobileIsDefault: State<Boolean> = stateOf(true)
+
+    // TODO(b/261029387): not yet supported
+    override val hasCarrierMergedConnection: State<Boolean> = stateOf(false)
+
+    // TODO(b/261029387): not yet supported
+    override val defaultConnectionIsValidated: State<Boolean> = stateOf(true)
+
+    override val isInEcmMode: State<Boolean> = stateOf(false)
+
+    override val mobileConnectionsBySubId: Incremental<Int, DemoMobileConnectionRepositoryKairos>
+        get() = reposBySubId
+
+    private fun BuildScope.newRepo(subId: Int) = activated {
+        DemoMobileConnectionRepositoryKairos(
+            subId = subId,
+            tableLogBuffer =
+                logFactory.getOrCreate(
+                    "DemoMobileConnectionLog[$subId]",
+                    MOBILE_CONNECTION_BUFFER_SIZE,
+                ),
+            mobileEvents = mobileEventsBySubId[subId].filterIsInstance(),
+            carrierMergedResetEvents =
+                wifiEvents.mapNotNull { it?.takeIf { it !is FakeWifiEventModel.CarrierMerged } },
+            wifiEvents = wifiEventsBySubId[subId],
+            mobileMappingsReverseLookup = mobileMappingsReverseLookup,
+        )
+    }
+
+    companion object {
+        private const val TAG = "DemoMobileConnectionsRepo"
+
+        private const val DEFAULT_CARRIER_NAME = "demo carrier"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSourceKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSourceKairos.kt
new file mode 100644
index 0000000..f329383
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/DemoModeMobileConnectionDataSourceKairos.kt
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.demo
+
+import android.os.Bundle
+import android.telephony.Annotation.DataActivityType
+import android.telephony.TelephonyManager.DATA_ACTIVITY_IN
+import android.telephony.TelephonyManager.DATA_ACTIVITY_INOUT
+import android.telephony.TelephonyManager.DATA_ACTIVITY_NONE
+import android.telephony.TelephonyManager.DATA_ACTIVITY_OUT
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.Flags
+import com.android.systemui.KairosActivatable
+import com.android.systemui.KairosBuilder
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.demomode.DemoMode.COMMAND_NETWORK
+import com.android.systemui.demomode.DemoModeController
+import com.android.systemui.kairos.Events
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairosBuilder
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.Mobile
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel.MobileDisabled
+import dagger.Binds
+import dagger.Provides
+import dagger.multibindings.ElementsIntoSet
+import javax.inject.Inject
+import javax.inject.Provider
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.map
+
+/**
+ * Data source that can map from demo mode commands to inputs into the
+ * [DemoMobileConnectionsRepositoryKairos]
+ */
+@ExperimentalKairosApi
+interface DemoModeMobileConnectionDataSourceKairos {
+    val mobileEvents: Events<FakeNetworkEventModel?>
+}
+
+@ExperimentalKairosApi
+@SysUISingleton
+class DemoModeMobileConnectionDataSourceKairosImpl
+@Inject
+constructor(demoModeController: DemoModeController) :
+    KairosBuilder by kairosBuilder(), DemoModeMobileConnectionDataSourceKairos {
+    private val demoCommandStream: Flow<Bundle> =
+        demoModeController.demoFlowForCommand(COMMAND_NETWORK)
+
+    // If the args contains "mobile", then all of the args are relevant. It's just the way demo mode
+    // commands work and it's a little silly
+    private val _mobileCommands: Flow<FakeNetworkEventModel?> =
+        demoCommandStream.map { args -> args.toMobileEvent() }
+    override val mobileEvents: Events<FakeNetworkEventModel?> = buildEvents {
+        _mobileCommands.toEvents()
+    }
+
+    private fun Bundle.toMobileEvent(): FakeNetworkEventModel? {
+        val mobile = getString("mobile") ?: return null
+        return if (mobile == "show") {
+            activeMobileEvent()
+        } else {
+            MobileDisabled(subId = getString("slot")?.toInt())
+        }
+    }
+
+    /** Parse a valid mobile command string into a network event */
+    private fun Bundle.activeMobileEvent(): Mobile {
+        // There are many key/value pairs supported by mobile demo mode. Bear with me here
+        val level = getString("level")?.toInt()
+        val dataType = getString("datatype")?.toDataType()
+        val slot = getString("slot")?.toInt()
+        val carrierId = getString("carrierid")?.toInt()
+        val inflateStrength = getString("inflate").toBoolean()
+        val activity = getString("activity")?.toActivity()
+        val carrierNetworkChange = getString("carriernetworkchange") == "show"
+        val roaming = getString("roam") == "show"
+        val name = getString("networkname") ?: "demo mode"
+        val slice = getString("slice").toBoolean()
+        val ntn = getString("ntn").toBoolean()
+
+        return Mobile(
+            level = level,
+            dataType = dataType,
+            subId = slot,
+            carrierId = carrierId,
+            inflateStrength = inflateStrength,
+            activity = activity,
+            carrierNetworkChange = carrierNetworkChange,
+            roaming = roaming,
+            name = name,
+            slice = slice,
+            ntn = ntn,
+        )
+    }
+
+    @dagger.Module
+    interface Module {
+        @Binds
+        fun bindImpl(
+            impl: DemoModeMobileConnectionDataSourceKairosImpl
+        ): DemoModeMobileConnectionDataSourceKairos
+
+        companion object {
+            @Provides
+            @ElementsIntoSet
+            fun kairosActivatable(
+                impl: Provider<DemoModeMobileConnectionDataSourceKairosImpl>
+            ): Set<@JvmSuppressWildcards KairosActivatable> =
+                if (Flags.statusBarMobileIconKairos()) setOf(impl.get()) else emptySet()
+        }
+    }
+}
+
+private fun String.toDataType(): MobileIconGroup =
+    when (this) {
+        "1x" -> TelephonyIcons.ONE_X
+        "3g" -> TelephonyIcons.THREE_G
+        "4g" -> TelephonyIcons.FOUR_G
+        "4g+" -> TelephonyIcons.FOUR_G_PLUS
+        "5g" -> TelephonyIcons.NR_5G
+        "5ge" -> TelephonyIcons.LTE_CA_5G_E
+        "5g+" -> TelephonyIcons.NR_5G_PLUS
+        "e" -> TelephonyIcons.E
+        "g" -> TelephonyIcons.G
+        "h" -> TelephonyIcons.H
+        "h+" -> TelephonyIcons.H_PLUS
+        "lte" -> TelephonyIcons.LTE
+        "lte+" -> TelephonyIcons.LTE_PLUS
+        "dis" -> TelephonyIcons.DATA_DISABLED
+        "not" -> TelephonyIcons.NOT_DEFAULT_DATA
+        else -> TelephonyIcons.UNKNOWN
+    }
+
+@DataActivityType
+private fun String.toActivity(): Int =
+    when (this) {
+        "inout" -> DATA_ACTIVITY_INOUT
+        "in" -> DATA_ACTIVITY_IN
+        "out" -> DATA_ACTIVITY_OUT
+        else -> DATA_ACTIVITY_NONE
+    }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/model/FakeNetworkEventModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/model/FakeNetworkEventModel.kt
index 42171d0..54162bb 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/model/FakeNetworkEventModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/demo/model/FakeNetworkEventModel.kt
@@ -25,11 +25,13 @@
  * Nullable fields represent optional command line arguments
  */
 sealed interface FakeNetworkEventModel {
+    // Null means the default (chosen by the repository)
+    val subId: Int?
+
     data class Mobile(
         val level: Int?,
         val dataType: SignalIcon.MobileIconGroup?,
-        // Null means the default (chosen by the repository)
-        val subId: Int?,
+        override val subId: Int?,
         val carrierId: Int?,
         val inflateStrength: Boolean = false,
         @DataActivityType val activity: Int?,
@@ -40,8 +42,5 @@
         val ntn: Boolean = false,
     ) : FakeNetworkEventModel
 
-    data class MobileDisabled(
-        // Null means the default (chosen by the repository)
-        val subId: Int?
-    ) : FakeNetworkEventModel
+    data class MobileDisabled(override val subId: Int?) : FakeNetworkEventModel
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairos.kt
new file mode 100644
index 0000000..d61d11b
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/CarrierMergedConnectionRepositoryKairos.kt
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.TelephonyManager
+import android.util.Log
+import com.android.systemui.KairosBuilder
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.combine
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.stateOf
+import com.android.systemui.kairosBuilder
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import javax.inject.Inject
+
+/**
+ * A repository implementation for a carrier merged (aka VCN) network. A carrier merged network is
+ * delivered to SysUI as a wifi network (see [WifiNetworkModel.CarrierMerged], but is visually
+ * displayed as a mobile network triangle.
+ *
+ * See [android.net.wifi.WifiInfo.isCarrierMerged] for more information.
+ *
+ * See [MobileConnectionRepositoryImpl] for a repository implementation of a typical mobile
+ * connection.
+ */
+@ExperimentalKairosApi
+class CarrierMergedConnectionRepositoryKairos(
+    override val subId: Int,
+    override val tableLogBuffer: TableLogBuffer,
+    private val telephonyManager: TelephonyManager,
+    val wifiRepository: WifiRepository,
+    override val isInEcmMode: State<Boolean>,
+) : MobileConnectionRepositoryKairos, KairosBuilder by kairosBuilder() {
+    init {
+        if (telephonyManager.subscriptionId != subId) {
+            error(
+                """CarrierMergedRepo: TelephonyManager should be created with subId($subId).
+                    | Found ${telephonyManager.subscriptionId} instead."""
+                    .trimMargin()
+            )
+        }
+    }
+
+    private val isWifiEnabled: State<Boolean> = buildState {
+        wifiRepository.isWifiEnabled.toState()
+    }
+    private val isWifiDefault: State<Boolean> = buildState {
+        wifiRepository.isWifiDefault.toState()
+    }
+    private val wifiNetwork: State<WifiNetworkModel> = buildState {
+        wifiRepository.wifiNetwork.toState()
+    }
+
+    /**
+     * Outputs the carrier merged network to use, or null if we don't have a valid carrier merged
+     * network.
+     */
+    private val network: State<WifiNetworkModel.CarrierMerged?> =
+        combine(isWifiEnabled, isWifiDefault, wifiNetwork) { isEnabled, isDefault, network ->
+            when {
+                !isEnabled -> null
+                !isDefault -> null
+                network !is WifiNetworkModel.CarrierMerged -> null
+                network.subscriptionId != subId -> {
+                    Log.w(
+                        TAG,
+                        """Connection repo subId=$subId does not equal wifi repo
+                            | subId=${network.subscriptionId}; not showing carrier merged"""
+                            .trimMargin(),
+                    )
+                    null
+                }
+                else -> network
+            }
+        }
+
+    override val cdmaRoaming: State<Boolean> = stateOf(ROAMING)
+
+    override val networkName: State<NetworkNameModel> =
+        // The SIM operator name should be the same throughout the lifetime of a subId, **but**
+        // it may not be available when this repo is created because it takes time to load. To
+        // be safe, we re-fetch it each time the network has changed.
+        network.map { NetworkNameModel.SimDerived(telephonyManager.simOperatorName) }
+
+    override val carrierName: State<NetworkNameModel>
+        get() = networkName
+
+    override val numberOfLevels: State<Int> =
+        wifiNetwork.map {
+            if (it is WifiNetworkModel.CarrierMerged) {
+                it.numberOfLevels
+            } else {
+                DEFAULT_NUM_LEVELS
+            }
+        }
+
+    override val primaryLevel: State<Int> =
+        network.map { it?.level ?: SIGNAL_STRENGTH_NONE_OR_UNKNOWN }
+
+    override val cdmaLevel: State<Int> =
+        network.map { it?.level ?: SIGNAL_STRENGTH_NONE_OR_UNKNOWN }
+
+    override val dataActivityDirection: State<DataActivityModel> = buildState {
+        wifiRepository.wifiActivity.toState()
+    }
+
+    override val resolvedNetworkType: State<ResolvedNetworkType> =
+        network.map {
+            if (it != null) {
+                ResolvedNetworkType.CarrierMergedNetworkType
+            } else {
+                ResolvedNetworkType.UnknownNetworkType
+            }
+        }
+
+    override val dataConnectionState: State<DataConnectionState> =
+        network.map {
+            if (it != null) {
+                DataConnectionState.Connected
+            } else {
+                DataConnectionState.Disconnected
+            }
+        }
+
+    override val isRoaming: State<Boolean> = stateOf(false)
+    override val carrierId: State<Int> = stateOf(INVALID_SUBSCRIPTION_ID)
+    override val inflateSignalStrength: State<Boolean> = stateOf(false)
+    override val allowNetworkSliceIndicator: State<Boolean> = stateOf(false)
+    override val isEmergencyOnly: State<Boolean> = stateOf(false)
+    override val operatorAlphaShort: State<String?> = stateOf(null)
+    override val isInService: State<Boolean> = stateOf(true)
+    override val isNonTerrestrial: State<Boolean> = stateOf(false)
+    override val isGsm: State<Boolean> = stateOf(false)
+    override val carrierNetworkChangeActive: State<Boolean> = stateOf(false)
+    override val satelliteLevel: State<Int> = stateOf(0)
+
+    /**
+     * Carrier merged connections happen over wifi but are displayed as a mobile triangle. Because
+     * they occur over wifi, it's possible to have a valid carrier merged connection even during
+     * airplane mode. See b/291993542.
+     */
+    override val isAllowedDuringAirplaneMode: State<Boolean> = stateOf(true)
+
+    /**
+     * It's not currently considered possible that a carrier merged network can have these
+     * prioritized capabilities. If we need to track them, we can add the same check as is in
+     * [MobileConnectionRepositoryImpl].
+     */
+    override val hasPrioritizedNetworkCapabilities: State<Boolean> = stateOf(false)
+
+    override val dataEnabled: State<Boolean>
+        get() = isWifiEnabled
+
+    companion object {
+        // Carrier merged is never roaming
+        private const val ROAMING = false
+    }
+
+    @SysUISingleton
+    class Factory
+    @Inject
+    constructor(
+        private val telephonyManager: TelephonyManager,
+        private val wifiRepository: WifiRepository,
+    ) {
+        fun build(
+            subId: Int,
+            mobileLogger: TableLogBuffer,
+            mobileRepo: MobileConnectionRepositoryKairos,
+        ): CarrierMergedConnectionRepositoryKairos {
+            return CarrierMergedConnectionRepositoryKairos(
+                subId,
+                mobileLogger,
+                telephonyManager.createForSubscriptionId(subId),
+                wifiRepository,
+                mobileRepo.isInEcmMode,
+            )
+        }
+    }
+}
+
+private const val TAG = "CarrierMergedConnectionRepository"
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryKairos.kt
new file mode 100644
index 0000000..1a8ca95
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/FullMobileConnectionRepositoryKairos.kt
@@ -0,0 +1,254 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import android.util.IndentingPrintWriter
+import androidx.annotation.VisibleForTesting
+import com.android.systemui.KairosBuilder
+import com.android.systemui.kairos.BuildSpec
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.flatMap
+import com.android.systemui.kairosBuilder
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import java.io.PrintWriter
+
+/**
+ * A repository that fully implements a mobile connection.
+ *
+ * This connection could either be a typical mobile connection (see [MobileConnectionRepositoryImpl]
+ * or a carrier merged connection (see [CarrierMergedConnectionRepository]). This repository
+ * switches between the two types of connections based on whether the connection is currently
+ * carrier merged.
+ */
+@ExperimentalKairosApi
+class FullMobileConnectionRepositoryKairos
+@AssistedInject
+constructor(
+    @Assisted override val subId: Int,
+    @Assisted override val tableLogBuffer: TableLogBuffer,
+    @Assisted private val mobileRepo: MobileConnectionRepositoryKairos,
+    @Assisted private val carrierMergedRepoSpec: BuildSpec<MobileConnectionRepositoryKairos>,
+    @Assisted private val isCarrierMerged: State<Boolean>,
+) : MobileConnectionRepositoryKairos, KairosBuilder by kairosBuilder() {
+
+    init {
+        onActivated {
+            logDiffsForTable(isCarrierMerged, tableLogBuffer, columnName = "isCarrierMerged")
+        }
+    }
+
+    @VisibleForTesting
+    val activeRepo: State<MobileConnectionRepositoryKairos> = buildState {
+        isCarrierMerged.mapLatestBuild { merged ->
+            if (merged) {
+                carrierMergedRepoSpec.applySpec()
+            } else {
+                mobileRepo
+            }
+        }
+    }
+
+    override val carrierId: State<Int> = activeRepo.flatMap { it.carrierId }
+
+    override val cdmaRoaming: State<Boolean> = activeRepo.flatMap { it.cdmaRoaming }
+
+    override val isEmergencyOnly: State<Boolean> =
+        activeRepo
+            .flatMap { it.isEmergencyOnly }
+            .also {
+                onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_EMERGENCY) }
+            }
+
+    override val isRoaming: State<Boolean> =
+        activeRepo
+            .flatMap { it.isRoaming }
+            .also { onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_ROAMING) } }
+
+    override val operatorAlphaShort: State<String?> =
+        activeRepo
+            .flatMap { it.operatorAlphaShort }
+            .also {
+                onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_OPERATOR) }
+            }
+
+    override val isInService: State<Boolean> =
+        activeRepo
+            .flatMap { it.isInService }
+            .also {
+                onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_IS_IN_SERVICE) }
+            }
+
+    override val isNonTerrestrial: State<Boolean> =
+        activeRepo
+            .flatMap { it.isNonTerrestrial }
+            .also { onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_IS_NTN) } }
+
+    override val isGsm: State<Boolean> =
+        activeRepo
+            .flatMap { it.isGsm }
+            .also { onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_IS_GSM) } }
+
+    override val cdmaLevel: State<Int> =
+        activeRepo
+            .flatMap { it.cdmaLevel }
+            .also {
+                onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_CDMA_LEVEL) }
+            }
+
+    override val primaryLevel: State<Int> =
+        activeRepo
+            .flatMap { it.primaryLevel }
+            .also {
+                onActivated { logDiffsForTable(it, tableLogBuffer, columnName = COL_PRIMARY_LEVEL) }
+            }
+
+    override val satelliteLevel: State<Int> =
+        activeRepo
+            .flatMap { it.satelliteLevel }
+            .also {
+                onActivated {
+                    logDiffsForTable(it, tableLogBuffer, columnName = COL_SATELLITE_LEVEL)
+                }
+            }
+
+    override val dataConnectionState: State<DataConnectionState> =
+        activeRepo
+            .flatMap { it.dataConnectionState }
+            .also { onActivated { logDiffsForTable(it, tableLogBuffer, columnPrefix = "") } }
+
+    override val dataActivityDirection: State<DataActivityModel> =
+        activeRepo
+            .flatMap { it.dataActivityDirection }
+            .also { onActivated { logDiffsForTable(it, tableLogBuffer, columnPrefix = "") } }
+
+    override val carrierNetworkChangeActive: State<Boolean> =
+        activeRepo
+            .flatMap { it.carrierNetworkChangeActive }
+            .also {
+                onActivated {
+                    logDiffsForTable(it, tableLogBuffer, columnName = COL_CARRIER_NETWORK_CHANGE)
+                }
+            }
+
+    override val resolvedNetworkType: State<ResolvedNetworkType> =
+        activeRepo
+            .flatMap { it.resolvedNetworkType }
+            .also { onActivated { logDiffsForTable(it, tableLogBuffer, columnPrefix = "") } }
+
+    override val dataEnabled: State<Boolean> =
+        activeRepo
+            .flatMap { it.dataEnabled }
+            .also {
+                onActivated { logDiffsForTable(it, tableLogBuffer, columnName = "dataEnabled") }
+            }
+
+    override val inflateSignalStrength: State<Boolean> =
+        activeRepo
+            .flatMap { it.inflateSignalStrength }
+            .also { onActivated { logDiffsForTable(it, tableLogBuffer, columnName = "inflate") } }
+
+    override val allowNetworkSliceIndicator: State<Boolean> =
+        activeRepo
+            .flatMap { it.allowNetworkSliceIndicator }
+            .also {
+                onActivated { logDiffsForTable(it, tableLogBuffer, columnName = "allowSlice") }
+            }
+
+    override val numberOfLevels: State<Int> = activeRepo.flatMap { it.numberOfLevels }
+
+    override val networkName: State<NetworkNameModel> =
+        activeRepo
+            .flatMap { it.networkName }
+            .also { onActivated { logDiffsForTable(it, tableLogBuffer, columnPrefix = "intent") } }
+
+    override val carrierName: State<NetworkNameModel> =
+        activeRepo
+            .flatMap { it.carrierName }
+            .also { onActivated { logDiffsForTable(it, tableLogBuffer, columnPrefix = "sub") } }
+
+    override val isAllowedDuringAirplaneMode: State<Boolean> =
+        activeRepo.flatMap { it.isAllowedDuringAirplaneMode }
+
+    override val hasPrioritizedNetworkCapabilities: State<Boolean> =
+        activeRepo.flatMap { it.hasPrioritizedNetworkCapabilities }
+
+    override val isInEcmMode: State<Boolean> = activeRepo.flatMap { it.isInEcmMode }
+
+    private var dumpCache: DumpCache? = null
+
+    private data class DumpCache(
+        val isCarrierMerged: Boolean,
+        val activeRepo: MobileConnectionRepositoryKairos,
+    )
+
+    fun dump(pw: PrintWriter) {
+        val cache = dumpCache ?: return
+        val ipw = IndentingPrintWriter(pw, "  ")
+
+        ipw.println("MobileConnectionRepository[$subId]")
+        ipw.increaseIndent()
+
+        ipw.println("carrierMerged=${cache.isCarrierMerged}")
+
+        ipw.print("Type (cellular or carrier merged): ")
+        when (cache.activeRepo) {
+            is CarrierMergedConnectionRepositoryKairos -> ipw.println("Carrier merged")
+            is MobileConnectionRepositoryKairosImpl -> ipw.println("Cellular")
+        }
+
+        ipw.increaseIndent()
+        ipw.println("Provider: ${cache.activeRepo}")
+        ipw.decreaseIndent()
+
+        ipw.decreaseIndent()
+    }
+
+    @AssistedFactory
+    interface Factory {
+        fun create(
+            subId: Int,
+            mobileLogger: TableLogBuffer,
+            isCarrierMerged: State<Boolean>,
+            mobileRepo: MobileConnectionRepositoryKairos,
+            mergedRepoSpec: BuildSpec<MobileConnectionRepositoryKairos>,
+        ): FullMobileConnectionRepositoryKairos
+    }
+
+    companion object {
+        const val COL_CARRIER_ID = "carrierId"
+        const val COL_CARRIER_NETWORK_CHANGE = "carrierNetworkChangeActive"
+        const val COL_CDMA_LEVEL = "cdmaLevel"
+        const val COL_EMERGENCY = "emergencyOnly"
+        const val COL_IS_NTN = "isNtn"
+        const val COL_IS_GSM = "isGsm"
+        const val COL_IS_IN_SERVICE = "isInService"
+        const val COL_OPERATOR = "operatorName"
+        const val COL_PRIMARY_LEVEL = "primaryLevel"
+        const val COL_SATELLITE_LEVEL = "satelliteLevel"
+        const val COL_ROAMING = "roaming"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
index b4a45e2..bf7c299 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryImpl.kt
@@ -542,6 +542,10 @@
 
     data class OnCarrierRoamingNtnSignalStrengthChanged(val signalStrength: NtnSignalStrength) :
         CallbackEvent
+
+    data class OnCallBackModeStarted(val type: Int) : CallbackEvent
+
+    data class OnCallBackModeStopped(val type: Int) : CallbackEvent
 }
 
 /**
@@ -560,6 +564,8 @@
     val onCarrierRoamingNtnSignalStrengthChanged:
         CallbackEvent.OnCarrierRoamingNtnSignalStrengthChanged? =
         null,
+    val addedCallbackModes: Set<Int> = emptySet(),
+    val removedCallbackModes: Set<Int> = emptySet(),
 ) {
     fun applyEvent(event: CallbackEvent): TelephonyCallbackState {
         return when (event) {
@@ -578,6 +584,37 @@
             is CallbackEvent.OnSignalStrengthChanged -> copy(onSignalStrengthChanged = event)
             is CallbackEvent.OnCarrierRoamingNtnSignalStrengthChanged ->
                 copy(onCarrierRoamingNtnSignalStrengthChanged = event)
+            is CallbackEvent.OnCallBackModeStarted -> {
+                copy(
+                    addedCallbackModes =
+                        if (event.type !in removedCallbackModes) {
+                            addedCallbackModes + event.type
+                        } else {
+                            addedCallbackModes
+                        },
+                    removedCallbackModes =
+                        if (event.type !in addedCallbackModes) {
+                            removedCallbackModes - event.type
+                        } else {
+                            removedCallbackModes
+                        },
+                )
+            }
+            is CallbackEvent.OnCallBackModeStopped ->
+                copy(
+                    addedCallbackModes =
+                        if (event.type !in removedCallbackModes) {
+                            addedCallbackModes - event.type
+                        } else {
+                            addedCallbackModes
+                        },
+                    removedCallbackModes =
+                        if (event.type !in addedCallbackModes) {
+                            removedCallbackModes + event.type
+                        } else {
+                            removedCallbackModes
+                        },
+                )
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosAdapter.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosAdapter.kt
new file mode 100644
index 0000000..9b37f48
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosAdapter.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.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import com.android.systemui.kairos.BuildScope
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.util.kotlin.Producer
+import kotlinx.coroutines.flow.StateFlow
+
+@ExperimentalKairosApi
+fun BuildScope.MobileConnectionRepositoryKairosAdapter(
+    kairosRepo: MobileConnectionRepositoryKairos,
+    carrierConfig: SystemUiCarrierConfig,
+) =
+    MobileConnectionRepositoryKairosAdapter(
+        subId = kairosRepo.subId,
+        carrierId = kairosRepo.carrierId.toStateFlow(),
+        inflateSignalStrength = carrierConfig.shouldInflateSignalStrength,
+        allowNetworkSliceIndicator = carrierConfig.allowNetworkSliceIndicator,
+        tableLogBuffer = kairosRepo.tableLogBuffer,
+        isEmergencyOnly = kairosRepo.isEmergencyOnly.toStateFlow(),
+        isRoaming = kairosRepo.isRoaming.toStateFlow(),
+        operatorAlphaShort = kairosRepo.operatorAlphaShort.toStateFlow(),
+        isInService = kairosRepo.isInService.toStateFlow(),
+        isNonTerrestrial = kairosRepo.isNonTerrestrial.toStateFlow(),
+        isGsm = kairosRepo.isGsm.toStateFlow(),
+        cdmaLevel = kairosRepo.cdmaLevel.toStateFlow(),
+        primaryLevel = kairosRepo.primaryLevel.toStateFlow(),
+        satelliteLevel = kairosRepo.satelliteLevel.toStateFlow(),
+        dataConnectionState = kairosRepo.dataConnectionState.toStateFlow(),
+        dataActivityDirection = kairosRepo.dataActivityDirection.toStateFlow(),
+        carrierNetworkChangeActive = kairosRepo.carrierNetworkChangeActive.toStateFlow(),
+        resolvedNetworkType = kairosRepo.resolvedNetworkType.toStateFlow(),
+        numberOfLevels = kairosRepo.numberOfLevels.toStateFlow(),
+        dataEnabled = kairosRepo.dataEnabled.toStateFlow(),
+        cdmaRoaming = kairosRepo.cdmaRoaming.toStateFlow(),
+        networkName = kairosRepo.networkName.toStateFlow(),
+        carrierName = kairosRepo.carrierName.toStateFlow(),
+        isAllowedDuringAirplaneMode = kairosRepo.isAllowedDuringAirplaneMode.toStateFlow(),
+        hasPrioritizedNetworkCapabilities =
+            kairosRepo.hasPrioritizedNetworkCapabilities.toStateFlow(),
+        isInEcmMode = { kairosNetwork.transact { kairosRepo.isInEcmMode.sample() } },
+    )
+
+@ExperimentalKairosApi
+class MobileConnectionRepositoryKairosAdapter(
+    override val subId: Int,
+    override val carrierId: StateFlow<Int>,
+    override val inflateSignalStrength: StateFlow<Boolean>,
+    override val allowNetworkSliceIndicator: StateFlow<Boolean>,
+    override val tableLogBuffer: TableLogBuffer,
+    override val isEmergencyOnly: StateFlow<Boolean>,
+    override val isRoaming: StateFlow<Boolean>,
+    override val operatorAlphaShort: StateFlow<String?>,
+    override val isInService: StateFlow<Boolean>,
+    override val isNonTerrestrial: StateFlow<Boolean>,
+    override val isGsm: StateFlow<Boolean>,
+    override val cdmaLevel: StateFlow<Int>,
+    override val primaryLevel: StateFlow<Int>,
+    override val satelliteLevel: StateFlow<Int>,
+    override val dataConnectionState: StateFlow<DataConnectionState>,
+    override val dataActivityDirection: StateFlow<DataActivityModel>,
+    override val carrierNetworkChangeActive: StateFlow<Boolean>,
+    override val resolvedNetworkType: StateFlow<ResolvedNetworkType>,
+    override val numberOfLevels: StateFlow<Int>,
+    override val dataEnabled: StateFlow<Boolean>,
+    override val cdmaRoaming: StateFlow<Boolean>,
+    override val networkName: StateFlow<NetworkNameModel>,
+    override val carrierName: StateFlow<NetworkNameModel>,
+    override val isAllowedDuringAirplaneMode: StateFlow<Boolean>,
+    override val hasPrioritizedNetworkCapabilities: StateFlow<Boolean>,
+    private val isInEcmMode: Producer<Boolean>,
+) : MobileConnectionRepository {
+    override suspend fun isInEcmMode(): Boolean = isInEcmMode.get()
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosImpl.kt
new file mode 100644
index 0000000..abe72e1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryKairosImpl.kt
@@ -0,0 +1,485 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import android.annotation.SuppressLint
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.net.ConnectivityManager
+import android.net.ConnectivityManager.NetworkCallback
+import android.net.Network
+import android.net.NetworkCapabilities
+import android.net.NetworkRequest
+import android.telephony.CellSignalStrength.SIGNAL_STRENGTH_NONE_OR_UNKNOWN
+import android.telephony.CellSignalStrengthCdma
+import android.telephony.ServiceState
+import android.telephony.SignalStrength
+import android.telephony.SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_NONE
+import android.telephony.TelephonyManager
+import android.telephony.TelephonyManager.ERI_FLASH
+import android.telephony.TelephonyManager.ERI_ON
+import android.telephony.TelephonyManager.EXTRA_SUBSCRIPTION_ID
+import android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN
+import android.telephony.TelephonyManager.UNKNOWN_CARRIER_ID
+import com.android.settingslib.Utils
+import com.android.systemui.KairosBuilder
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags.ROAMING_INDICATOR_VIA_DISPLAY_INFO
+import com.android.systemui.kairos.Events
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.Transactional
+import com.android.systemui.kairos.awaitClose
+import com.android.systemui.kairos.coalescingEvents
+import com.android.systemui.kairos.conflatedEvents
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.mapNotNull
+import com.android.systemui.kairos.stateOf
+import com.android.systemui.kairos.transactionally
+import com.android.systemui.kairosBuilder
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Disconnected
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.DefaultNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.OverrideNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.toDataConnectionType
+import com.android.systemui.statusbar.pipeline.mobile.data.model.toNetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.toMobileDataActivityModel
+import dagger.assisted.Assisted
+import dagger.assisted.AssistedFactory
+import dagger.assisted.AssistedInject
+import java.time.Duration
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.asExecutor
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.scan
+import kotlinx.coroutines.withContext
+
+/**
+ * A repository implementation for a typical mobile connection (as opposed to a carrier merged
+ * connection -- see [CarrierMergedConnectionRepository]).
+ */
+@ExperimentalKairosApi
+class MobileConnectionRepositoryKairosImpl
+@AssistedInject
+constructor(
+    @Assisted override val subId: Int,
+    private val context: Context,
+    @Assisted subscriptionModel: State<SubscriptionModel?>,
+    @Assisted defaultNetworkName: NetworkNameModel,
+    @Assisted networkNameSeparator: String,
+    connectivityManager: ConnectivityManager,
+    @Assisted private val telephonyManager: TelephonyManager,
+    @Assisted systemUiCarrierConfig: SystemUiCarrierConfig,
+    broadcastDispatcher: BroadcastDispatcher,
+    private val mobileMappingsProxy: MobileMappingsProxy,
+    @Background private val bgDispatcher: CoroutineDispatcher,
+    logger: MobileInputLogger,
+    @Assisted override val tableLogBuffer: TableLogBuffer,
+    flags: FeatureFlagsClassic,
+) : MobileConnectionRepositoryKairos, KairosBuilder by kairosBuilder() {
+
+    init {
+        if (telephonyManager.subscriptionId != subId) {
+            throw IllegalStateException(
+                "MobileRepo: TelephonyManager should be created with subId($subId). " +
+                    "Found ${telephonyManager.subscriptionId} instead."
+            )
+        }
+    }
+
+    /**
+     * This flow defines the single shared connection to system_server via TelephonyCallback. Any
+     * new callback should be added to this listener and funneled through callbackEvents via a data
+     * class. See [CallbackEvent] for defining new callbacks.
+     *
+     * The reason we need to do this is because TelephonyManager limits the number of registered
+     * listeners per-process, so we don't want to create a new listener for every callback.
+     *
+     * A note on the design for back pressure here: We don't control _which_ telephony callback
+     * comes in first, since we register every relevant bit of information as a batch. E.g., if a
+     * downstream starts collecting on a field which is backed by
+     * [TelephonyCallback.ServiceStateListener], it's not possible for us to guarantee that _that_
+     * callback comes in -- the first callback could very well be
+     * [TelephonyCallback.DataActivityListener], which would promptly be dropped if we didn't keep
+     * it tracked. We use the [scan] operator here to track the most recent callback of _each type_
+     * here. See [TelephonyCallbackState] to see how the callbacks are stored.
+     */
+    private val callbackEvents: Events<TelephonyCallbackState> = buildEvents {
+        coalescingEvents(
+            initialValue = TelephonyCallbackState(),
+            coalesce = TelephonyCallbackState::applyEvent,
+        ) {
+            val callback =
+                object :
+                    TelephonyCallback(),
+                    TelephonyCallback.CarrierNetworkListener,
+                    TelephonyCallback.CarrierRoamingNtnListener,
+                    TelephonyCallback.DataActivityListener,
+                    TelephonyCallback.DataConnectionStateListener,
+                    TelephonyCallback.DataEnabledListener,
+                    TelephonyCallback.DisplayInfoListener,
+                    TelephonyCallback.ServiceStateListener,
+                    TelephonyCallback.SignalStrengthsListener,
+                    TelephonyCallback.EmergencyCallbackModeListener {
+
+                    override fun onCarrierNetworkChange(active: Boolean) {
+                        logger.logOnCarrierNetworkChange(active, subId)
+                        emit(CallbackEvent.OnCarrierNetworkChange(active))
+                    }
+
+                    override fun onCarrierRoamingNtnModeChanged(active: Boolean) {
+                        logger.logOnCarrierRoamingNtnModeChanged(active)
+                        emit(CallbackEvent.OnCarrierRoamingNtnModeChanged(active))
+                    }
+
+                    override fun onDataActivity(direction: Int) {
+                        logger.logOnDataActivity(direction, subId)
+                        emit(CallbackEvent.OnDataActivity(direction))
+                    }
+
+                    override fun onDataEnabledChanged(enabled: Boolean, reason: Int) {
+                        logger.logOnDataEnabledChanged(enabled, subId)
+                        emit(CallbackEvent.OnDataEnabledChanged(enabled))
+                    }
+
+                    override fun onDataConnectionStateChanged(dataState: Int, networkType: Int) {
+                        logger.logOnDataConnectionStateChanged(dataState, networkType, subId)
+                        emit(CallbackEvent.OnDataConnectionStateChanged(dataState))
+                    }
+
+                    override fun onDisplayInfoChanged(telephonyDisplayInfo: TelephonyDisplayInfo) {
+                        logger.logOnDisplayInfoChanged(telephonyDisplayInfo, subId)
+                        emit(CallbackEvent.OnDisplayInfoChanged(telephonyDisplayInfo))
+                    }
+
+                    override fun onServiceStateChanged(serviceState: ServiceState) {
+                        logger.logOnServiceStateChanged(serviceState, subId)
+                        emit(CallbackEvent.OnServiceStateChanged(serviceState))
+                    }
+
+                    override fun onSignalStrengthsChanged(signalStrength: SignalStrength) {
+                        logger.logOnSignalStrengthsChanged(signalStrength, subId)
+                        emit(CallbackEvent.OnSignalStrengthChanged(signalStrength))
+                    }
+
+                    override fun onCallbackModeStarted(
+                        type: Int,
+                        timerDuration: Duration,
+                        subId: Int,
+                    ) {
+                        // logger.logOnCallBackModeStarted(type, subId)
+                        emit(CallbackEvent.OnCallBackModeStarted(type))
+                    }
+
+                    override fun onCallbackModeRestarted(
+                        type: Int,
+                        timerDuration: Duration,
+                        subId: Int,
+                    ) {
+                        // no-op
+                    }
+
+                    override fun onCallbackModeStopped(type: Int, reason: Int, subId: Int) {
+                        // logger.logOnCallBackModeStopped(type, reason, subId)
+                        emit(CallbackEvent.OnCallBackModeStopped(type))
+                    }
+                }
+            withContext(bgDispatcher) {
+                telephonyManager.registerTelephonyCallback(bgDispatcher.asExecutor(), callback)
+            }
+            awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
+        }
+    }
+
+    private val serviceState: State<ServiceState?> = buildState {
+        callbackEvents.mapNotNull { it.onServiceStateChanged?.serviceState }.holdState(null)
+    }
+
+    override val isEmergencyOnly: State<Boolean> = serviceState.map { it?.isEmergencyOnly == true }
+
+    private val displayInfo: State<TelephonyDisplayInfo?> = buildState {
+        callbackEvents.mapNotNull { it.onDisplayInfoChanged?.telephonyDisplayInfo }.holdState(null)
+    }
+
+    override val isRoaming: State<Boolean> =
+        if (flags.isEnabled(ROAMING_INDICATOR_VIA_DISPLAY_INFO)) {
+            displayInfo.map { it?.isRoaming == true }
+        } else {
+            serviceState.map { it?.roaming == true }
+        }
+
+    override val operatorAlphaShort: State<String?> = serviceState.map { it?.operatorAlphaShort }
+
+    override val isInService: State<Boolean> =
+        serviceState.map { it?.let(Utils::isInService) == true }
+
+    private val carrierRoamingNtnActive: State<Boolean> = buildState {
+        callbackEvents.mapNotNull { it.onCarrierRoamingNtnModeChanged?.active }.holdState(false)
+    }
+
+    override val isNonTerrestrial: State<Boolean>
+        get() = carrierRoamingNtnActive
+
+    private val signalStrength: State<SignalStrength?> = buildState {
+        callbackEvents.mapNotNull { it.onSignalStrengthChanged?.signalStrength }.holdState(null)
+    }
+
+    override val isGsm: State<Boolean> = signalStrength.map { it?.isGsm == true }
+
+    override val cdmaLevel: State<Int> =
+        signalStrength.map {
+            it?.getCellSignalStrengths(CellSignalStrengthCdma::class.java)?.firstOrNull()?.level
+                ?: SIGNAL_STRENGTH_NONE_OR_UNKNOWN
+        }
+
+    override val primaryLevel: State<Int> =
+        signalStrength.map { it?.level ?: SIGNAL_STRENGTH_NONE_OR_UNKNOWN }
+
+    override val satelliteLevel: State<Int> = buildState {
+        callbackEvents
+            .mapNotNull { it.onCarrierRoamingNtnSignalStrengthChanged?.signalStrength?.level }
+            .holdState(0)
+    }
+
+    override val dataConnectionState: State<DataConnectionState> = buildState {
+        callbackEvents
+            .mapNotNull { it.onDataConnectionStateChanged?.dataState?.toDataConnectionType() }
+            .holdState(Disconnected)
+    }
+
+    override val dataActivityDirection: State<DataActivityModel> = buildState {
+        callbackEvents
+            .mapNotNull { it.onDataActivity?.direction?.toMobileDataActivityModel() }
+            .holdState(DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+    }
+
+    override val carrierNetworkChangeActive: State<Boolean> = buildState {
+        callbackEvents.mapNotNull { it.onCarrierNetworkChange?.active }.holdState(false)
+    }
+
+    private val telephonyDisplayInfo: State<TelephonyDisplayInfo?> = buildState {
+        callbackEvents.mapNotNull { it.onDisplayInfoChanged?.telephonyDisplayInfo }.holdState(null)
+    }
+
+    override val resolvedNetworkType: State<ResolvedNetworkType> =
+        telephonyDisplayInfo.map { displayInfo ->
+            displayInfo
+                ?.overrideNetworkType
+                ?.takeIf { it != OVERRIDE_NETWORK_TYPE_NONE }
+                ?.let { OverrideNetworkType(mobileMappingsProxy.toIconKeyOverride(it)) }
+                ?: displayInfo
+                    ?.networkType
+                    ?.takeIf { it != NETWORK_TYPE_UNKNOWN }
+                    ?.let { DefaultNetworkType(mobileMappingsProxy.toIconKey(it)) }
+                ?: UnknownNetworkType
+        }
+
+    override val inflateSignalStrength: State<Boolean> = buildState {
+        systemUiCarrierConfig.shouldInflateSignalStrength.toState()
+    }
+
+    override val allowNetworkSliceIndicator: State<Boolean> = buildState {
+        systemUiCarrierConfig.allowNetworkSliceIndicator.toState()
+    }
+
+    override val numberOfLevels: State<Int> =
+        inflateSignalStrength.map { shouldInflate ->
+            if (shouldInflate) {
+                DEFAULT_NUM_LEVELS + 1
+            } else {
+                DEFAULT_NUM_LEVELS
+            }
+        }
+
+    override val carrierName: State<NetworkNameModel> =
+        subscriptionModel.map {
+            it?.let { model -> NetworkNameModel.SubscriptionDerived(model.carrierName) }
+                ?: defaultNetworkName
+        }
+
+    /**
+     * There are a few cases where we will need to poll [TelephonyManager] so we can update some
+     * internal state where callbacks aren't provided. Any of those events should be merged into
+     * this flow, which can be used to trigger the polling.
+     */
+    private val telephonyPollingEvent: Events<Unit> = callbackEvents.map {}
+
+    private val cdmaEnhancedRoamingIndicatorDisplayNumber: Transactional<Int?> = transactionally {
+        try {
+            telephonyManager.cdmaEnhancedRoamingIndicatorDisplayNumber
+        } catch (e: UnsupportedOperationException) {
+            // Handles the same as a function call failure
+            null
+        }
+    }
+
+    override val cdmaRoaming: State<Boolean> = buildState {
+        telephonyPollingEvent
+            .map {
+                val cdmaEri = cdmaEnhancedRoamingIndicatorDisplayNumber.sample()
+                cdmaEri == ERI_ON || cdmaEri == ERI_FLASH
+            }
+            .holdState(false)
+    }
+
+    override val carrierId: State<Int> = buildState {
+        broadcastDispatcher
+            .broadcastFlow(
+                filter =
+                    IntentFilter(TelephonyManager.ACTION_SUBSCRIPTION_CARRIER_IDENTITY_CHANGED),
+                map = { intent, _ -> intent },
+            )
+            .filter { intent ->
+                intent.getIntExtra(EXTRA_SUBSCRIPTION_ID, INVALID_SUBSCRIPTION_ID) == subId
+            }
+            .map { it.carrierId() }
+            .toState(telephonyManager.simCarrierId)
+    }
+
+    /**
+     * BroadcastDispatcher does not handle sticky broadcasts, so we can't use it here. Note that we
+     * now use the [SharingStarted.Eagerly] strategy, because there have been cases where the sticky
+     * broadcast does not represent the correct state.
+     *
+     * See b/322432056 for context.
+     */
+    @SuppressLint("RegisterReceiverViaContext")
+    override val networkName: State<NetworkNameModel> = buildState {
+        conflatedEvents {
+                val receiver =
+                    object : BroadcastReceiver() {
+                        override fun onReceive(context: Context, intent: Intent) {
+                            if (
+                                intent.getIntExtra(
+                                    EXTRA_SUBSCRIPTION_INDEX,
+                                    INVALID_SUBSCRIPTION_ID,
+                                ) == subId
+                            ) {
+                                logger.logServiceProvidersUpdatedBroadcast(intent)
+                                emit(
+                                    intent.toNetworkNameModel(networkNameSeparator)
+                                        ?: defaultNetworkName
+                                )
+                            }
+                        }
+                    }
+
+                context.registerReceiver(
+                    receiver,
+                    IntentFilter(TelephonyManager.ACTION_SERVICE_PROVIDERS_UPDATED),
+                )
+
+                awaitClose { context.unregisterReceiver(receiver) }
+            }
+            .holdState(defaultNetworkName)
+    }
+
+    override val dataEnabled: State<Boolean> = buildState {
+        callbackEvents
+            .mapNotNull { it.onDataEnabledChanged?.enabled }
+            .holdState(telephonyManager.isDataConnectionAllowed)
+    }
+
+    override val isInEcmMode: State<Boolean> = buildState {
+        callbackEvents
+            .mapNotNull {
+                (it.addedCallbackModes to it.removedCallbackModes).takeIf { (added, removed) ->
+                    added.isNotEmpty() || removed.isNotEmpty()
+                }
+            }
+            .foldState(emptySet<Int>()) { (added, removed), acc -> acc - removed + added }
+            .mapTransactionally { it.isNotEmpty() }
+    }
+
+    /** Typical mobile connections aren't available during airplane mode. */
+    override val isAllowedDuringAirplaneMode: State<Boolean> = stateOf(false)
+
+    /**
+     * Currently, a network with NET_CAPABILITY_PRIORITIZE_LATENCY is the only type of network that
+     * we consider to be a "network slice". _PRIORITIZE_BANDWIDTH may be added in the future. Any of
+     * these capabilities that are used here must also be represented in the
+     * self_certified_network_capabilities.xml config file
+     */
+    @SuppressLint("WrongConstant")
+    private val networkSliceRequest: NetworkRequest =
+        NetworkRequest.Builder()
+            .addCapability(NetworkCapabilities.NET_CAPABILITY_PRIORITIZE_LATENCY)
+            .setSubscriptionIds(setOf(subId))
+            .build()
+
+    @SuppressLint("MissingPermission")
+    override val hasPrioritizedNetworkCapabilities: State<Boolean> = buildState {
+        conflatedEvents {
+                // Our network callback listens only for this.subId && net_cap_prioritize_latency
+                // therefore our state is a simple mapping of whether or not that network exists
+                val callback =
+                    object : NetworkCallback() {
+                        override fun onAvailable(network: Network) {
+                            logger.logPrioritizedNetworkAvailable(network.netId)
+                            emit(true)
+                        }
+
+                        override fun onLost(network: Network) {
+                            logger.logPrioritizedNetworkLost(network.netId)
+                            emit(false)
+                        }
+                    }
+
+                connectivityManager.registerNetworkCallback(networkSliceRequest, callback)
+
+                awaitClose { connectivityManager.unregisterNetworkCallback(callback) }
+            }
+            .holdState(false)
+    }
+
+    @AssistedFactory
+    fun interface Factory {
+        fun create(
+            subId: Int,
+            mobileLogger: TableLogBuffer,
+            subscriptionModel: State<SubscriptionModel?>,
+            defaultNetworkName: NetworkNameModel,
+            networkNameSeparator: String,
+            systemUiCarrierConfig: SystemUiCarrierConfig,
+            telephonyManager: TelephonyManager,
+        ): MobileConnectionRepositoryKairosImpl
+    }
+}
+
+private fun Intent.carrierId(): Int =
+    getIntExtra(TelephonyManager.EXTRA_CARRIER_ID, UNKNOWN_CARRIER_ID)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
index 2efc057..d6105c2 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryImpl.kt
@@ -192,20 +192,16 @@
     override val isDeviceEmergencyCallCapable: StateFlow<Boolean> =
         serviceStateChangedEvent
             .mapLatest {
-                val modems = telephonyManager.activeModemCount
-
-                // Assume false for automotive devices which don't have the calling feature.
-                // TODO: b/398045526 to revisit the below.
-                val isAutomotive: Boolean =
-                    context.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
-                val hasFeatureCalling: Boolean =
+                // TODO(b/400460777): check for hasSystemFeature only once
+                val hasRadioAccess: Boolean =
                     context.packageManager.hasSystemFeature(
-                        PackageManager.FEATURE_TELEPHONY_CALLING
+                        PackageManager.FEATURE_TELEPHONY_RADIO_ACCESS
                     )
-                if (isAutomotive && !hasFeatureCalling) {
+                if (!hasRadioAccess) {
                     return@mapLatest false
                 }
 
+                val modems = telephonyManager.activeModemCount
                 // Check the service state for every modem. If any state reports emergency calling
                 // capable, then consider the device to have emergency call capabilities
                 (0..<modems)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosImpl.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosImpl.kt
new file mode 100644
index 0000000..e468159
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionsRepositoryKairosImpl.kt
@@ -0,0 +1,584 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository.prod
+
+import android.annotation.SuppressLint
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.content.pm.PackageManager
+import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionInfo
+import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.TelephonyCallback
+import android.telephony.TelephonyCallback.ActiveDataSubscriptionIdListener
+import android.telephony.TelephonyCallback.EmergencyCallbackModeListener
+import android.telephony.TelephonyManager
+import android.util.IndentingPrintWriter
+import com.android.internal.telephony.PhoneConstants
+import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.keyguard.KeyguardUpdateMonitorCallback
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.MobileMappings.Config
+import com.android.systemui.Dumpable
+import com.android.systemui.Flags
+import com.android.systemui.KairosActivatable
+import com.android.systemui.KairosBuilder
+import com.android.systemui.activated
+import com.android.systemui.broadcast.BroadcastDispatcher
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.kairos.BuildSpec
+import com.android.systemui.kairos.Events
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.Incremental
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.StateSelector
+import com.android.systemui.kairos.asIncremental
+import com.android.systemui.kairos.asyncEvent
+import com.android.systemui.kairos.buildSpec
+import com.android.systemui.kairos.changes
+import com.android.systemui.kairos.combine
+import com.android.systemui.kairos.effect
+import com.android.systemui.kairos.filterNotNull
+import com.android.systemui.kairos.flatMap
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.mapNotNull
+import com.android.systemui.kairos.mapValues
+import com.android.systemui.kairos.mergeLeft
+import com.android.systemui.kairos.onEach
+import com.android.systemui.kairos.rebuildOn
+import com.android.systemui.kairos.selector
+import com.android.systemui.kairos.stateOf
+import com.android.systemui.kairos.switchEvents
+import com.android.systemui.kairos.transitions
+import com.android.systemui.kairos.util.WithPrev
+import com.android.systemui.kairosBuilder
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.TableLogBufferFactory
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.res.R
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.AirplaneModeRepository
+import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.CarrierConfigRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxy
+import com.android.systemui.statusbar.pipeline.shared.data.model.DefaultConnectionModel
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.WifiRepository
+import com.android.systemui.statusbar.pipeline.wifi.shared.model.WifiNetworkModel
+import com.android.systemui.utils.coroutines.flow.conflatedCallbackFlow
+import dagger.Binds
+import dagger.Lazy
+import dagger.Provides
+import dagger.multibindings.ElementsIntoSet
+import java.io.PrintWriter
+import java.time.Duration
+import javax.inject.Inject
+import javax.inject.Provider
+import kotlinx.coroutines.CoroutineDispatcher
+import kotlinx.coroutines.channels.awaitClose
+import kotlinx.coroutines.flow.callbackFlow
+import kotlinx.coroutines.flow.flowOn
+import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.withContext
+
+@ExperimentalKairosApi
+@SysUISingleton
+class MobileConnectionsRepositoryKairosImpl
+@Inject
+constructor(
+    connectivityRepository: ConnectivityRepository,
+    private val subscriptionManager: SubscriptionManager,
+    private val subscriptionManagerProxy: SubscriptionManagerProxy,
+    private val telephonyManager: TelephonyManager,
+    private val logger: MobileInputLogger,
+    @MobileSummaryLog private val tableLogger: TableLogBuffer,
+    mobileMappingsProxy: MobileMappingsProxy,
+    broadcastDispatcher: BroadcastDispatcher,
+    private val context: Context,
+    @Background private val bgDispatcher: CoroutineDispatcher,
+    @Main private val mainDispatcher: CoroutineDispatcher,
+    airplaneModeRepository: AirplaneModeRepository,
+    // Some "wifi networks" should be rendered as a mobile connection, which is why the wifi
+    // repository is an input to the mobile repository.
+    // See [CarrierMergedConnectionRepositoryKairos] for details.
+    wifiRepository: WifiRepository,
+    private val keyguardUpdateMonitor: KeyguardUpdateMonitor,
+    dumpManager: DumpManager,
+    private val mobileRepoFactory: Lazy<ConnectionRepoFactory>,
+) : MobileConnectionsRepositoryKairos, Dumpable, KairosBuilder by kairosBuilder() {
+
+    init {
+        dumpManager.registerNormalDumpable("MobileConnectionsRepositoryKairos", this)
+    }
+
+    private val carrierMergedSubId: State<Int?> = buildState {
+        combine(
+                wifiRepository.wifiNetwork.toState(),
+                connectivityRepository.defaultConnections.toState(),
+                airplaneModeRepository.isAirplaneMode.toState(),
+            ) { wifiNetwork, defaultConnections, isAirplaneMode ->
+                // The carrier merged connection should only be used if it's also the default
+                // connection or mobile connections aren't available because of airplane mode.
+                val defaultConnectionIsNonMobile =
+                    defaultConnections.carrierMerged.isDefault ||
+                        defaultConnections.wifi.isDefault ||
+                        isAirplaneMode
+
+                if (wifiNetwork is WifiNetworkModel.CarrierMerged && defaultConnectionIsNonMobile) {
+                    wifiNetwork.subscriptionId
+                } else {
+                    null
+                }
+            }
+            .also {
+                logDiffsForTable(it, tableLogger, LOGGING_PREFIX, columnName = "carrierMergedSubId")
+            }
+    }
+
+    private val mobileSubscriptionsChangeEvent: Events<Unit> = buildEvents {
+        conflatedCallbackFlow {
+                val callback =
+                    object : SubscriptionManager.OnSubscriptionsChangedListener() {
+                        override fun onSubscriptionsChanged() {
+                            logger.logOnSubscriptionsChanged()
+                            trySend(Unit)
+                        }
+                    }
+                subscriptionManager.addOnSubscriptionsChangedListener(Runnable::run, callback)
+                awaitClose { subscriptionManager.removeOnSubscriptionsChangedListener(callback) }
+            }
+            .flowOn(bgDispatcher)
+            .toEvents()
+    }
+
+    /** Turn ACTION_SERVICE_STATE (for subId = -1) into an event */
+    private val serviceStateChangedEvent: Events<Unit> = buildEvents {
+        broadcastDispatcher
+            .broadcastFlow(IntentFilter(Intent.ACTION_SERVICE_STATE)) { intent, _ ->
+                val subId =
+                    intent.getIntExtra(
+                        SubscriptionManager.EXTRA_SUBSCRIPTION_INDEX,
+                        INVALID_SUBSCRIPTION_ID,
+                    )
+
+                // Only emit if the subId is not associated with an active subscription
+                if (subId == INVALID_SUBSCRIPTION_ID) {
+                    Unit
+                }
+            }
+            .toEvents()
+    }
+
+    /** Eager flow to determine the device-based emergency calls only state */
+    override val isDeviceEmergencyCallCapable: State<Boolean> = buildState {
+        rebuildOn(serviceStateChangedEvent) { asyncEvent { doAnyModemsSupportEmergencyCalls() } }
+            .switchEvents()
+            .holdState(false)
+            .also {
+                logDiffsForTable(
+                    it,
+                    tableLogger,
+                    LOGGING_PREFIX,
+                    columnName = "deviceEmergencyOnly",
+                )
+            }
+    }
+
+    private suspend fun doAnyModemsSupportEmergencyCalls(): Boolean =
+        withContext(bgDispatcher) {
+            val modems = telephonyManager.activeModemCount
+
+            // Assume false for automotive devices which don't have the calling feature.
+            // TODO: b/398045526 to revisit the below.
+            val isAutomotive: Boolean =
+                context.packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE)
+            val hasFeatureCalling: Boolean =
+                context.packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CALLING)
+            if (isAutomotive && !hasFeatureCalling) {
+                return@withContext false
+            }
+
+            // Check the service state for every modem. If any state reports emergency calling
+            // capable, then consider the device to have emergency call capabilities
+            (0..<modems)
+                .map { telephonyManager.getServiceStateForSlot(it) }
+                .any { it?.isEmergencyOnly == true }
+        }
+
+    /**
+     * State flow that emits the set of mobile data subscriptions, each represented by its own
+     * [SubscriptionModel].
+     */
+    override val subscriptions: State<List<SubscriptionModel>> = buildState {
+        rebuildOn(mergeLeft(mobileSubscriptionsChangeEvent, carrierMergedSubId.changes)) {
+                asyncEvent { fetchSubscriptionModels() }
+            }
+            .switchEvents()
+            .holdState(emptyList())
+            .also {
+                logDiffsForTable(it, tableLogger, LOGGING_PREFIX, columnName = "subscriptions")
+            }
+    }
+
+    val subscriptionsById: State<Map<Int, SubscriptionModel>> =
+        subscriptions.map { subs -> subs.associateBy { it.subscriptionId } }
+
+    override val mobileConnectionsBySubId: Incremental<Int, MobileConnectionRepositoryKairos> =
+        buildIncremental {
+            subscriptionsById
+                .asIncremental()
+                .mapValues { (subId, sub) -> mobileRepoFactory.get().create(subId) }
+                .applyLatestSpecForKey()
+        }
+
+    private val telephonyManagerState: State<Pair<Int?, Set<Int>>> = buildState {
+        callbackFlow {
+                val callback =
+                    object :
+                        TelephonyCallback(),
+                        ActiveDataSubscriptionIdListener,
+                        EmergencyCallbackModeListener {
+                        override fun onActiveDataSubscriptionIdChanged(subId: Int) {
+                            if (subId != INVALID_SUBSCRIPTION_ID) {
+                                trySend { (_, set): Pair<Int?, Set<Int>> -> subId to set }
+                            } else {
+                                trySend { (_, set): Pair<Int?, Set<Int>> -> null to set }
+                            }
+                        }
+
+                        override fun onCallbackModeStarted(
+                            type: Int,
+                            timerDuration: Duration,
+                            subId: Int,
+                        ) {
+                            trySend { (id, set): Pair<Int?, Set<Int>> -> id to (set + type) }
+                        }
+
+                        override fun onCallbackModeRestarted(
+                            type: Int,
+                            timerDuration: Duration,
+                            subId: Int,
+                        ) {
+                            // no-op
+                        }
+
+                        override fun onCallbackModeStopped(type: Int, reason: Int, subId: Int) {
+                            trySend { (id, set): Pair<Int?, Set<Int>> -> id to (set - type) }
+                        }
+                    }
+                telephonyManager.registerTelephonyCallback(Runnable::run, callback)
+                awaitClose { telephonyManager.unregisterTelephonyCallback(callback) }
+            }
+            .flowOn(bgDispatcher)
+            .scanToState(null to emptySet())
+    }
+
+    override val activeMobileDataSubscriptionId: State<Int?> =
+        telephonyManagerState
+            .map { it.first }
+            .also {
+                onActivated {
+                    logDiffsForTable(it, tableLogger, LOGGING_PREFIX, columnName = "activeSubId")
+                }
+            }
+
+    override val activeMobileDataRepository: State<MobileConnectionRepositoryKairos?> =
+        combine(activeMobileDataSubscriptionId, mobileConnectionsBySubId) { id, cache -> cache[id] }
+
+    override val defaultDataSubId: State<Int?> = buildState {
+        broadcastDispatcher
+            .broadcastFlow(
+                IntentFilter(TelephonyManager.ACTION_DEFAULT_DATA_SUBSCRIPTION_CHANGED)
+            ) { intent, _ ->
+                intent
+                    .getIntExtra(PhoneConstants.SUBSCRIPTION_KEY, INVALID_SUBSCRIPTION_ID)
+                    .takeIf { it != INVALID_SUBSCRIPTION_ID }
+            }
+            .onStart {
+                emit(
+                    subscriptionManagerProxy.getDefaultDataSubscriptionId().takeIf {
+                        it != INVALID_SUBSCRIPTION_ID
+                    }
+                )
+            }
+            .toState(initialValue = null)
+            .also { logDiffsForTable(it, tableLogger, LOGGING_PREFIX, columnName = "defaultSubId") }
+    }
+
+    private val carrierConfigChangedEvent: Events<Unit> =
+        buildEvents {
+                broadcastDispatcher
+                    .broadcastFlow(IntentFilter(CarrierConfigManager.ACTION_CARRIER_CONFIG_CHANGED))
+                    .toEvents()
+            }
+            .onEach { logger.logActionCarrierConfigChanged() }
+
+    override val defaultDataSubRatConfig: State<Config> = buildState {
+        rebuildOn(mergeLeft(defaultDataSubId.changes, carrierConfigChangedEvent)) {
+            Config.readConfig(context).also { effect { logger.logDefaultDataSubRatConfig(it) } }
+        }
+    }
+
+    override val defaultMobileIconMapping: State<Map<String, MobileIconGroup>> = buildState {
+        defaultDataSubRatConfig
+            .map { mobileMappingsProxy.mapIconSets(it) }
+            .apply { observe { logger.logDefaultMobileIconMapping(it) } }
+    }
+
+    override val defaultMobileIconGroup: State<MobileIconGroup> = buildState {
+        defaultDataSubRatConfig
+            .map { mobileMappingsProxy.getDefaultIcons(it) }
+            .apply { observe { logger.logDefaultMobileIconGroup(it) } }
+    }
+
+    override val isAnySimSecure: State<Boolean> = buildState {
+        conflatedCallbackFlow {
+                val callback =
+                    object : KeyguardUpdateMonitorCallback() {
+                        override fun onSimStateChanged(subId: Int, slotId: Int, simState: Int) {
+                            logger.logOnSimStateChanged()
+                            trySend(keyguardUpdateMonitor.isSimPinSecure)
+                        }
+                    }
+                keyguardUpdateMonitor.registerCallback(callback)
+                awaitClose { keyguardUpdateMonitor.removeCallback(callback) }
+            }
+            .flowOn(mainDispatcher)
+            .toState(false)
+            .also {
+                logDiffsForTable(it, tableLogger, LOGGING_PREFIX, columnName = "isAnySimSecure")
+            }
+    }
+
+    private val defaultConnections: State<DefaultConnectionModel> = buildState {
+        connectivityRepository.defaultConnections.toState()
+    }
+
+    override val mobileIsDefault: State<Boolean> =
+        defaultConnections
+            .map { it.mobile.isDefault }
+            .also {
+                onActivated {
+                    logDiffsForTable(
+                        it,
+                        tableLogger,
+                        columnPrefix = LOGGING_PREFIX,
+                        columnName = "mobileIsDefault",
+                    )
+                }
+            }
+
+    override val hasCarrierMergedConnection: State<Boolean> =
+        carrierMergedSubId
+            .map { it != null }
+            .also {
+                onActivated {
+                    logDiffsForTable(
+                        it,
+                        tableLogger,
+                        columnPrefix = LOGGING_PREFIX,
+                        columnName = "hasCarrierMergedConnection",
+                    )
+                }
+            }
+
+    override val defaultConnectionIsValidated: State<Boolean> =
+        defaultConnections
+            .map { it.isValidated }
+            .also {
+                onActivated {
+                    logDiffsForTable(
+                        it,
+                        tableLogger,
+                        columnPrefix = LOGGING_PREFIX,
+                        columnName = "defaultConnectionIsValidated",
+                    )
+                }
+            }
+
+    /**
+     * Flow that tracks the active mobile data subscriptions. Emits `true` whenever the active data
+     * subscription Id changes but the subscription group remains the same. In these cases, we want
+     * to retain the previous subscription's validation status for up to 2s to avoid flickering the
+     * icon.
+     *
+     * TODO(b/265164432): we should probably expose all change events, not just same group
+     */
+    @SuppressLint("MissingPermission")
+    override val activeSubChangedInGroupEvent: Events<Unit> = buildEvents {
+        activeMobileDataSubscriptionId.transitions
+            .mapNotNull { (prevVal, newVal) ->
+                prevVal?.let { newVal?.let { WithPrev(prevVal, newVal) } }
+            }
+            .mapAsyncLatest { (prevVal, newVal) ->
+                if (isActiveSubChangeInGroup(prevVal, newVal)) Unit else null
+            }
+            .filterNotNull()
+    }
+
+    private suspend fun isActiveSubChangeInGroup(prevId: Int, newId: Int): Boolean =
+        withContext(bgDispatcher) {
+            val prevSub = subscriptionManager.getActiveSubscriptionInfo(prevId)?.groupUuid
+            val nextSub = subscriptionManager.getActiveSubscriptionInfo(newId)?.groupUuid
+            prevSub != null && prevSub == nextSub
+        }
+
+    private val isInEcmModeTopLevel: State<Boolean> =
+        telephonyManagerState.map { it.second.isNotEmpty() }
+
+    override val isInEcmMode: State<Boolean> =
+        isInEcmModeTopLevel.flatMap { isInEcm ->
+            if (isInEcm) {
+                stateOf(true)
+            } else {
+                mobileConnectionsBySubId.flatMap {
+                    it.mapValues { it.value.isInEcmMode }.combine().map { it.values.any { it } }
+                }
+            }
+        }
+
+    /** Determines which subId is currently carrier-merged. */
+    val carrierMergedSelector: StateSelector<Int?> = carrierMergedSubId.selector()
+
+    private suspend fun fetchSubscriptionModels(): List<SubscriptionModel> =
+        withContext(bgDispatcher) {
+            subscriptionManager.completeActiveSubscriptionInfoList.map { it.toSubscriptionModel() }
+        }
+
+    private fun SubscriptionInfo.toSubscriptionModel(): SubscriptionModel =
+        SubscriptionModel(
+            subscriptionId = subscriptionId,
+            isOpportunistic = isOpportunistic,
+            isExclusivelyNonTerrestrial = isOnlyNonTerrestrialNetwork,
+            groupUuid = groupUuid,
+            carrierName = carrierName.toString(),
+            profileClass = profileClass,
+        )
+
+    private var dumpCache: DumpCache? = null
+
+    private data class DumpCache(val repos: Map<Int, FullMobileConnectionRepositoryKairos>)
+
+    override fun dump(pw: PrintWriter, args: Array<String>) {
+        val cache = dumpCache ?: return
+        val ipw = IndentingPrintWriter(pw, " ")
+        ipw.println("Connection cache:")
+
+        ipw.increaseIndent()
+        cache.repos.forEach { (subId, repo) -> ipw.println("$subId: $repo") }
+        ipw.decreaseIndent()
+
+        ipw.println("Connections (${cache.repos.size} total):")
+        ipw.increaseIndent()
+        cache.repos.values.forEach { it.dump(ipw) }
+        ipw.decreaseIndent()
+    }
+
+    fun interface ConnectionRepoFactory {
+        fun create(subId: Int): BuildSpec<MobileConnectionRepositoryKairos>
+    }
+
+    @dagger.Module
+    object Module {
+        @Provides
+        @ElementsIntoSet
+        fun kairosActivatable(
+            impl: Provider<MobileConnectionsRepositoryKairosImpl>
+        ): Set<@JvmSuppressWildcards KairosActivatable> =
+            if (Flags.statusBarMobileIconKairos()) setOf(impl.get()) else emptySet()
+    }
+
+    companion object {
+        private const val LOGGING_PREFIX = "Repo"
+    }
+}
+
+@ExperimentalKairosApi
+class MobileConnectionRepositoryKairosFactoryImpl
+@Inject
+constructor(
+    context: Context,
+    private val connectionsRepo: MobileConnectionsRepositoryKairosImpl,
+    private val logFactory: TableLogBufferFactory,
+    private val carrierConfigRepo: CarrierConfigRepository,
+    private val telephonyManager: TelephonyManager,
+    private val mobileRepoFactory: MobileConnectionRepositoryKairosImpl.Factory,
+    private val mergedRepoFactory: CarrierMergedConnectionRepositoryKairos.Factory,
+) : MobileConnectionsRepositoryKairosImpl.ConnectionRepoFactory {
+
+    private val networkNameSeparator: String =
+        context.getString(R.string.status_bar_network_name_separator)
+
+    private val defaultNetworkName =
+        NetworkNameModel.Default(
+            context.getString(com.android.internal.R.string.lockscreen_carrier_default)
+        )
+
+    override fun create(subId: Int): BuildSpec<MobileConnectionRepositoryKairos> = buildSpec {
+        activated {
+            val mobileLogger =
+                logFactory.getOrCreate(tableBufferLogName(subId), MOBILE_CONNECTION_BUFFER_SIZE)
+            val mobileRepo = activated {
+                mobileRepoFactory.create(
+                    subId,
+                    mobileLogger,
+                    connectionsRepo.subscriptionsById.map { subs -> subs[subId] },
+                    defaultNetworkName,
+                    networkNameSeparator,
+                    carrierConfigRepo.getOrCreateConfigForSubId(subId),
+                    telephonyManager.createForSubscriptionId(subId),
+                )
+            }
+            FullMobileConnectionRepositoryKairos(
+                subId = subId,
+                tableLogBuffer = mobileLogger,
+                mobileRepo = mobileRepo,
+                carrierMergedRepoSpec =
+                    buildSpec {
+                        activated { mergedRepoFactory.build(subId, mobileLogger, mobileRepo) }
+                    },
+                isCarrierMerged = connectionsRepo.carrierMergedSelector[subId],
+            )
+        }
+    }
+
+    companion object {
+        /** The buffer size to use for logging. */
+        private const val MOBILE_CONNECTION_BUFFER_SIZE = 100
+
+        /** Returns a log buffer name for a mobile connection with the given [subId]. */
+        fun tableBufferLogName(subId: Int): String = "MobileConnectionLog[$subId]"
+    }
+
+    @dagger.Module
+    interface Module {
+        @Binds
+        fun bindImpl(
+            impl: MobileConnectionRepositoryKairosFactoryImpl
+        ): MobileConnectionsRepositoryKairosImpl.ConnectionRepoFactory
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairos.kt
new file mode 100644
index 0000000..4580ad9
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconInteractorKairos.kt
@@ -0,0 +1,380 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
+
+import android.content.Context
+import com.android.internal.telephony.flags.Flags
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.graph.SignalDrawable
+import com.android.settingslib.mobile.MobileIconCarrierIdOverrides
+import com.android.settingslib.mobile.MobileIconCarrierIdOverridesImpl
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState.Connected
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel.DefaultIcon
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.NetworkTypeIconModel.OverriddenIcon
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
+import com.android.systemui.statusbar.pipeline.satellite.ui.model.SatelliteIconModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.stateIn
+
+interface MobileIconInteractorKairos {
+    /** The table log created for this connection */
+    val tableLogBuffer: TableLogBuffer
+
+    /** The current mobile data activity */
+    val activity: Flow<DataActivityModel>
+
+    /** See [MobileConnectionsRepository.mobileIsDefault]. */
+    val mobileIsDefault: Flow<Boolean>
+
+    /**
+     * True when telephony tells us that the data state is CONNECTED. See
+     * [android.telephony.TelephonyCallback.DataConnectionStateListener] for more details. We
+     * consider this connection to be serving data, and thus want to show a network type icon, when
+     * data is connected. Other data connection states would typically cause us not to show the icon
+     */
+    val isDataConnected: StateFlow<Boolean>
+
+    /** True if we consider this connection to be in service, i.e. can make calls */
+    val isInService: StateFlow<Boolean>
+
+    /** True if this connection is emergency only */
+    val isEmergencyOnly: StateFlow<Boolean>
+
+    /** Observable for the data enabled state of this connection */
+    val isDataEnabled: StateFlow<Boolean>
+
+    /** True if the RAT icon should always be displayed and false otherwise. */
+    val alwaysShowDataRatIcon: StateFlow<Boolean>
+
+    /** Canonical representation of the current mobile signal strength as a triangle. */
+    val signalLevelIcon: StateFlow<SignalIconModel>
+
+    /** Observable for RAT type (network type) indicator */
+    val networkTypeIconGroup: StateFlow<NetworkTypeIconModel>
+
+    /** Whether or not to show the slice attribution */
+    val showSliceAttribution: StateFlow<Boolean>
+
+    /** True if this connection is satellite-based */
+    val isNonTerrestrial: StateFlow<Boolean>
+
+    /**
+     * Provider name for this network connection. The name can be one of 3 values:
+     * 1. The default network name, if one is configured
+     * 2. A derived name based off of the intent [ACTION_SERVICE_PROVIDERS_UPDATED]
+     * 3. Or, in the case where the repository sends us the default network name, we check for an
+     *    override in [connectionInfo.operatorAlphaShort], a value that is derived from
+     *    [ServiceState]
+     */
+    val networkName: StateFlow<NetworkNameModel>
+
+    /**
+     * Provider name for this network connection. The name can be one of 3 values:
+     * 1. The default network name, if one is configured
+     * 2. A name provided by the [SubscriptionModel] of this network connection
+     * 3. Or, in the case where the repository sends us the default network name, we check for an
+     *    override in [connectionInfo.operatorAlphaShort], a value that is derived from
+     *    [ServiceState]
+     *
+     * TODO(b/296600321): De-duplicate this field with [networkName] after determining the data
+     *   provided is identical
+     */
+    val carrierName: StateFlow<String>
+
+    /** True if there is only one active subscription. */
+    val isSingleCarrier: StateFlow<Boolean>
+
+    /**
+     * True if this connection is considered roaming. The roaming bit can come from [ServiceState],
+     * or directly from the telephony manager's CDMA ERI number value. Note that we don't consider a
+     * connection to be roaming while carrier network change is active
+     */
+    val isRoaming: StateFlow<Boolean>
+
+    /** See [MobileIconsInteractor.isForceHidden]. */
+    val isForceHidden: Flow<Boolean>
+
+    /** See [MobileConnectionRepository.isAllowedDuringAirplaneMode]. */
+    val isAllowedDuringAirplaneMode: StateFlow<Boolean>
+
+    /** True when in carrier network change mode */
+    val carrierNetworkChangeActive: StateFlow<Boolean>
+}
+
+/** Interactor for a single mobile connection. This connection _should_ have one subscription ID */
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+class MobileIconInteractorKairosImpl(
+    @Background scope: CoroutineScope,
+    defaultSubscriptionHasDataEnabled: StateFlow<Boolean>,
+    override val alwaysShowDataRatIcon: StateFlow<Boolean>,
+    alwaysUseCdmaLevel: StateFlow<Boolean>,
+    override val isSingleCarrier: StateFlow<Boolean>,
+    override val mobileIsDefault: StateFlow<Boolean>,
+    defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>,
+    defaultMobileIconGroup: StateFlow<MobileIconGroup>,
+    isDefaultConnectionFailed: StateFlow<Boolean>,
+    override val isForceHidden: Flow<Boolean>,
+    connectionRepository: MobileConnectionRepository,
+    private val context: Context,
+    val carrierIdOverrides: MobileIconCarrierIdOverrides = MobileIconCarrierIdOverridesImpl(),
+) : MobileIconInteractor, MobileIconInteractorKairos {
+    override val tableLogBuffer: TableLogBuffer = connectionRepository.tableLogBuffer
+
+    override val activity = connectionRepository.dataActivityDirection
+
+    override val isDataEnabled: StateFlow<Boolean> = connectionRepository.dataEnabled
+
+    override val carrierNetworkChangeActive: StateFlow<Boolean> =
+        connectionRepository.carrierNetworkChangeActive
+
+    // True if there exists _any_ icon override for this carrierId. Note that overrides can include
+    // any or none of the icon groups defined in MobileMappings, so we still need to check on a
+    // per-network-type basis whether or not the given icon group is overridden
+    private val carrierIdIconOverrideExists =
+        connectionRepository.carrierId
+            .map { carrierIdOverrides.carrierIdEntryExists(it) }
+            .distinctUntilChanged()
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val networkName =
+        combine(connectionRepository.operatorAlphaShort, connectionRepository.networkName) {
+                operatorAlphaShort,
+                networkName ->
+                if (networkName is NetworkNameModel.Default && operatorAlphaShort != null) {
+                    NetworkNameModel.IntentDerived(operatorAlphaShort)
+                } else {
+                    networkName
+                }
+            }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                connectionRepository.networkName.value,
+            )
+
+    override val carrierName =
+        combine(connectionRepository.operatorAlphaShort, connectionRepository.carrierName) {
+                operatorAlphaShort,
+                networkName ->
+                if (networkName is NetworkNameModel.Default && operatorAlphaShort != null) {
+                    operatorAlphaShort
+                } else {
+                    networkName.name
+                }
+            }
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                connectionRepository.carrierName.value.name,
+            )
+
+    /** What the mobile icon would be before carrierId overrides */
+    private val defaultNetworkType: StateFlow<MobileIconGroup> =
+        combine(
+                connectionRepository.resolvedNetworkType,
+                defaultMobileIconMapping,
+                defaultMobileIconGroup,
+            ) { resolvedNetworkType, mapping, defaultGroup ->
+                when (resolvedNetworkType) {
+                    is ResolvedNetworkType.CarrierMergedNetworkType ->
+                        resolvedNetworkType.iconGroupOverride
+                    else -> {
+                        mapping[resolvedNetworkType.lookupKey] ?: defaultGroup
+                    }
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), defaultMobileIconGroup.value)
+
+    override val networkTypeIconGroup =
+        combine(defaultNetworkType, carrierIdIconOverrideExists) { networkType, overrideExists ->
+                // DefaultIcon comes out of the icongroup lookup, we check for overrides here
+                if (overrideExists) {
+                    val iconOverride =
+                        carrierIdOverrides.getOverrideFor(
+                            connectionRepository.carrierId.value,
+                            networkType.name,
+                            context.resources,
+                        )
+                    if (iconOverride > 0) {
+                        OverriddenIcon(networkType, iconOverride)
+                    } else {
+                        DefaultIcon(networkType)
+                    }
+                } else {
+                    DefaultIcon(networkType)
+                }
+            }
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                tableLogBuffer = tableLogBuffer,
+                initialValue = DefaultIcon(defaultMobileIconGroup.value),
+            )
+            .stateIn(
+                scope,
+                SharingStarted.WhileSubscribed(),
+                DefaultIcon(defaultMobileIconGroup.value),
+            )
+
+    override val showSliceAttribution: StateFlow<Boolean> =
+        combine(
+                connectionRepository.allowNetworkSliceIndicator,
+                connectionRepository.hasPrioritizedNetworkCapabilities,
+            ) { allowed, hasPrioritizedNetworkCapabilities ->
+                allowed && hasPrioritizedNetworkCapabilities
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isNonTerrestrial: StateFlow<Boolean> = connectionRepository.isNonTerrestrial
+
+    override val isRoaming: StateFlow<Boolean> =
+        combine(
+                connectionRepository.carrierNetworkChangeActive,
+                connectionRepository.isGsm,
+                connectionRepository.isRoaming,
+                connectionRepository.cdmaRoaming,
+            ) { carrierNetworkChangeActive, isGsm, isRoaming, cdmaRoaming ->
+                if (carrierNetworkChangeActive) {
+                    false
+                } else if (isGsm) {
+                    isRoaming
+                } else {
+                    cdmaRoaming
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    private val level: StateFlow<Int> =
+        combine(
+                connectionRepository.isGsm,
+                connectionRepository.primaryLevel,
+                connectionRepository.cdmaLevel,
+                alwaysUseCdmaLevel,
+            ) { isGsm, primaryLevel, cdmaLevel, alwaysUseCdmaLevel ->
+                when {
+                    // GSM connections should never use the CDMA level
+                    isGsm -> primaryLevel
+                    alwaysUseCdmaLevel -> cdmaLevel
+                    else -> primaryLevel
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
+
+    private val numberOfLevels: StateFlow<Int> = connectionRepository.numberOfLevels
+
+    override val isDataConnected: StateFlow<Boolean> =
+        connectionRepository.dataConnectionState
+            .map { it == Connected }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isInService = connectionRepository.isInService
+
+    override val isEmergencyOnly: StateFlow<Boolean> = connectionRepository.isEmergencyOnly
+
+    override val isAllowedDuringAirplaneMode = connectionRepository.isAllowedDuringAirplaneMode
+
+    /** Whether or not to show the error state of [SignalDrawable] */
+    private val showExclamationMark: StateFlow<Boolean> =
+        combine(defaultSubscriptionHasDataEnabled, isDefaultConnectionFailed, isInService) {
+                isDefaultDataEnabled,
+                isDefaultConnectionFailed,
+                isInService ->
+                !isDefaultDataEnabled || isDefaultConnectionFailed || !isInService
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), true)
+
+    private val cellularShownLevel: StateFlow<Int> =
+        combine(level, isInService, connectionRepository.inflateSignalStrength) {
+                level,
+                isInService,
+                inflate ->
+                if (isInService) {
+                    if (inflate) level + 1 else level
+                } else 0
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
+
+    // Satellite level is unaffected by the inflateSignalStrength property
+    // See b/346904529 for details
+    private val satelliteShownLevel: StateFlow<Int> =
+        if (Flags.carrierRoamingNbIotNtn()) {
+                connectionRepository.satelliteLevel
+            } else {
+                combine(level, isInService) { level, isInService -> if (isInService) level else 0 }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), 0)
+
+    private val cellularIcon: Flow<SignalIconModel.Cellular> =
+        combine(
+            cellularShownLevel,
+            numberOfLevels,
+            showExclamationMark,
+            carrierNetworkChangeActive,
+        ) { cellularShownLevel, numberOfLevels, showExclamationMark, carrierNetworkChange ->
+            SignalIconModel.Cellular(
+                cellularShownLevel,
+                numberOfLevels,
+                showExclamationMark,
+                carrierNetworkChange,
+            )
+        }
+
+    private val satelliteIcon: Flow<SignalIconModel.Satellite> =
+        satelliteShownLevel.map {
+            SignalIconModel.Satellite(
+                level = it,
+                icon =
+                    SatelliteIconModel.fromSignalStrength(it)
+                        ?: SatelliteIconModel.fromSignalStrength(0)!!,
+            )
+        }
+
+    override val signalLevelIcon: StateFlow<SignalIconModel> = run {
+        val initial =
+            SignalIconModel.Cellular(
+                cellularShownLevel.value,
+                numberOfLevels.value,
+                showExclamationMark.value,
+                carrierNetworkChangeActive.value,
+            )
+        isNonTerrestrial
+            .flatMapLatest { ntn ->
+                if (ntn) {
+                    satelliteIcon
+                } else {
+                    cellularIcon
+                }
+            }
+            .distinctUntilChanged()
+            .logDiffsForTable(tableLogBuffer, columnPrefix = "icon", initialValue = initial)
+            .stateIn(scope, SharingStarted.WhileSubscribed(), initial)
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairos.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairos.kt
new file mode 100644
index 0000000..e8e0a83
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/mobile/domain/interactor/MobileIconsInteractorKairos.kt
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.domain.interactor
+
+import android.content.Context
+import android.telephony.CarrierConfigManager
+import android.telephony.SubscriptionManager
+import android.telephony.SubscriptionManager.PROFILE_CLASS_PROVISIONING
+import com.android.settingslib.SignalIcon.MobileIconGroup
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags.FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logDiffsForTable
+import com.android.systemui.statusbar.core.NewStatusBarIcons
+import com.android.systemui.statusbar.core.StatusBarRootModernization
+import com.android.systemui.statusbar.pipeline.dagger.MobileSummaryLog
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
+import com.android.systemui.statusbar.pipeline.mobile.domain.model.SignalIconModel
+import com.android.systemui.statusbar.pipeline.shared.data.model.ConnectivitySlot
+import com.android.systemui.statusbar.pipeline.shared.data.repository.ConnectivityRepository
+import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
+import com.android.systemui.util.CarrierConfigTracker
+import java.lang.ref.WeakReference
+import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.delay
+import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.SharingStarted
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
+import kotlinx.coroutines.flow.filter
+import kotlinx.coroutines.flow.flatMapLatest
+import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.map
+import kotlinx.coroutines.flow.mapLatest
+import kotlinx.coroutines.flow.stateIn
+import kotlinx.coroutines.flow.transformLatest
+
+/**
+ * Business layer logic for the set of mobile subscription icons.
+ *
+ * This interactor represents known set of mobile subscriptions (represented by [SubscriptionInfo]).
+ * The list of subscriptions is filtered based on the opportunistic flags on the infos.
+ *
+ * It provides the default mapping between the telephony display info and the icon group that
+ * represents each RAT (LTE, 3G, etc.), as well as can produce an interactor for each individual
+ * icon
+ */
+interface MobileIconsInteractorKairos {
+    /** See [MobileConnectionsRepository.mobileIsDefault]. */
+    val mobileIsDefault: StateFlow<Boolean>
+
+    /** List of subscriptions, potentially filtered for CBRS */
+    val filteredSubscriptions: Flow<List<SubscriptionModel>>
+
+    /** Subscription ID of the current default data subscription */
+    val defaultDataSubId: Flow<Int?>
+
+    /**
+     * The current list of [MobileIconInteractor]s associated with the current list of
+     * [filteredSubscriptions]
+     */
+    val icons: StateFlow<List<MobileIconInteractor>>
+
+    /** Whether the mobile icons can be stacked vertically. */
+    val isStackable: StateFlow<Boolean>
+
+    /**
+     * Observable for the subscriptionId of the current mobile data connection. Null if we don't
+     * have a valid subscription id
+     */
+    val activeMobileDataSubscriptionId: StateFlow<Int?>
+
+    /** True if the active mobile data subscription has data enabled */
+    val activeDataConnectionHasDataEnabled: StateFlow<Boolean>
+
+    /**
+     * Flow providing a reference to the Interactor for the active data subId. This represents the
+     * [MobileIconInteractor] responsible for the active data connection, if any.
+     */
+    val activeDataIconInteractor: StateFlow<MobileIconInteractor?>
+
+    /** True if the RAT icon should always be displayed and false otherwise. */
+    val alwaysShowDataRatIcon: StateFlow<Boolean>
+
+    /** True if the CDMA level should be preferred over the primary level. */
+    val alwaysUseCdmaLevel: StateFlow<Boolean>
+
+    /** True if there is only one active subscription. */
+    val isSingleCarrier: StateFlow<Boolean>
+
+    /** The icon mapping from network type to [MobileIconGroup] for the default subscription */
+    val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>>
+
+    /** Fallback [MobileIconGroup] in the case where there is no icon in the mapping */
+    val defaultMobileIconGroup: StateFlow<MobileIconGroup>
+
+    /** True only if the default network is mobile, and validation also failed */
+    val isDefaultConnectionFailed: StateFlow<Boolean>
+
+    /** True once the user has been set up */
+    val isUserSetUp: StateFlow<Boolean>
+
+    /** True if we're configured to force-hide the mobile icons and false otherwise. */
+    val isForceHidden: Flow<Boolean>
+
+    /**
+     * True if the device-level service state (with -1 subscription id) reports emergency calls
+     * only. This value is only useful when there are no other subscriptions OR all existing
+     * subscriptions report that they are not in service.
+     */
+    val isDeviceInEmergencyCallsOnlyMode: Flow<Boolean>
+
+    /**
+     * Vends out a [MobileIconInteractor] tracking the [MobileConnectionRepository] for the given
+     * subId.
+     */
+    fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor
+}
+
+@OptIn(ExperimentalCoroutinesApi::class)
+@Suppress("EXPERIMENTAL_IS_NOT_ENABLED")
+@SysUISingleton
+class MobileIconsInteractorKairosImpl
+@Inject
+constructor(
+    private val mobileConnectionsRepo: MobileConnectionsRepository,
+    private val carrierConfigTracker: CarrierConfigTracker,
+    @MobileSummaryLog private val tableLogger: TableLogBuffer,
+    connectivityRepository: ConnectivityRepository,
+    userSetupRepo: UserSetupRepository,
+    @Background private val scope: CoroutineScope,
+    private val context: Context,
+    private val featureFlagsClassic: FeatureFlagsClassic,
+) : MobileIconsInteractor, MobileIconsInteractorKairos {
+
+    // Weak reference lookup for created interactors
+    private val reuseCache = mutableMapOf<Int, WeakReference<MobileIconInteractor>>()
+
+    override val mobileIsDefault =
+        combine(
+                mobileConnectionsRepo.mobileIsDefault,
+                mobileConnectionsRepo.hasCarrierMergedConnection,
+            ) { mobileIsDefault, hasCarrierMergedConnection ->
+                // Because carrier merged networks are displayed as mobile networks, they're part of
+                // the `isDefault` calculation. See b/272586234.
+                mobileIsDefault || hasCarrierMergedConnection
+            }
+            .logDiffsForTable(
+                tableLogger,
+                LOGGING_PREFIX,
+                columnName = "mobileIsDefault",
+                initialValue = false,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val activeMobileDataSubscriptionId: StateFlow<Int?> =
+        mobileConnectionsRepo.activeMobileDataSubscriptionId
+
+    override val activeDataConnectionHasDataEnabled: StateFlow<Boolean> =
+        mobileConnectionsRepo.activeMobileDataRepository
+            .flatMapLatest { it?.dataEnabled ?: flowOf(false) }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val activeDataIconInteractor: StateFlow<MobileIconInteractor?> =
+        mobileConnectionsRepo.activeMobileDataSubscriptionId
+            .mapLatest {
+                if (it != null) {
+                    getMobileConnectionInteractorForSubId(it)
+                } else {
+                    null
+                }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), null)
+
+    private val unfilteredSubscriptions: Flow<List<SubscriptionModel>> =
+        mobileConnectionsRepo.subscriptions
+
+    /** Any filtering that we can do based purely on the info of each subscription individually. */
+    private val subscriptionsBasedFilteredSubs =
+        unfilteredSubscriptions
+            .map { it.filterBasedOnProvisioning().filterBasedOnNtn() }
+            .distinctUntilChanged()
+
+    private fun List<SubscriptionModel>.filterBasedOnProvisioning(): List<SubscriptionModel> =
+        if (!featureFlagsClassic.isEnabled(FILTER_PROVISIONING_NETWORK_SUBSCRIPTIONS)) {
+            this
+        } else {
+            this.filter { it.profileClass != PROFILE_CLASS_PROVISIONING }
+        }
+
+    /**
+     * Subscriptions that exclusively support non-terrestrial networks should **never** directly
+     * show any iconography in the status bar. These subscriptions only exist to provide a backing
+     * for the device-based satellite connections, and the iconography for those connections are
+     * already being handled in
+     * [com.android.systemui.statusbar.pipeline.satellite.data.DeviceBasedSatelliteRepository]. We
+     * need to filter out those subscriptions here so we guarantee the subscription never turns into
+     * an icon. See b/336881301.
+     */
+    private fun List<SubscriptionModel>.filterBasedOnNtn(): List<SubscriptionModel> {
+        return this.filter { !it.isExclusivelyNonTerrestrial }
+    }
+
+    /**
+     * Generally, SystemUI wants to show iconography for each subscription that is listed by
+     * [SubscriptionManager]. However, in the case of opportunistic subscriptions, we want to only
+     * show a single representation of the pair of subscriptions. The docs define opportunistic as:
+     *
+     * "A subscription is opportunistic (if) the network it connects to has limited coverage"
+     * https://developer.android.com/reference/android/telephony/SubscriptionManager#setOpportunistic(boolean,%20int)
+     *
+     * In the case of opportunistic networks (typically CBRS), we will filter out one of the
+     * subscriptions based on
+     * [CarrierConfigManager.KEY_ALWAYS_SHOW_PRIMARY_SIGNAL_BAR_IN_OPPORTUNISTIC_NETWORK_BOOLEAN],
+     * and by checking which subscription is opportunistic, or which one is active.
+     */
+    override val filteredSubscriptions: Flow<List<SubscriptionModel>> =
+        combine(
+                subscriptionsBasedFilteredSubs,
+                mobileConnectionsRepo.activeMobileDataSubscriptionId,
+                connectivityRepository.vcnSubId,
+            ) { preFilteredSubs, activeId, vcnSubId ->
+                filterSubsBasedOnOpportunistic(preFilteredSubs, activeId, vcnSubId)
+            }
+            .distinctUntilChanged()
+            .logDiffsForTable(
+                tableLogger,
+                LOGGING_PREFIX,
+                columnName = "filteredSubscriptions",
+                initialValue = listOf(),
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), listOf())
+
+    private fun filterSubsBasedOnOpportunistic(
+        subList: List<SubscriptionModel>,
+        activeId: Int?,
+        vcnSubId: Int?,
+    ): List<SubscriptionModel> {
+        // Based on the old logic,
+        if (subList.size != 2) {
+            return subList
+        }
+
+        val info1 = subList[0]
+        val info2 = subList[1]
+
+        // Filtering only applies to subscriptions in the same group
+        if (info1.groupUuid == null || info1.groupUuid != info2.groupUuid) {
+            return subList
+        }
+
+        // If both subscriptions are primary, show both
+        if (!info1.isOpportunistic && !info2.isOpportunistic) {
+            return subList
+        }
+
+        // NOTE: at this point, we are now returning a single SubscriptionInfo
+
+        // If carrier required, always show the icon of the primary subscription.
+        // Otherwise, show whichever subscription is currently active for internet.
+        if (carrierConfigTracker.alwaysShowPrimarySignalBarInOpportunisticNetworkDefault) {
+            // return the non-opportunistic info
+            return if (info1.isOpportunistic) listOf(info2) else listOf(info1)
+        } else {
+            // It's possible for the subId of the VCN to disagree with the active subId in
+            // cases where the system has tried to switch but found no connection. In these
+            // scenarios, VCN will always have the subId that we want to use, so use that
+            // value instead of the activeId reported by telephony
+            val subIdToKeep = vcnSubId ?: activeId
+
+            return if (info1.subscriptionId == subIdToKeep) {
+                listOf(info1)
+            } else {
+                listOf(info2)
+            }
+        }
+    }
+
+    override val defaultDataSubId = mobileConnectionsRepo.defaultDataSubId
+
+    override val icons =
+        filteredSubscriptions
+            .mapLatest { subs ->
+                subs.map { getMobileConnectionInteractorForSubId(it.subscriptionId) }
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), emptyList())
+
+    override val isStackable =
+        if (NewStatusBarIcons.isEnabled && StatusBarRootModernization.isEnabled) {
+                icons.flatMapLatest { icons ->
+                    combine(icons.map { it.signalLevelIcon }) { signalLevelIcons ->
+                        // These are only stackable if:
+                        // - They are cellular
+                        // - There's exactly two
+                        // - They have the same number of levels
+                        signalLevelIcons.filterIsInstance<SignalIconModel.Cellular>().let {
+                            it.size == 2 && it[0].numberOfLevels == it[1].numberOfLevels
+                        }
+                    }
+                }
+            } else {
+                flowOf(false)
+            }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    /**
+     * Copied from the old pipeline. We maintain a 2s period of time where we will keep the
+     * validated bit from the old active network (A) while data is changing to the new one (B).
+     *
+     * This condition only applies if
+     * 1. A and B are in the same subscription group (e.g. for CBRS data switching) and
+     * 2. A was validated before the switch
+     *
+     * The goal of this is to minimize the flickering in the UI of the cellular indicator
+     */
+    private val forcingCellularValidation =
+        mobileConnectionsRepo.activeSubChangedInGroupEvent
+            .filter { mobileConnectionsRepo.defaultConnectionIsValidated.value }
+            .transformLatest {
+                emit(true)
+                delay(2000)
+                emit(false)
+            }
+            .logDiffsForTable(
+                tableLogger,
+                LOGGING_PREFIX,
+                columnName = "forcingValidation",
+                initialValue = false,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    /**
+     * Mapping from network type to [MobileIconGroup] using the config generated for the default
+     * subscription Id. This mapping is the same for every subscription.
+     */
+    override val defaultMobileIconMapping: StateFlow<Map<String, MobileIconGroup>> =
+        mobileConnectionsRepo.defaultMobileIconMapping.stateIn(
+            scope,
+            SharingStarted.WhileSubscribed(),
+            initialValue = mapOf(),
+        )
+
+    override val alwaysShowDataRatIcon: StateFlow<Boolean> =
+        mobileConnectionsRepo.defaultDataSubRatConfig
+            .mapLatest { it.alwaysShowDataRatIcon }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val alwaysUseCdmaLevel: StateFlow<Boolean> =
+        mobileConnectionsRepo.defaultDataSubRatConfig
+            .mapLatest { it.alwaysShowCdmaRssi }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isSingleCarrier: StateFlow<Boolean> =
+        mobileConnectionsRepo.subscriptions
+            .map { it.size == 1 }
+            .logDiffsForTable(
+                tableLogger,
+                columnPrefix = LOGGING_PREFIX,
+                columnName = "isSingleCarrier",
+                initialValue = false,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    /** If there is no mapping in [defaultMobileIconMapping], then use this default icon group */
+    override val defaultMobileIconGroup: StateFlow<MobileIconGroup> =
+        mobileConnectionsRepo.defaultMobileIconGroup.stateIn(
+            scope,
+            SharingStarted.WhileSubscribed(),
+            initialValue = TelephonyIcons.G,
+        )
+
+    /**
+     * We want to show an error state when cellular has actually failed to validate, but not if some
+     * other transport type is active, because then we expect there not to be validation.
+     */
+    override val isDefaultConnectionFailed: StateFlow<Boolean> =
+        combine(
+                mobileIsDefault,
+                mobileConnectionsRepo.defaultConnectionIsValidated,
+                forcingCellularValidation,
+            ) { mobileIsDefault, defaultConnectionIsValidated, forcingCellularValidation ->
+                when {
+                    !mobileIsDefault -> false
+                    forcingCellularValidation -> false
+                    else -> !defaultConnectionIsValidated
+                }
+            }
+            .logDiffsForTable(
+                tableLogger,
+                LOGGING_PREFIX,
+                columnName = "isDefaultConnectionFailed",
+                initialValue = false,
+            )
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isUserSetUp: StateFlow<Boolean> = userSetupRepo.isUserSetUp
+
+    override val isForceHidden: Flow<Boolean> =
+        connectivityRepository.forceHiddenSlots
+            .map { it.contains(ConnectivitySlot.MOBILE) }
+            .stateIn(scope, SharingStarted.WhileSubscribed(), false)
+
+    override val isDeviceInEmergencyCallsOnlyMode: Flow<Boolean> =
+        mobileConnectionsRepo.isDeviceEmergencyCallCapable
+
+    /** Vends out new [MobileIconInteractor] for a particular subId */
+    override fun getMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
+        reuseCache[subId]?.get() ?: createMobileConnectionInteractorForSubId(subId)
+
+    private fun createMobileConnectionInteractorForSubId(subId: Int): MobileIconInteractor =
+        MobileIconInteractorImpl(
+                scope,
+                activeDataConnectionHasDataEnabled,
+                alwaysShowDataRatIcon,
+                alwaysUseCdmaLevel,
+                isSingleCarrier,
+                mobileIsDefault,
+                defaultMobileIconMapping,
+                defaultMobileIconGroup,
+                isDefaultConnectionFailed,
+                isForceHidden,
+                mobileConnectionsRepo.getRepoForSubId(subId),
+                context,
+            )
+            .also { reuseCache[subId] = WeakReference(it) }
+
+    companion object {
+        private const val LOGGING_PREFIX = "Intr"
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt
index d734889..cfd5097 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/binder/HomeStatusBarViewBinder.kt
@@ -47,7 +47,8 @@
 import com.android.systemui.statusbar.pipeline.shared.ui.model.VisibilityModel
 import com.android.systemui.statusbar.pipeline.shared.ui.viewmodel.HomeStatusBarViewModel
 import javax.inject.Inject
-import kotlinx.coroutines.flow.collectLatest
+import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.launch
 
 /**
@@ -153,39 +154,43 @@
                         OngoingActivityChipBinder.createBinding(primaryChipView)
 
                     launch {
-                        viewModel.primaryOngoingActivityChip.collect { primaryChipModel ->
-                            OngoingActivityChipBinder.bind(
-                                primaryChipModel,
-                                primaryChipViewBinding,
-                                iconViewStore,
+                        combine(
+                                viewModel.primaryOngoingActivityChip,
+                                viewModel.canShowOngoingActivityChips,
+                                ::Pair,
                             )
+                            .distinctUntilChanged()
+                            .collect { (primaryChipModel, areChipsAllowed) ->
+                                OngoingActivityChipBinder.bind(
+                                    primaryChipModel,
+                                    primaryChipViewBinding,
+                                    iconViewStore,
+                                )
 
-                            if (StatusBarRootModernization.isEnabled) {
-                                launch {
+                                if (StatusBarRootModernization.isEnabled) {
                                     bindLegacyPrimaryOngoingActivityChipWithVisibility(
-                                        viewModel,
+                                        areChipsAllowed,
                                         primaryChipModel,
                                         primaryChipViewBinding,
                                     )
-                                }
-                            } else {
-                                when (primaryChipModel) {
-                                    is OngoingActivityChipModel.Active ->
-                                        listener?.onOngoingActivityStatusChanged(
-                                            hasPrimaryOngoingActivity = true,
-                                            hasSecondaryOngoingActivity = false,
-                                            shouldAnimate = true,
-                                        )
+                                } else {
+                                    when (primaryChipModel) {
+                                        is OngoingActivityChipModel.Active ->
+                                            listener?.onOngoingActivityStatusChanged(
+                                                hasPrimaryOngoingActivity = true,
+                                                hasSecondaryOngoingActivity = false,
+                                                shouldAnimate = true,
+                                            )
 
-                                    is OngoingActivityChipModel.Inactive ->
-                                        listener?.onOngoingActivityStatusChanged(
-                                            hasPrimaryOngoingActivity = false,
-                                            hasSecondaryOngoingActivity = false,
-                                            shouldAnimate = primaryChipModel.shouldAnimate,
-                                        )
+                                        is OngoingActivityChipModel.Inactive ->
+                                            listener?.onOngoingActivityStatusChanged(
+                                                hasPrimaryOngoingActivity = false,
+                                                hasSecondaryOngoingActivity = false,
+                                                shouldAnimate = primaryChipModel.shouldAnimate,
+                                            )
+                                    }
                                 }
                             }
-                        }
                     }
                 }
 
@@ -199,49 +204,53 @@
                             view.requireViewById(R.id.ongoing_activity_chip_secondary)
                         )
                     launch {
-                        viewModel.ongoingActivityChipsLegacy.collectLatest { chips ->
-                            OngoingActivityChipBinder.bind(
-                                chips.primary,
-                                primaryChipViewBinding,
-                                iconViewStore,
+                        combine(
+                                viewModel.ongoingActivityChipsLegacy,
+                                viewModel.canShowOngoingActivityChips,
+                                ::Pair,
                             )
-                            OngoingActivityChipBinder.bind(
-                                chips.secondary,
-                                secondaryChipViewBinding,
-                                iconViewStore,
-                            )
-
-                            if (StatusBarRootModernization.isEnabled) {
-                                launch {
+                            .distinctUntilChanged()
+                            .collect { (chips, areChipsAllowed) ->
+                                OngoingActivityChipBinder.bind(
+                                    chips.primary,
+                                    primaryChipViewBinding,
+                                    iconViewStore,
+                                )
+                                OngoingActivityChipBinder.bind(
+                                    chips.secondary,
+                                    secondaryChipViewBinding,
+                                    iconViewStore,
+                                )
+                                if (StatusBarRootModernization.isEnabled) {
                                     bindOngoingActivityChipsWithVisibility(
-                                        viewModel,
+                                        areChipsAllowed,
                                         chips,
                                         primaryChipViewBinding,
                                         secondaryChipViewBinding,
                                     )
+                                } else {
+                                    listener?.onOngoingActivityStatusChanged(
+                                        hasPrimaryOngoingActivity =
+                                            chips.primary is OngoingActivityChipModel.Active,
+                                        hasSecondaryOngoingActivity =
+                                            chips.secondary is OngoingActivityChipModel.Active,
+                                        // TODO(b/364653005): Figure out the animation story here.
+                                        shouldAnimate = true,
+                                    )
                                 }
-                            } else {
-                                listener?.onOngoingActivityStatusChanged(
-                                    hasPrimaryOngoingActivity =
-                                        chips.primary is OngoingActivityChipModel.Active,
-                                    hasSecondaryOngoingActivity =
-                                        chips.secondary is OngoingActivityChipModel.Active,
-                                    // TODO(b/364653005): Figure out the animation story here.
-                                    shouldAnimate = true,
-                                )
                             }
-
-                            viewModel.contentArea.collect { _ ->
-                                OngoingActivityChipBinder.resetPrimaryChipWidthRestrictions(
-                                    primaryChipViewBinding,
-                                    viewModel.ongoingActivityChipsLegacy.value.primary,
-                                )
-                                OngoingActivityChipBinder.resetSecondaryChipWidthRestrictions(
-                                    secondaryChipViewBinding,
-                                    viewModel.ongoingActivityChipsLegacy.value.secondary,
-                                )
-                                view.requestLayout()
-                            }
+                    }
+                    launch {
+                        viewModel.contentArea.collect { _ ->
+                            OngoingActivityChipBinder.resetPrimaryChipWidthRestrictions(
+                                primaryChipViewBinding,
+                                viewModel.ongoingActivityChipsLegacy.value.primary,
+                            )
+                            OngoingActivityChipBinder.resetSecondaryChipWidthRestrictions(
+                                secondaryChipViewBinding,
+                                viewModel.ongoingActivityChipsLegacy.value.secondary,
+                            )
+                            view.requestLayout()
                         }
                     }
                 }
@@ -249,7 +258,7 @@
                 if (SceneContainerFlag.isEnabled) {
                     listener?.let { listener ->
                         launch {
-                            viewModel.isHomeStatusBarAllowedByScene.collect {
+                            viewModel.isHomeStatusBarAllowed.collect {
                                 listener.onIsHomeStatusBarAllowedBySceneChanged(it)
                             }
                         }
@@ -314,48 +323,42 @@
     }
 
     /** Bind the (legacy) single primary ongoing activity chip with the status bar visibility */
-    private suspend fun bindLegacyPrimaryOngoingActivityChipWithVisibility(
-        viewModel: HomeStatusBarViewModel,
+    private fun bindLegacyPrimaryOngoingActivityChipWithVisibility(
+        areChipsAllowed: Boolean,
         primaryChipModel: OngoingActivityChipModel,
         primaryChipViewBinding: OngoingActivityChipViewBinding,
     ) {
-        viewModel.canShowOngoingActivityChips.collectLatest { visible ->
-            if (!visible) {
-                primaryChipViewBinding.rootView.hide(shouldAnimateChange = false)
-            } else {
-                when (primaryChipModel) {
-                    is OngoingActivityChipModel.Active -> {
-                        primaryChipViewBinding.rootView.show(shouldAnimateChange = true)
-                    }
+        if (!areChipsAllowed) {
+            primaryChipViewBinding.rootView.hide(shouldAnimateChange = false)
+        } else {
+            when (primaryChipModel) {
+                is OngoingActivityChipModel.Active -> {
+                    primaryChipViewBinding.rootView.show(shouldAnimateChange = true)
+                }
 
-                    is OngoingActivityChipModel.Inactive -> {
-                        primaryChipViewBinding.rootView.hide(
-                            state = View.GONE,
-                            shouldAnimateChange = primaryChipModel.shouldAnimate,
-                        )
-                    }
+                is OngoingActivityChipModel.Inactive -> {
+                    primaryChipViewBinding.rootView.hide(
+                        state = View.GONE,
+                        shouldAnimateChange = primaryChipModel.shouldAnimate,
+                    )
                 }
             }
         }
     }
 
     /** Bind the primary/secondary chips along with the home status bar's visibility */
-    private suspend fun bindOngoingActivityChipsWithVisibility(
-        viewModel: HomeStatusBarViewModel,
+    private fun bindOngoingActivityChipsWithVisibility(
+        areChipsAllowed: Boolean,
         chips: MultipleOngoingActivityChipsModelLegacy,
         primaryChipViewBinding: OngoingActivityChipViewBinding,
         secondaryChipViewBinding: OngoingActivityChipViewBinding,
     ) {
-        viewModel.canShowOngoingActivityChips.collectLatest { canShow ->
-            if (!canShow) {
-                primaryChipViewBinding.rootView.hide(shouldAnimateChange = false)
-                secondaryChipViewBinding.rootView.hide(shouldAnimateChange = false)
-            } else {
-                primaryChipViewBinding.rootView.adjustVisibility(chips.primary.toVisibilityModel())
-                secondaryChipViewBinding.rootView.adjustVisibility(
-                    chips.secondary.toVisibilityModel()
-                )
-            }
+        if (!areChipsAllowed) {
+            primaryChipViewBinding.rootView.hide(shouldAnimateChange = false)
+            secondaryChipViewBinding.rootView.hide(shouldAnimateChange = false)
+        } else {
+            primaryChipViewBinding.rootView.adjustVisibility(chips.primary.toVisibilityModel())
+            secondaryChipViewBinding.rootView.adjustVisibility(chips.secondary.toVisibilityModel())
         }
     }
 
@@ -428,10 +431,15 @@
     // See CollapsedStatusBarFragment#hide.
     private fun View.hide(state: Int = View.INVISIBLE, shouldAnimateChange: Boolean) {
         animate().cancel()
-        if (visibility == View.INVISIBLE || visibility == View.GONE) {
+
+        if (
+            (visibility == View.INVISIBLE && state == View.INVISIBLE) ||
+                (visibility == View.GONE && state == View.GONE)
+        ) {
             return
         }
-        if (!shouldAnimateChange) {
+        val isAlreadyHidden = visibility == View.INVISIBLE || visibility == View.GONE
+        if (!shouldAnimateChange || isAlreadyHidden) {
             alpha = 0f
             visibility = state
             return
@@ -495,7 +503,7 @@
 
     /**
      * Called when the scene state has changed such that the home status bar is newly allowed or no
-     * longer allowed. See [HomeStatusBarViewModel.isHomeStatusBarAllowedByScene].
+     * longer allowed. See [HomeStatusBarViewModel.isHomeStatusBarAllowed].
      */
     fun onIsHomeStatusBarAllowedBySceneChanged(isHomeStatusBarAllowedByScene: Boolean)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
index 4189221..c91ea9a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/composable/StatusBarRoot.kt
@@ -196,13 +196,15 @@
 
                                 setContent {
                                     PlatformTheme {
-                                        val chips by
+                                        val chipsVisibilityModel by
                                             statusBarViewModel.ongoingActivityChips
                                                 .collectAsStateWithLifecycle()
-                                        OngoingActivityChips(
-                                            chips = chips,
-                                            iconViewStore = iconViewStore,
-                                        )
+                                        if (chipsVisibilityModel.areChipsAllowed) {
+                                            OngoingActivityChips(
+                                                chips = chipsVisibilityModel.chips,
+                                                iconViewStore = iconViewStore,
+                                            )
+                                        }
                                     }
                                 }
                             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/ChipsVisibilityModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/ChipsVisibilityModel.kt
new file mode 100644
index 0000000..5cc432f
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/model/ChipsVisibilityModel.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.shared.ui.model
+
+import com.android.systemui.statusbar.chips.ui.model.MultipleOngoingActivityChipsModel
+
+data class ChipsVisibilityModel(
+    val chips: MultipleOngoingActivityChipsModel,
+    /**
+     * True if the chips are allowed to be shown and false otherwise (e.g. if we're on lockscreen).
+     */
+    val areChipsAllowed: Boolean,
+)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
index 807e905..3bae91a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModel.kt
@@ -18,6 +18,7 @@
 
 import android.annotation.ColorInt
 import android.graphics.Rect
+import android.view.Display
 import android.view.View
 import androidx.compose.runtime.getValue
 import com.android.app.tracing.coroutines.launchTraced as launch
@@ -41,7 +42,9 @@
 import com.android.systemui.scene.shared.flag.SceneContainerFlag
 import com.android.systemui.scene.shared.model.Overlays
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.domain.interactor.ShadeDisplaysInteractor
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.shade.shared.flag.ShadeWindowGoesAround
 import com.android.systemui.statusbar.chips.mediaprojection.domain.model.MediaProjectionStopDialogModel
 import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips
 import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.ShareToAppChipViewModel
@@ -67,11 +70,13 @@
 import com.android.systemui.statusbar.pipeline.battery.ui.viewmodel.BatteryViewModel
 import com.android.systemui.statusbar.pipeline.shared.domain.interactor.HomeStatusBarIconBlockListInteractor
 import com.android.systemui.statusbar.pipeline.shared.domain.interactor.HomeStatusBarInteractor
+import com.android.systemui.statusbar.pipeline.shared.ui.model.ChipsVisibilityModel
 import com.android.systemui.statusbar.pipeline.shared.ui.model.SystemInfoCombinedVisibilityModel
 import com.android.systemui.statusbar.pipeline.shared.ui.model.VisibilityModel
 import dagger.assisted.Assisted
 import dagger.assisted.AssistedFactory
 import dagger.assisted.AssistedInject
+import javax.inject.Provider
 import kotlinx.coroutines.CoroutineDispatcher
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.awaitCancellation
@@ -125,7 +130,7 @@
     val primaryOngoingActivityChip: StateFlow<OngoingActivityChipModel>
 
     /** All supported activity chips, whether they are currently active or not. */
-    val ongoingActivityChips: StateFlow<MultipleOngoingActivityChipsModel>
+    val ongoingActivityChips: StateFlow<ChipsVisibilityModel>
 
     /**
      * The multiple ongoing activity chips that should be shown on the left-hand side of the status
@@ -141,13 +146,12 @@
     val popupChips: List<PopupChipModel.Shown>
 
     /**
-     * True if the current scene can show the home status bar (aka this status bar), and false if
-     * the current scene should never show the home status bar.
+     * True if the status bar should be visible.
      *
      * TODO(b/364360986): Once the is<SomeChildView>Visible flows are fully enabled, we shouldn't
      *   need this flow anymore.
      */
-    val isHomeStatusBarAllowedByScene: StateFlow<Boolean>
+    val isHomeStatusBarAllowed: StateFlow<Boolean>
 
     /** True if the home status bar is showing, and there is no HUN happening */
     val canShowOngoingActivityChips: Flow<Boolean>
@@ -221,6 +225,7 @@
     statusBarContentInsetsViewModelStore: StatusBarContentInsetsViewModelStore,
     @Background bgScope: CoroutineScope,
     @Background bgDispatcher: CoroutineDispatcher,
+    shadeDisplaysInteractor: Provider<ShadeDisplaysInteractor>,
 ) : HomeStatusBarViewModel, ExclusiveActivatable() {
 
     private val hydrator = Hydrator(traceName = "HomeStatusBarViewModel.hydrator")
@@ -252,19 +257,49 @@
 
     override val primaryOngoingActivityChip = ongoingActivityChipsViewModel.primaryChip
 
-    override val ongoingActivityChips = ongoingActivityChipsViewModel.chips
-
     override val ongoingActivityChipsLegacy = ongoingActivityChipsViewModel.chipsLegacy
 
     override val popupChips
         get() = statusBarPopupChips.shownPopupChips
 
-    override val isHomeStatusBarAllowedByScene: StateFlow<Boolean> =
+    /**
+     * Whether the display of this statusbar has the shade window (that is hosting shade container
+     * and lockscreen, among other things).
+     */
+    private val isShadeWindowOnThisDisplay =
+        if (ShadeWindowGoesAround.isEnabled) {
+            shadeDisplaysInteractor.get().displayId.map { shadeDisplayId ->
+                thisDisplayId == shadeDisplayId
+            }
+        } else {
+            // Shade doesn't move anywhere, it is always on the default display.
+            flowOf(thisDisplayId == Display.DEFAULT_DISPLAY)
+        }
+
+    private val isShadeVisibleOnAnyDisplay =
+        if (SceneContainerFlag.isEnabled) {
+            sceneInteractor.currentOverlays.map { currentOverlays ->
+                (Overlays.NotificationsShade in currentOverlays ||
+                    Overlays.QuickSettingsShade in currentOverlays)
+            }
+        } else {
+            shadeInteractor.isAnyFullyExpanded
+        }
+
+    private val isShadeVisibleOnThisDisplay: Flow<Boolean> =
+        combine(isShadeWindowOnThisDisplay, isShadeVisibleOnAnyDisplay) {
+            hasShade,
+            isShadeVisibleOnAnyDisplay ->
+            hasShade && isShadeVisibleOnAnyDisplay
+        }
+
+    private val isHomeStatusBarAllowedByScene: Flow<Boolean> =
         combine(
                 sceneInteractor.currentScene,
-                sceneInteractor.currentOverlays,
+                isShadeVisibleOnThisDisplay,
                 sceneContainerOcclusionInteractor.invisibleDueToOcclusion,
-            ) { currentScene, currentOverlays, isOccluded ->
+            ) { currentScene, isShadeVisible, isOccluded ->
+
                 // All scenes have their own status bars, so we should only show the home status bar
                 // if we're not in a scene. There are two exceptions:
                 // 1) The shade (notifications or quick settings) is shown, because it has its own
@@ -272,9 +307,7 @@
                 // 2) If the scene is occluded, then the occluding app needs to show the status bar.
                 // (Fullscreen apps actually won't show the status bar but that's handled with the
                 // rest of our fullscreen app logic, which lives elsewhere.)
-                (currentScene == Scenes.Gone &&
-                    Overlays.NotificationsShade !in currentOverlays &&
-                    Overlays.QuickSettingsShade !in currentOverlays) || isOccluded
+                (currentScene == Scenes.Gone && !isShadeVisible) || isOccluded
             }
             .distinctUntilChanged()
             .logDiffsForTable(
@@ -282,7 +315,6 @@
                 columnName = COL_ALLOWED_BY_SCENE,
                 initialValue = false,
             )
-            .stateIn(bgScope, SharingStarted.WhileSubscribed(), initialValue = false)
 
     override val areNotificationsLightsOut: Flow<Boolean> =
         if (NotificationsLiveDataStoreRefactor.isUnexpectedlyInLegacyMode()) {
@@ -331,21 +363,29 @@
      * if we shouldn't be showing any part of the home status bar.
      */
     private val isHomeScreenStatusBarAllowedLegacy: Flow<Boolean> =
-        combine(
-            keyguardTransitionInteractor.currentKeyguardState,
-            shadeInteractor.isAnyFullyExpanded,
-        ) { currentKeyguardState, isShadeExpanded ->
-            (currentKeyguardState == GONE || currentKeyguardState == OCCLUDED) && !isShadeExpanded
+        combine(keyguardTransitionInteractor.currentKeyguardState, isShadeVisibleOnThisDisplay) {
+            currentKeyguardState,
+            isShadeVisibleOnThisDisplay ->
+            (currentKeyguardState == GONE || currentKeyguardState == OCCLUDED) &&
+                !isShadeVisibleOnThisDisplay
             // TODO(b/364360986): Add edge cases, like secure camera launch.
         }
 
-    private val isHomeStatusBarAllowed: Flow<Boolean> =
+    // "Compat" to cover both legacy and Scene container case in one flow.
+    private val isHomeStatusBarAllowedCompat =
         if (SceneContainerFlag.isEnabled) {
             isHomeStatusBarAllowedByScene
         } else {
             isHomeScreenStatusBarAllowedLegacy
         }
 
+    override val isHomeStatusBarAllowed =
+        isHomeStatusBarAllowedCompat.stateIn(
+            bgScope,
+            SharingStarted.WhileSubscribed(),
+            initialValue = false,
+        )
+
     private val shouldHomeStatusBarBeVisible =
         combine(
                 isHomeStatusBarAllowed,
@@ -369,15 +409,6 @@
             )
             .flowOn(bgDispatcher)
 
-    private val isAnyChipVisible =
-        if (StatusBarChipsModernization.isEnabled) {
-            ongoingActivityChips.map { it.active.any { chip -> !chip.isHidden } }
-        } else if (StatusBarNotifChips.isEnabled) {
-            ongoingActivityChipsLegacy.map { it.primary is OngoingActivityChipModel.Active }
-        } else {
-            primaryOngoingActivityChip.map { it is OngoingActivityChipModel.Active }
-        }
-
     /**
      * True if we need to hide the usual start side content in order to show the heads up
      * notification info.
@@ -419,9 +450,38 @@
         combine(
             isHomeStatusBarAllowed,
             keyguardInteractor.isSecureCameraActive,
-            headsUpNotificationInteractor.statusBarHeadsUpStatus,
-        ) { isHomeStatusBarAllowed, isSecureCameraActive, headsUpState ->
-            isHomeStatusBarAllowed && !isSecureCameraActive && !headsUpState.isPinned
+            hideStartSideContentForHeadsUp,
+        ) { isHomeStatusBarAllowed, isSecureCameraActive, hideStartSideContentForHeadsUp ->
+            isHomeStatusBarAllowed && !isSecureCameraActive && !hideStartSideContentForHeadsUp
+        }
+
+    override val ongoingActivityChips =
+        combine(ongoingActivityChipsViewModel.chips, canShowOngoingActivityChips) { chips, canShow
+                ->
+                ChipsVisibilityModel(chips, areChipsAllowed = canShow)
+            }
+            .stateIn(
+                bgScope,
+                SharingStarted.WhileSubscribed(),
+                initialValue =
+                    ChipsVisibilityModel(
+                        chips = MultipleOngoingActivityChipsModel(),
+                        areChipsAllowed = false,
+                    ),
+            )
+
+    private val hasOngoingActivityChips =
+        if (StatusBarChipsModernization.isEnabled) {
+            ongoingActivityChips.map { it.chips.active.any { chip -> !chip.isHidden } }
+        } else if (StatusBarNotifChips.isEnabled) {
+            ongoingActivityChipsLegacy.map { it.primary is OngoingActivityChipModel.Active }
+        } else {
+            primaryOngoingActivityChip.map { it is OngoingActivityChipModel.Active }
+        }
+
+    private val isAnyChipVisible =
+        combine(hasOngoingActivityChips, canShowOngoingActivityChips) { hasChips, canShowChips ->
+            hasChips && canShowChips
         }
 
     override val isClockVisible: Flow<VisibilityModel> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
index d41ef97..ab5b349 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/SecurityControllerImpl.java
@@ -425,7 +425,7 @@
     @Override
     @Nullable
     public Drawable getIcon() {
-        DeprecateDpmSupervisionApis.assertInNewMode();
+        DeprecateDpmSupervisionApis.unsafeAssertInNewMode();
         return isParentalControlsEnabled()
             ? mContext.getDrawable(R.drawable.ic_supervision)
             : null;
@@ -439,7 +439,7 @@
     @Override
     @Nullable
     public CharSequence getLabel() {
-        DeprecateDpmSupervisionApis.assertInNewMode();
+        DeprecateDpmSupervisionApis.unsafeAssertInNewMode();
         return isParentalControlsEnabled()
                 ? mContext.getString(R.string.status_bar_supervision)
                 : null;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
index a28d14f..e8347df 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/domain/interactor/ZenModeInteractor.kt
@@ -137,7 +137,7 @@
                 )
         else MutableStateFlow<ZenMode?>(null)
         get() {
-            ModesUi.assertInNewMode()
+            ModesUi.unsafeAssertInNewMode()
             return field
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
index 16f24f1..5d7ce91 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/ui/dialog/composable/ModeTileGrid.kt
@@ -34,7 +34,7 @@
 import androidx.compose.ui.unit.dp
 import androidx.lifecycle.compose.collectAsStateWithLifecycle
 import com.android.systemui.Flags
-import com.android.systemui.qs.panels.ui.compose.PagerDots
+import com.android.systemui.common.ui.compose.PagerDots
 import com.android.systemui.statusbar.policy.ui.dialog.viewmodel.ModesDialogViewModel
 
 @Composable
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
index 0596a80..25972ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerImpl.java
@@ -185,7 +185,7 @@
 
     @Override
     public void stop() {
-        StatusBarConnectedDisplays.assertInNewMode();
+        StatusBarConnectedDisplays.unsafeAssertInNewMode();
 
         try {
             mWindowManager.removeView(mStatusBarWindowView);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
index f7688d2..39afc38 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowControllerStore.kt
@@ -24,11 +24,11 @@
 import com.android.systemui.display.data.repository.DisplayRepository
 import com.android.systemui.display.data.repository.DisplayWindowPropertiesRepository
 import com.android.systemui.display.data.repository.PerDisplayStore
-import com.android.systemui.display.data.repository.PerDisplayStoreImpl
 import com.android.systemui.display.data.repository.SingleDisplayStore
 import com.android.systemui.statusbar.core.StatusBarConnectedDisplays
 import com.android.systemui.statusbar.data.repository.StatusBarConfigurationControllerStore
 import com.android.systemui.statusbar.data.repository.StatusBarContentInsetsProviderStore
+import com.android.systemui.statusbar.data.repository.StatusBarPerDisplayStoreImpl
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 
@@ -48,10 +48,13 @@
     displayRepository: DisplayRepository,
 ) :
     StatusBarWindowControllerStore,
-    PerDisplayStoreImpl<StatusBarWindowController>(backgroundApplicationScope, displayRepository) {
+    StatusBarPerDisplayStoreImpl<StatusBarWindowController>(
+        backgroundApplicationScope,
+        displayRepository,
+    ) {
 
     init {
-        StatusBarConnectedDisplays.assertInNewMode()
+        StatusBarConnectedDisplays.unsafeAssertInNewMode()
     }
 
     override fun createInstanceForDisplay(displayId: Int): StatusBarWindowController? {
diff --git a/packages/SystemUI/src/com/android/systemui/supervision/shared/DeprecateDpmSupervisionApis.kt b/packages/SystemUI/src/com/android/systemui/supervision/shared/DeprecateDpmSupervisionApis.kt
index cbd3dc7..a94d51a 100644
--- a/packages/SystemUI/src/com/android/systemui/supervision/shared/DeprecateDpmSupervisionApis.kt
+++ b/packages/SystemUI/src/com/android/systemui/supervision/shared/DeprecateDpmSupervisionApis.kt
@@ -50,7 +50,9 @@
      * Caution!! Using this check incorrectly will cause crashes in nextfood builds!
      */
     @JvmStatic
-    inline fun assertInNewMode() = RefactorFlagUtils.assertInNewMode(isEnabled, FLAG_NAME)
+    @Deprecated("Avoid crashing.", ReplaceWith("if (this.isUnexpectedlyInLegacyMode()) return"))
+    inline fun unsafeAssertInNewMode() =
+        RefactorFlagUtils.unsafeAssertInNewMode(isEnabled, FLAG_NAME)
 
     /**
      * Called to ensure code is only run when the flag is disabled. This will throw an exception if
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Producer.kt
similarity index 71%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/src/com/android/systemui/util/kotlin/Producer.kt
index 9b7cd70..a6209fa 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Producer.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,8 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.util.kotlin
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+/** Like a [javax.inject.Provider], but [get] is a `suspend fun`. */
+fun interface Producer<out T> {
+    suspend fun get(): T
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
index bb8fe46..3ac6c7b 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/VolumeDialog.kt
@@ -28,7 +28,7 @@
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.res.R
 import com.android.systemui.volume.Events
-import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
+import com.android.systemui.volume.dialog.dagger.factory.VolumeDialogComponentFactory
 import com.android.systemui.volume.dialog.domain.interactor.VolumeDialogVisibilityInteractor
 import javax.inject.Inject
 import kotlinx.coroutines.awaitCancellation
@@ -37,7 +37,7 @@
 @Inject
 constructor(
     @Application context: Context,
-    private val componentFactory: VolumeDialogComponent.Factory,
+    private val componentFactory: VolumeDialogComponentFactory,
     private val visibilityInteractor: VolumeDialogVisibilityInteractor,
 ) : ComponentDialog(context, R.style.Theme_SystemUI_Dialog_Volume) {
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
index 434f6b5..36b2b48 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/VolumeDialogComponent.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.volume.dialog.dagger
 
+import com.android.systemui.volume.dialog.dagger.factory.VolumeDialogComponentFactory
 import com.android.systemui.volume.dialog.dagger.module.VolumeDialogModule
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
@@ -38,9 +39,9 @@
     fun sliderComponentFactory(): VolumeDialogSliderComponent.Factory
 
     @Subcomponent.Factory
-    interface Factory {
+    interface Factory : VolumeDialogComponentFactory {
 
-        fun create(
+        override fun create(
             /**
              * Provides a coroutine scope to use inside [VolumeDialogScope].
              * [com.android.systemui.volume.dialog.VolumeDialogPlugin] manages the lifecycle of this
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/factory/VolumeDialogComponentFactory.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/factory/VolumeDialogComponentFactory.kt
new file mode 100644
index 0000000..d909f26
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/factory/VolumeDialogComponentFactory.kt
@@ -0,0 +1,26 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.volume.dialog.dagger.factory
+
+import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
+import kotlinx.coroutines.CoroutineScope
+
+/** Common interface for all dagger Subcomponent.Factory providing [VolumeDialogComponent]. */
+interface VolumeDialogComponentFactory {
+
+    fun create(scope: CoroutineScope): VolumeDialogComponent
+}
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt
index 7b08317..fcf4d110 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogModule.kt
@@ -16,10 +16,12 @@
 
 package com.android.systemui.volume.dialog.dagger.module
 
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
 import com.android.systemui.volume.dialog.ringer.data.repository.VolumeDialogRingerFeedbackRepository
 import com.android.systemui.volume.dialog.ringer.data.repository.VolumeDialogRingerFeedbackRepositoryImpl
 import com.android.systemui.volume.dialog.ringer.ui.binder.VolumeDialogRingerViewBinder
 import com.android.systemui.volume.dialog.settings.ui.binder.VolumeDialogSettingsButtonViewBinder
+import com.android.systemui.volume.dialog.sliders.dagger.VolumeDialogSliderComponent
 import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSlidersViewBinder
 import com.android.systemui.volume.dialog.ui.binder.ViewBinder
 import dagger.Binds
@@ -27,7 +29,7 @@
 import dagger.Provides
 
 /** Dagger module for volume dialog code in the volume package */
-@Module
+@Module(subcomponents = [VolumeDialogSliderComponent::class])
 interface VolumeDialogModule {
 
     @Binds
@@ -38,6 +40,7 @@
     companion object {
 
         @Provides
+        @VolumeDialog
         fun provideViewBinders(
             slidersViewBinder: VolumeDialogSlidersViewBinder,
             ringerViewBinder: VolumeDialogRingerViewBinder,
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogPluginModule.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogPluginModule.kt
index 547c51d..35752ae 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogPluginModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/dagger/module/VolumeDialogPluginModule.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.volume.dialog.dagger.module
 
 import com.android.systemui.volume.dialog.dagger.VolumeDialogComponent
+import com.android.systemui.volume.dialog.dagger.factory.VolumeDialogComponentFactory
 import com.android.systemui.volume.dialog.shared.model.CsdWarningConfigModel
 import com.android.systemui.volume.dialog.utils.VolumeTracer
 import com.android.systemui.volume.dialog.utils.VolumeTracerImpl
@@ -27,6 +28,11 @@
 @Module(subcomponents = [VolumeDialogComponent::class])
 interface VolumeDialogPluginModule {
 
+    @Binds
+    fun bindVolumeDialogComponentFactory(
+        factory: VolumeDialogComponent.Factory
+    ): VolumeDialogComponentFactory
+
     @Binds fun bindVolumeTracer(volumeTracer: VolumeTracerImpl): VolumeTracer
 
     companion object {
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt
index 577e47b..d0ed24d 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponent.kt
@@ -19,6 +19,7 @@
 import com.android.systemui.volume.dialog.sliders.domain.model.VolumeDialogSliderType
 import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogOverscrollViewBinder
 import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSliderViewBinder
+import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderViewModel
 import dagger.BindsInstance
 import dagger.Subcomponent
 
@@ -34,6 +35,8 @@
 
     fun overscrollViewBinder(): VolumeDialogOverscrollViewBinder
 
+    fun sliderViewModel(): VolumeDialogSliderViewModel
+
     @Subcomponent.Factory
     interface Factory {
 
diff --git a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
index 5de8fe5..11d9df4 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/dialog/ui/binder/VolumeDialogViewBinder.kt
@@ -37,6 +37,7 @@
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.res.R
 import com.android.systemui.util.kotlin.awaitCancellationThenDispose
+import com.android.systemui.volume.dialog.dagger.scope.VolumeDialog
 import com.android.systemui.volume.dialog.dagger.scope.VolumeDialogScope
 import com.android.systemui.volume.dialog.shared.model.VolumeDialogVisibilityModel
 import com.android.systemui.volume.dialog.ui.utils.JankListenerFactory
@@ -72,7 +73,7 @@
     private val viewModel: VolumeDialogViewModel,
     private val jankListenerFactory: JankListenerFactory,
     private val tracer: VolumeTracer,
-    private val viewBinders: List<@JvmSuppressWildcards ViewBinder>,
+    @VolumeDialog private val viewBinders: List<@JvmSuppressWildcards ViewBinder>,
 ) {
 
     private val halfOpenedOffsetPx: Float =
diff --git a/packages/SystemUI/src/com/android/systemui/volume/panel/shared/flag/VolumePanelFlag.kt b/packages/SystemUI/src/com/android/systemui/volume/panel/shared/flag/VolumePanelFlag.kt
index 485f4b5..4919139 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/panel/shared/flag/VolumePanelFlag.kt
+++ b/packages/SystemUI/src/com/android/systemui/volume/panel/shared/flag/VolumePanelFlag.kt
@@ -29,6 +29,6 @@
     }
 
     fun assertNewVolumePanel() {
-        RefactorFlagUtils.assertInNewMode(Flags.newVolumePanel(), Flags.FLAG_NEW_VOLUME_PANEL)
+        RefactorFlagUtils.unsafeAssertInNewMode(Flags.newVolumePanel(), Flags.FLAG_NEW_VOLUME_PANEL)
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
index feaf1a6..8e71349 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/WMShell.java
@@ -302,7 +302,7 @@
                         .commitUpdate(mDisplayTracker.getDefaultDisplayId());
             }
         });
-        mSysUiState.addCallback(sysUiStateFlag -> {
+        mSysUiState.addCallback((sysUiStateFlag, displayId) -> {
             mIsSysUiStateValid = (sysUiStateFlag & INVALID_SYSUI_STATE_MASK) == 0;
             pip.onSystemUiStateChanged(mIsSysUiStateValid, sysUiStateFlag);
         });
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
rename from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
rename to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
similarity index 93%
rename from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
rename to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 93%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..5476160 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
rename from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withAnimator.json
rename to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 98%
rename from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withAnimator.json
rename to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index aa80445..41a46df 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withAnimator.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -468,15 +468,15 @@
         238,
         249,
         254,
-        233,
-        191,
-        153,
-        117,
-        85,
-        57,
-        33,
-        14,
-        3,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         0,
         0,
         0,
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
rename from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json
rename to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenLaunching_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 100%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withAnimator.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withAnimator_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
similarity index 92%
copy from packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
copy to packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
index 5619611..848c7d4 100644
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenReturning_withSpring.json
+++ b/packages/SystemUI/tests/goldens/animations/withoutFade_withoutHole_whenReturning_withSpring_backgroundAnimationTimeSeries_drawHoleAfterFadeout.json
@@ -350,12 +350,12 @@
       "type": "int",
       "data_points": [
         0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
+        255,
+        255,
+        255,
+        255,
+        255,
+        255,
         255,
         255,
         255,
@@ -371,14 +371,5 @@
         0
       ]
     }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenReturning_withSpring.actual.mp4"
-  }
+  ]
 }
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withSpring.json b/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withSpring.json
deleted file mode 100644
index 7abff2c..0000000
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withFade_whenLaunching_withSpring.json
+++ /dev/null
@@ -1,384 +0,0 @@
-{
-  "frame_ids": [
-    0,
-    16,
-    32,
-    48,
-    64,
-    80,
-    96,
-    112,
-    128,
-    144,
-    160,
-    176,
-    192,
-    208,
-    224,
-    240,
-    256,
-    272,
-    288,
-    304
-  ],
-  "features": [
-    {
-      "name": "bounds",
-      "type": "rect",
-      "data_points": [
-        {
-          "left": 0,
-          "top": 0,
-          "right": 0,
-          "bottom": 0
-        },
-        {
-          "left": 104,
-          "top": 285,
-          "right": 215,
-          "bottom": 414
-        },
-        {
-          "left": 92,
-          "top": 252,
-          "right": 227,
-          "bottom": 447
-        },
-        {
-          "left": 77,
-          "top": 213,
-          "right": 242,
-          "bottom": 486
-        },
-        {
-          "left": 63,
-          "top": 175,
-          "right": 256,
-          "bottom": 524
-        },
-        {
-          "left": 50,
-          "top": 141,
-          "right": 269,
-          "bottom": 558
-        },
-        {
-          "left": 40,
-          "top": 112,
-          "right": 279,
-          "bottom": 587
-        },
-        {
-          "left": 31,
-          "top": 88,
-          "right": 288,
-          "bottom": 611
-        },
-        {
-          "left": 23,
-          "top": 68,
-          "right": 296,
-          "bottom": 631
-        },
-        {
-          "left": 18,
-          "top": 53,
-          "right": 301,
-          "bottom": 646
-        },
-        {
-          "left": 13,
-          "top": 41,
-          "right": 306,
-          "bottom": 658
-        },
-        {
-          "left": 10,
-          "top": 31,
-          "right": 309,
-          "bottom": 667
-        },
-        {
-          "left": 7,
-          "top": 24,
-          "right": 312,
-          "bottom": 673
-        },
-        {
-          "left": 5,
-          "top": 18,
-          "right": 314,
-          "bottom": 678
-        },
-        {
-          "left": 4,
-          "top": 13,
-          "right": 315,
-          "bottom": 681
-        },
-        {
-          "left": 3,
-          "top": 10,
-          "right": 316,
-          "bottom": 684
-        },
-        {
-          "left": 2,
-          "top": 7,
-          "right": 317,
-          "bottom": 685
-        },
-        {
-          "left": 1,
-          "top": 5,
-          "right": 318,
-          "bottom": 687
-        },
-        {
-          "left": 1,
-          "top": 4,
-          "right": 318,
-          "bottom": 688
-        },
-        {
-          "left": 0,
-          "top": 3,
-          "right": 319,
-          "bottom": 688
-        }
-      ]
-    },
-    {
-      "name": "corner_radii",
-      "type": "cornerRadii",
-      "data_points": [
-        null,
-        {
-          "top_left_x": 9.492916,
-          "top_left_y": 9.492916,
-          "top_right_x": 9.492916,
-          "top_right_y": 9.492916,
-          "bottom_right_x": 18.985832,
-          "bottom_right_y": 18.985832,
-          "bottom_left_x": 18.985832,
-          "bottom_left_y": 18.985832
-        },
-        {
-          "top_left_x": 8.381761,
-          "top_left_y": 8.381761,
-          "top_right_x": 8.381761,
-          "top_right_y": 8.381761,
-          "bottom_right_x": 16.763521,
-          "bottom_right_y": 16.763521,
-          "bottom_left_x": 16.763521,
-          "bottom_left_y": 16.763521
-        },
-        {
-          "top_left_x": 7.07397,
-          "top_left_y": 7.07397,
-          "top_right_x": 7.07397,
-          "top_right_y": 7.07397,
-          "bottom_right_x": 14.14794,
-          "bottom_right_y": 14.14794,
-          "bottom_left_x": 14.14794,
-          "bottom_left_y": 14.14794
-        },
-        {
-          "top_left_x": 5.7880254,
-          "top_left_y": 5.7880254,
-          "top_right_x": 5.7880254,
-          "top_right_y": 5.7880254,
-          "bottom_right_x": 11.576051,
-          "bottom_right_y": 11.576051,
-          "bottom_left_x": 11.576051,
-          "bottom_left_y": 11.576051
-        },
-        {
-          "top_left_x": 4.6295347,
-          "top_left_y": 4.6295347,
-          "top_right_x": 4.6295347,
-          "top_right_y": 4.6295347,
-          "bottom_right_x": 9.259069,
-          "bottom_right_y": 9.259069,
-          "bottom_left_x": 9.259069,
-          "bottom_left_y": 9.259069
-        },
-        {
-          "top_left_x": 3.638935,
-          "top_left_y": 3.638935,
-          "top_right_x": 3.638935,
-          "top_right_y": 3.638935,
-          "bottom_right_x": 7.27787,
-          "bottom_right_y": 7.27787,
-          "bottom_left_x": 7.27787,
-          "bottom_left_y": 7.27787
-        },
-        {
-          "top_left_x": 2.8209057,
-          "top_left_y": 2.8209057,
-          "top_right_x": 2.8209057,
-          "top_right_y": 2.8209057,
-          "bottom_right_x": 5.6418114,
-          "bottom_right_y": 5.6418114,
-          "bottom_left_x": 5.6418114,
-          "bottom_left_y": 5.6418114
-        },
-        {
-          "top_left_x": 2.1620893,
-          "top_left_y": 2.1620893,
-          "top_right_x": 2.1620893,
-          "top_right_y": 2.1620893,
-          "bottom_right_x": 4.3241787,
-          "bottom_right_y": 4.3241787,
-          "bottom_left_x": 4.3241787,
-          "bottom_left_y": 4.3241787
-        },
-        {
-          "top_left_x": 1.6414614,
-          "top_left_y": 1.6414614,
-          "top_right_x": 1.6414614,
-          "top_right_y": 1.6414614,
-          "bottom_right_x": 3.2829227,
-          "bottom_right_y": 3.2829227,
-          "bottom_left_x": 3.2829227,
-          "bottom_left_y": 3.2829227
-        },
-        {
-          "top_left_x": 1.2361269,
-          "top_left_y": 1.2361269,
-          "top_right_x": 1.2361269,
-          "top_right_y": 1.2361269,
-          "bottom_right_x": 2.4722538,
-          "bottom_right_y": 2.4722538,
-          "bottom_left_x": 2.4722538,
-          "bottom_left_y": 2.4722538
-        },
-        {
-          "top_left_x": 0.92435074,
-          "top_left_y": 0.92435074,
-          "top_right_x": 0.92435074,
-          "top_right_y": 0.92435074,
-          "bottom_right_x": 1.8487015,
-          "bottom_right_y": 1.8487015,
-          "bottom_left_x": 1.8487015,
-          "bottom_left_y": 1.8487015
-        },
-        {
-          "top_left_x": 0.68693924,
-          "top_left_y": 0.68693924,
-          "top_right_x": 0.68693924,
-          "top_right_y": 0.68693924,
-          "bottom_right_x": 1.3738785,
-          "bottom_right_y": 1.3738785,
-          "bottom_left_x": 1.3738785,
-          "bottom_left_y": 1.3738785
-        },
-        {
-          "top_left_x": 0.5076904,
-          "top_left_y": 0.5076904,
-          "top_right_x": 0.5076904,
-          "top_right_y": 0.5076904,
-          "bottom_right_x": 1.0153809,
-          "bottom_right_y": 1.0153809,
-          "bottom_left_x": 1.0153809,
-          "bottom_left_y": 1.0153809
-        },
-        {
-          "top_left_x": 0.3733511,
-          "top_left_y": 0.3733511,
-          "top_right_x": 0.3733511,
-          "top_right_y": 0.3733511,
-          "bottom_right_x": 0.7467022,
-          "bottom_right_y": 0.7467022,
-          "bottom_left_x": 0.7467022,
-          "bottom_left_y": 0.7467022
-        },
-        {
-          "top_left_x": 0.27331638,
-          "top_left_y": 0.27331638,
-          "top_right_x": 0.27331638,
-          "top_right_y": 0.27331638,
-          "bottom_right_x": 0.54663277,
-          "bottom_right_y": 0.54663277,
-          "bottom_left_x": 0.54663277,
-          "bottom_left_y": 0.54663277
-        },
-        {
-          "top_left_x": 0.19925308,
-          "top_left_y": 0.19925308,
-          "top_right_x": 0.19925308,
-          "top_right_y": 0.19925308,
-          "bottom_right_x": 0.39850616,
-          "bottom_right_y": 0.39850616,
-          "bottom_left_x": 0.39850616,
-          "bottom_left_y": 0.39850616
-        },
-        {
-          "top_left_x": 0.14470005,
-          "top_left_y": 0.14470005,
-          "top_right_x": 0.14470005,
-          "top_right_y": 0.14470005,
-          "bottom_right_x": 0.2894001,
-          "bottom_right_y": 0.2894001,
-          "bottom_left_x": 0.2894001,
-          "bottom_left_y": 0.2894001
-        },
-        {
-          "top_left_x": 0.10470486,
-          "top_left_y": 0.10470486,
-          "top_right_x": 0.10470486,
-          "top_right_y": 0.10470486,
-          "bottom_right_x": 0.20940971,
-          "bottom_right_y": 0.20940971,
-          "bottom_left_x": 0.20940971,
-          "bottom_left_y": 0.20940971
-        },
-        {
-          "top_left_x": 0.07550812,
-          "top_left_y": 0.07550812,
-          "top_right_x": 0.07550812,
-          "top_right_y": 0.07550812,
-          "bottom_right_x": 0.15101624,
-          "bottom_right_y": 0.15101624,
-          "bottom_left_x": 0.15101624,
-          "bottom_left_y": 0.15101624
-        }
-      ]
-    },
-    {
-      "name": "alpha",
-      "type": "int",
-      "data_points": [
-        0,
-        45,
-        126,
-        190,
-        228,
-        246,
-        253,
-        255,
-        255,
-        255,
-        249,
-        226,
-        192,
-        153,
-        112,
-        72,
-        34,
-        0,
-        0,
-        0
-      ]
-    }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimation_whenLaunching_withSpring.json",
-    "goldenIdentifier": "backgroundAnimation_whenLaunching_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimation_whenLaunching[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimation_whenLaunching_withSpring.actual.mp4"
-  }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withSpring.json b/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withSpring.json
deleted file mode 100644
index 825190b..0000000
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenLaunching_withSpring.json
+++ /dev/null
@@ -1,384 +0,0 @@
-{
-  "frame_ids": [
-    0,
-    16,
-    32,
-    48,
-    64,
-    80,
-    96,
-    112,
-    128,
-    144,
-    160,
-    176,
-    192,
-    208,
-    224,
-    240,
-    256,
-    272,
-    288,
-    304
-  ],
-  "features": [
-    {
-      "name": "bounds",
-      "type": "rect",
-      "data_points": [
-        {
-          "left": 0,
-          "top": 0,
-          "right": 0,
-          "bottom": 0
-        },
-        {
-          "left": 104,
-          "top": 285,
-          "right": 215,
-          "bottom": 414
-        },
-        {
-          "left": 92,
-          "top": 252,
-          "right": 227,
-          "bottom": 447
-        },
-        {
-          "left": 77,
-          "top": 213,
-          "right": 242,
-          "bottom": 486
-        },
-        {
-          "left": 63,
-          "top": 175,
-          "right": 256,
-          "bottom": 524
-        },
-        {
-          "left": 50,
-          "top": 141,
-          "right": 269,
-          "bottom": 558
-        },
-        {
-          "left": 40,
-          "top": 112,
-          "right": 279,
-          "bottom": 587
-        },
-        {
-          "left": 31,
-          "top": 88,
-          "right": 288,
-          "bottom": 611
-        },
-        {
-          "left": 23,
-          "top": 68,
-          "right": 296,
-          "bottom": 631
-        },
-        {
-          "left": 18,
-          "top": 53,
-          "right": 301,
-          "bottom": 646
-        },
-        {
-          "left": 13,
-          "top": 41,
-          "right": 306,
-          "bottom": 658
-        },
-        {
-          "left": 10,
-          "top": 31,
-          "right": 309,
-          "bottom": 667
-        },
-        {
-          "left": 7,
-          "top": 24,
-          "right": 312,
-          "bottom": 673
-        },
-        {
-          "left": 5,
-          "top": 18,
-          "right": 314,
-          "bottom": 678
-        },
-        {
-          "left": 4,
-          "top": 13,
-          "right": 315,
-          "bottom": 681
-        },
-        {
-          "left": 3,
-          "top": 10,
-          "right": 316,
-          "bottom": 684
-        },
-        {
-          "left": 2,
-          "top": 7,
-          "right": 317,
-          "bottom": 685
-        },
-        {
-          "left": 1,
-          "top": 5,
-          "right": 318,
-          "bottom": 687
-        },
-        {
-          "left": 1,
-          "top": 4,
-          "right": 318,
-          "bottom": 688
-        },
-        {
-          "left": 0,
-          "top": 3,
-          "right": 319,
-          "bottom": 688
-        }
-      ]
-    },
-    {
-      "name": "corner_radii",
-      "type": "cornerRadii",
-      "data_points": [
-        null,
-        {
-          "top_left_x": 9.492916,
-          "top_left_y": 9.492916,
-          "top_right_x": 9.492916,
-          "top_right_y": 9.492916,
-          "bottom_right_x": 18.985832,
-          "bottom_right_y": 18.985832,
-          "bottom_left_x": 18.985832,
-          "bottom_left_y": 18.985832
-        },
-        {
-          "top_left_x": 8.381761,
-          "top_left_y": 8.381761,
-          "top_right_x": 8.381761,
-          "top_right_y": 8.381761,
-          "bottom_right_x": 16.763521,
-          "bottom_right_y": 16.763521,
-          "bottom_left_x": 16.763521,
-          "bottom_left_y": 16.763521
-        },
-        {
-          "top_left_x": 7.07397,
-          "top_left_y": 7.07397,
-          "top_right_x": 7.07397,
-          "top_right_y": 7.07397,
-          "bottom_right_x": 14.14794,
-          "bottom_right_y": 14.14794,
-          "bottom_left_x": 14.14794,
-          "bottom_left_y": 14.14794
-        },
-        {
-          "top_left_x": 5.7880254,
-          "top_left_y": 5.7880254,
-          "top_right_x": 5.7880254,
-          "top_right_y": 5.7880254,
-          "bottom_right_x": 11.576051,
-          "bottom_right_y": 11.576051,
-          "bottom_left_x": 11.576051,
-          "bottom_left_y": 11.576051
-        },
-        {
-          "top_left_x": 4.6295347,
-          "top_left_y": 4.6295347,
-          "top_right_x": 4.6295347,
-          "top_right_y": 4.6295347,
-          "bottom_right_x": 9.259069,
-          "bottom_right_y": 9.259069,
-          "bottom_left_x": 9.259069,
-          "bottom_left_y": 9.259069
-        },
-        {
-          "top_left_x": 3.638935,
-          "top_left_y": 3.638935,
-          "top_right_x": 3.638935,
-          "top_right_y": 3.638935,
-          "bottom_right_x": 7.27787,
-          "bottom_right_y": 7.27787,
-          "bottom_left_x": 7.27787,
-          "bottom_left_y": 7.27787
-        },
-        {
-          "top_left_x": 2.8209057,
-          "top_left_y": 2.8209057,
-          "top_right_x": 2.8209057,
-          "top_right_y": 2.8209057,
-          "bottom_right_x": 5.6418114,
-          "bottom_right_y": 5.6418114,
-          "bottom_left_x": 5.6418114,
-          "bottom_left_y": 5.6418114
-        },
-        {
-          "top_left_x": 2.1620893,
-          "top_left_y": 2.1620893,
-          "top_right_x": 2.1620893,
-          "top_right_y": 2.1620893,
-          "bottom_right_x": 4.3241787,
-          "bottom_right_y": 4.3241787,
-          "bottom_left_x": 4.3241787,
-          "bottom_left_y": 4.3241787
-        },
-        {
-          "top_left_x": 1.6414614,
-          "top_left_y": 1.6414614,
-          "top_right_x": 1.6414614,
-          "top_right_y": 1.6414614,
-          "bottom_right_x": 3.2829227,
-          "bottom_right_y": 3.2829227,
-          "bottom_left_x": 3.2829227,
-          "bottom_left_y": 3.2829227
-        },
-        {
-          "top_left_x": 1.2361269,
-          "top_left_y": 1.2361269,
-          "top_right_x": 1.2361269,
-          "top_right_y": 1.2361269,
-          "bottom_right_x": 2.4722538,
-          "bottom_right_y": 2.4722538,
-          "bottom_left_x": 2.4722538,
-          "bottom_left_y": 2.4722538
-        },
-        {
-          "top_left_x": 0.92435074,
-          "top_left_y": 0.92435074,
-          "top_right_x": 0.92435074,
-          "top_right_y": 0.92435074,
-          "bottom_right_x": 1.8487015,
-          "bottom_right_y": 1.8487015,
-          "bottom_left_x": 1.8487015,
-          "bottom_left_y": 1.8487015
-        },
-        {
-          "top_left_x": 0.68693924,
-          "top_left_y": 0.68693924,
-          "top_right_x": 0.68693924,
-          "top_right_y": 0.68693924,
-          "bottom_right_x": 1.3738785,
-          "bottom_right_y": 1.3738785,
-          "bottom_left_x": 1.3738785,
-          "bottom_left_y": 1.3738785
-        },
-        {
-          "top_left_x": 0.5076904,
-          "top_left_y": 0.5076904,
-          "top_right_x": 0.5076904,
-          "top_right_y": 0.5076904,
-          "bottom_right_x": 1.0153809,
-          "bottom_right_y": 1.0153809,
-          "bottom_left_x": 1.0153809,
-          "bottom_left_y": 1.0153809
-        },
-        {
-          "top_left_x": 0.3733511,
-          "top_left_y": 0.3733511,
-          "top_right_x": 0.3733511,
-          "top_right_y": 0.3733511,
-          "bottom_right_x": 0.7467022,
-          "bottom_right_y": 0.7467022,
-          "bottom_left_x": 0.7467022,
-          "bottom_left_y": 0.7467022
-        },
-        {
-          "top_left_x": 0.27331638,
-          "top_left_y": 0.27331638,
-          "top_right_x": 0.27331638,
-          "top_right_y": 0.27331638,
-          "bottom_right_x": 0.54663277,
-          "bottom_right_y": 0.54663277,
-          "bottom_left_x": 0.54663277,
-          "bottom_left_y": 0.54663277
-        },
-        {
-          "top_left_x": 0.19925308,
-          "top_left_y": 0.19925308,
-          "top_right_x": 0.19925308,
-          "top_right_y": 0.19925308,
-          "bottom_right_x": 0.39850616,
-          "bottom_right_y": 0.39850616,
-          "bottom_left_x": 0.39850616,
-          "bottom_left_y": 0.39850616
-        },
-        {
-          "top_left_x": 0.14470005,
-          "top_left_y": 0.14470005,
-          "top_right_x": 0.14470005,
-          "top_right_y": 0.14470005,
-          "bottom_right_x": 0.2894001,
-          "bottom_right_y": 0.2894001,
-          "bottom_left_x": 0.2894001,
-          "bottom_left_y": 0.2894001
-        },
-        {
-          "top_left_x": 0.10470486,
-          "top_left_y": 0.10470486,
-          "top_right_x": 0.10470486,
-          "top_right_y": 0.10470486,
-          "bottom_right_x": 0.20940971,
-          "bottom_right_y": 0.20940971,
-          "bottom_left_x": 0.20940971,
-          "bottom_left_y": 0.20940971
-        },
-        {
-          "top_left_x": 0.07550812,
-          "top_left_y": 0.07550812,
-          "top_right_x": 0.07550812,
-          "top_right_y": 0.07550812,
-          "bottom_right_x": 0.15101624,
-          "bottom_right_y": 0.15101624,
-          "bottom_left_x": 0.15101624,
-          "bottom_left_y": 0.15101624
-        }
-      ]
-    },
-    {
-      "name": "alpha",
-      "type": "int",
-      "data_points": [
-        0,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        249,
-        226,
-        192,
-        153,
-        112,
-        72,
-        34,
-        0,
-        0,
-        0
-      ]
-    }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimationWithoutFade_whenLaunching_withSpring.json",
-    "goldenIdentifier": "backgroundAnimationWithoutFade_whenLaunching_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimationWithoutFade_whenLaunching[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimationWithoutFade_whenLaunching_withSpring.actual.mp4"
-  }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withSpring.json b/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withSpring.json
deleted file mode 100644
index 63c2631..0000000
--- a/packages/SystemUI/tests/goldens/backgroundAnimationTimeSeries_withoutFade_whenReturning_withSpring.json
+++ /dev/null
@@ -1,384 +0,0 @@
-{
-  "frame_ids": [
-    0,
-    16,
-    32,
-    48,
-    64,
-    80,
-    96,
-    112,
-    128,
-    144,
-    160,
-    176,
-    192,
-    208,
-    224,
-    240,
-    256,
-    272,
-    288,
-    304
-  ],
-  "features": [
-    {
-      "name": "bounds",
-      "type": "rect",
-      "data_points": [
-        {
-          "left": 0,
-          "top": 0,
-          "right": 0,
-          "bottom": 0
-        },
-        {
-          "left": 104,
-          "top": 285,
-          "right": 215,
-          "bottom": 414
-        },
-        {
-          "left": 92,
-          "top": 252,
-          "right": 227,
-          "bottom": 447
-        },
-        {
-          "left": 77,
-          "top": 213,
-          "right": 242,
-          "bottom": 486
-        },
-        {
-          "left": 63,
-          "top": 175,
-          "right": 256,
-          "bottom": 524
-        },
-        {
-          "left": 50,
-          "top": 141,
-          "right": 269,
-          "bottom": 558
-        },
-        {
-          "left": 40,
-          "top": 112,
-          "right": 279,
-          "bottom": 587
-        },
-        {
-          "left": 31,
-          "top": 88,
-          "right": 288,
-          "bottom": 611
-        },
-        {
-          "left": 23,
-          "top": 68,
-          "right": 296,
-          "bottom": 631
-        },
-        {
-          "left": 18,
-          "top": 53,
-          "right": 301,
-          "bottom": 646
-        },
-        {
-          "left": 13,
-          "top": 41,
-          "right": 306,
-          "bottom": 658
-        },
-        {
-          "left": 10,
-          "top": 31,
-          "right": 309,
-          "bottom": 667
-        },
-        {
-          "left": 7,
-          "top": 24,
-          "right": 312,
-          "bottom": 673
-        },
-        {
-          "left": 5,
-          "top": 18,
-          "right": 314,
-          "bottom": 678
-        },
-        {
-          "left": 4,
-          "top": 13,
-          "right": 315,
-          "bottom": 681
-        },
-        {
-          "left": 3,
-          "top": 10,
-          "right": 316,
-          "bottom": 684
-        },
-        {
-          "left": 2,
-          "top": 7,
-          "right": 317,
-          "bottom": 685
-        },
-        {
-          "left": 1,
-          "top": 5,
-          "right": 318,
-          "bottom": 687
-        },
-        {
-          "left": 1,
-          "top": 4,
-          "right": 318,
-          "bottom": 688
-        },
-        {
-          "left": 0,
-          "top": 3,
-          "right": 319,
-          "bottom": 688
-        }
-      ]
-    },
-    {
-      "name": "corner_radii",
-      "type": "cornerRadii",
-      "data_points": [
-        null,
-        {
-          "top_left_x": 9.492916,
-          "top_left_y": 9.492916,
-          "top_right_x": 9.492916,
-          "top_right_y": 9.492916,
-          "bottom_right_x": 18.985832,
-          "bottom_right_y": 18.985832,
-          "bottom_left_x": 18.985832,
-          "bottom_left_y": 18.985832
-        },
-        {
-          "top_left_x": 8.381761,
-          "top_left_y": 8.381761,
-          "top_right_x": 8.381761,
-          "top_right_y": 8.381761,
-          "bottom_right_x": 16.763521,
-          "bottom_right_y": 16.763521,
-          "bottom_left_x": 16.763521,
-          "bottom_left_y": 16.763521
-        },
-        {
-          "top_left_x": 7.07397,
-          "top_left_y": 7.07397,
-          "top_right_x": 7.07397,
-          "top_right_y": 7.07397,
-          "bottom_right_x": 14.14794,
-          "bottom_right_y": 14.14794,
-          "bottom_left_x": 14.14794,
-          "bottom_left_y": 14.14794
-        },
-        {
-          "top_left_x": 5.7880254,
-          "top_left_y": 5.7880254,
-          "top_right_x": 5.7880254,
-          "top_right_y": 5.7880254,
-          "bottom_right_x": 11.576051,
-          "bottom_right_y": 11.576051,
-          "bottom_left_x": 11.576051,
-          "bottom_left_y": 11.576051
-        },
-        {
-          "top_left_x": 4.6295347,
-          "top_left_y": 4.6295347,
-          "top_right_x": 4.6295347,
-          "top_right_y": 4.6295347,
-          "bottom_right_x": 9.259069,
-          "bottom_right_y": 9.259069,
-          "bottom_left_x": 9.259069,
-          "bottom_left_y": 9.259069
-        },
-        {
-          "top_left_x": 3.638935,
-          "top_left_y": 3.638935,
-          "top_right_x": 3.638935,
-          "top_right_y": 3.638935,
-          "bottom_right_x": 7.27787,
-          "bottom_right_y": 7.27787,
-          "bottom_left_x": 7.27787,
-          "bottom_left_y": 7.27787
-        },
-        {
-          "top_left_x": 2.8209057,
-          "top_left_y": 2.8209057,
-          "top_right_x": 2.8209057,
-          "top_right_y": 2.8209057,
-          "bottom_right_x": 5.6418114,
-          "bottom_right_y": 5.6418114,
-          "bottom_left_x": 5.6418114,
-          "bottom_left_y": 5.6418114
-        },
-        {
-          "top_left_x": 2.1620893,
-          "top_left_y": 2.1620893,
-          "top_right_x": 2.1620893,
-          "top_right_y": 2.1620893,
-          "bottom_right_x": 4.3241787,
-          "bottom_right_y": 4.3241787,
-          "bottom_left_x": 4.3241787,
-          "bottom_left_y": 4.3241787
-        },
-        {
-          "top_left_x": 1.6414614,
-          "top_left_y": 1.6414614,
-          "top_right_x": 1.6414614,
-          "top_right_y": 1.6414614,
-          "bottom_right_x": 3.2829227,
-          "bottom_right_y": 3.2829227,
-          "bottom_left_x": 3.2829227,
-          "bottom_left_y": 3.2829227
-        },
-        {
-          "top_left_x": 1.2361269,
-          "top_left_y": 1.2361269,
-          "top_right_x": 1.2361269,
-          "top_right_y": 1.2361269,
-          "bottom_right_x": 2.4722538,
-          "bottom_right_y": 2.4722538,
-          "bottom_left_x": 2.4722538,
-          "bottom_left_y": 2.4722538
-        },
-        {
-          "top_left_x": 0.92435074,
-          "top_left_y": 0.92435074,
-          "top_right_x": 0.92435074,
-          "top_right_y": 0.92435074,
-          "bottom_right_x": 1.8487015,
-          "bottom_right_y": 1.8487015,
-          "bottom_left_x": 1.8487015,
-          "bottom_left_y": 1.8487015
-        },
-        {
-          "top_left_x": 0.68693924,
-          "top_left_y": 0.68693924,
-          "top_right_x": 0.68693924,
-          "top_right_y": 0.68693924,
-          "bottom_right_x": 1.3738785,
-          "bottom_right_y": 1.3738785,
-          "bottom_left_x": 1.3738785,
-          "bottom_left_y": 1.3738785
-        },
-        {
-          "top_left_x": 0.5076904,
-          "top_left_y": 0.5076904,
-          "top_right_x": 0.5076904,
-          "top_right_y": 0.5076904,
-          "bottom_right_x": 1.0153809,
-          "bottom_right_y": 1.0153809,
-          "bottom_left_x": 1.0153809,
-          "bottom_left_y": 1.0153809
-        },
-        {
-          "top_left_x": 0.3733511,
-          "top_left_y": 0.3733511,
-          "top_right_x": 0.3733511,
-          "top_right_y": 0.3733511,
-          "bottom_right_x": 0.7467022,
-          "bottom_right_y": 0.7467022,
-          "bottom_left_x": 0.7467022,
-          "bottom_left_y": 0.7467022
-        },
-        {
-          "top_left_x": 0.27331638,
-          "top_left_y": 0.27331638,
-          "top_right_x": 0.27331638,
-          "top_right_y": 0.27331638,
-          "bottom_right_x": 0.54663277,
-          "bottom_right_y": 0.54663277,
-          "bottom_left_x": 0.54663277,
-          "bottom_left_y": 0.54663277
-        },
-        {
-          "top_left_x": 0.19925308,
-          "top_left_y": 0.19925308,
-          "top_right_x": 0.19925308,
-          "top_right_y": 0.19925308,
-          "bottom_right_x": 0.39850616,
-          "bottom_right_y": 0.39850616,
-          "bottom_left_x": 0.39850616,
-          "bottom_left_y": 0.39850616
-        },
-        {
-          "top_left_x": 0.14470005,
-          "top_left_y": 0.14470005,
-          "top_right_x": 0.14470005,
-          "top_right_y": 0.14470005,
-          "bottom_right_x": 0.2894001,
-          "bottom_right_y": 0.2894001,
-          "bottom_left_x": 0.2894001,
-          "bottom_left_y": 0.2894001
-        },
-        {
-          "top_left_x": 0.10470486,
-          "top_left_y": 0.10470486,
-          "top_right_x": 0.10470486,
-          "top_right_y": 0.10470486,
-          "bottom_right_x": 0.20940971,
-          "bottom_right_y": 0.20940971,
-          "bottom_left_x": 0.20940971,
-          "bottom_left_y": 0.20940971
-        },
-        {
-          "top_left_x": 0.07550812,
-          "top_left_y": 0.07550812,
-          "top_right_x": 0.07550812,
-          "top_right_y": 0.07550812,
-          "bottom_right_x": 0.15101624,
-          "bottom_right_y": 0.15101624,
-          "bottom_left_x": 0.15101624,
-          "bottom_left_y": 0.15101624
-        }
-      ]
-    },
-    {
-      "name": "alpha",
-      "type": "int",
-      "data_points": [
-        0,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        255,
-        249,
-        226,
-        192,
-        153,
-        112,
-        72,
-        34,
-        0,
-        0,
-        0
-      ]
-    }
-  ],
-  "\/\/metadata": {
-    "goldenRepoPath": "frameworks\/base\/packages\/SystemUI\/tests\/goldens\/backgroundAnimationWithoutFade_whenReturning_withSpring.json",
-    "goldenIdentifier": "backgroundAnimationWithoutFade_whenReturning_withSpring",
-    "testClassName": "TransitionAnimatorTest",
-    "testMethodName": "backgroundAnimationWithoutFade_whenReturning[true]",
-    "deviceLocalPath": "\/data\/user\/0\/com.android.systemui.tests\/files\/platform_screenshots",
-    "result": "FAILED",
-    "videoLocation": "TransitionAnimatorTest\/backgroundAnimationWithoutFade_whenReturning_withSpring.actual.mp4"
-  }
-}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
index 7cf9327..5b32b92 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/WindowMagnificationControllerTest.java
@@ -191,7 +191,7 @@
         mWindowManager = spy(new TestableWindowManager(wm));
 
         mContext.addMockSystemService(Context.WINDOW_SERVICE, mWindowManager);
-        mSysUiState = new SysUiState(mDisplayTracker, mKosmos.getSceneContainerPlugin());
+        mSysUiState = mKosmos.getSysuiState();
         mSysUiState.addCallback(Mockito.mock(SysUiState.SysUiStateCallback.class));
         when(mSecureSettings.getIntForUser(anyString(), anyInt(), anyInt())).then(
                 returnsSecondArg());
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
index a1f59c2..1268de0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/TransitionAnimatorTest.kt
@@ -23,11 +23,14 @@
 import android.graphics.Color
 import android.graphics.PointF
 import android.graphics.drawable.GradientDrawable
+import android.platform.test.annotations.DisableFlags
+import android.platform.test.annotations.EnableFlags
 import android.platform.test.annotations.MotionTest
 import android.view.ViewGroup
 import android.widget.FrameLayout
 import androidx.test.ext.junit.rules.ActivityScenarioRule
 import androidx.test.filters.SmallTest
+import com.android.systemui.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.activity.EmptyTestActivity
 import com.android.systemui.concurrency.fakeExecutor
@@ -45,25 +48,29 @@
 import platform.test.runner.parameterized.Parameters
 import platform.test.screenshot.GoldenPathManager
 import platform.test.screenshot.PathConfig
+import platform.test.screenshot.PathElementNoContext
 
 @SmallTest
 @MotionTest
 @RunWith(ParameterizedAndroidJunit4::class)
 class TransitionAnimatorTest(
     private val fadeWindowBackgroundLayer: Boolean,
+    private val drawHole: Boolean,
     private val isLaunching: Boolean,
     private val useSpring: Boolean,
 ) : SysuiTestCase() {
     companion object {
         private const val GOLDENS_PATH = "frameworks/base/packages/SystemUI/tests/goldens"
 
-        @get:Parameters(name = "fadeBackground={0}, isLaunching={1}, useSpring={2}")
+        @get:Parameters(name = "fadeBackground={0}, drawHole={1}, isLaunching={2}, useSpring={3}")
         @JvmStatic
         val parameterValues = buildList {
             booleanArrayOf(true, false).forEach { fadeBackground ->
-                booleanArrayOf(true, false).forEach { isLaunching ->
-                    booleanArrayOf(true, false).forEach { useSpring ->
-                        add(arrayOf(fadeBackground, isLaunching, useSpring))
+                booleanArrayOf(true, false).forEach { drawHole ->
+                    booleanArrayOf(true, false).forEach { isLaunching ->
+                        booleanArrayOf(true, false).forEach { useSpring ->
+                            add(arrayOf(fadeBackground, drawHole, isLaunching, useSpring))
+                        }
                     }
                 }
             }
@@ -71,7 +78,44 @@
     }
 
     private val kosmos = Kosmos()
-    private val pathManager = GoldenPathManager(context, GOLDENS_PATH, pathConfig = PathConfig())
+    private val pathManager =
+        GoldenPathManager(
+            context,
+            GOLDENS_PATH,
+            pathConfig =
+                PathConfig(
+                    PathElementNoContext("base", isDir = true) { "animations" },
+                    PathElementNoContext("fade", isDir = false) {
+                        if (fadeWindowBackgroundLayer) {
+                            "withFade"
+                        } else {
+                            "withoutFade"
+                        }
+                    },
+                    PathElementNoContext("hole", isDir = false) {
+                        if (drawHole) {
+                            "withHole"
+                        } else {
+                            "withoutHole"
+                        }
+                    },
+                    PathElementNoContext("direction", isDir = false) {
+                        if (isLaunching) {
+                            "whenLaunching"
+                        } else {
+                            "whenReturning"
+                        }
+                    },
+                    PathElementNoContext("mode", isDir = false) {
+                        if (useSpring) {
+                            "withSpring"
+                        } else {
+                            "withAnimator"
+                        }
+                    },
+                ),
+        )
+
     private val transitionAnimator =
         TransitionAnimator(
             kosmos.fakeExecutor,
@@ -80,24 +124,6 @@
             ActivityTransitionAnimator.SPRING_TIMINGS,
             ActivityTransitionAnimator.SPRING_INTERPOLATORS,
         )
-    private val fade =
-        if (fadeWindowBackgroundLayer) {
-            "withFade"
-        } else {
-            "withoutFade"
-        }
-    private val direction =
-        if (isLaunching) {
-            "whenLaunching"
-        } else {
-            "whenReturning"
-        }
-    private val mode =
-        if (useSpring) {
-            "withSpring"
-        } else {
-            "withAnimator"
-        }
 
     @get:Rule(order = 1) val activityRule = ActivityScenarioRule(EmptyTestActivity::class.java)
     @get:Rule(order = 2) val animatorTestRule = android.animation.AnimatorTestRule(this)
@@ -108,6 +134,7 @@
             pathManager,
         )
 
+    @DisableFlags(Flags.FLAG_MOVE_TRANSITION_ANIMATION_LAYER)
     @Test
     fun backgroundAnimationTimeSeries() {
         val transitionContainer = createScene()
@@ -118,7 +145,21 @@
 
         motionRule
             .assertThat(recordedMotion)
-            .timeSeriesMatchesGolden("backgroundAnimationTimeSeries_${fade}_${direction}_$mode")
+            .timeSeriesMatchesGolden("backgroundAnimationTimeSeries")
+    }
+
+    @EnableFlags(Flags.FLAG_MOVE_TRANSITION_ANIMATION_LAYER)
+    @Test
+    fun backgroundAnimationTimeSeries_drawHoleAfterFadeout() {
+        val transitionContainer = createScene()
+        val backgroundLayer = createBackgroundLayer()
+        val animation = createAnimation(transitionContainer, backgroundLayer)
+
+        val recordedMotion = record(backgroundLayer, animation)
+
+        motionRule
+            .assertThat(recordedMotion)
+            .timeSeriesMatchesGolden("backgroundAnimationTimeSeries_drawHoleAfterFadeout")
     }
 
     private fun createScene(): ViewGroup {
@@ -169,6 +210,7 @@
                 endState,
                 backgroundLayer,
                 fadeWindowBackgroundLayer,
+                drawHole,
                 startVelocity = startVelocity,
             )
             .apply { runOnMainThreadAndWaitForIdleSync { start() } }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt
index 75a5768..c81900d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/back/FlingOnBackAnimationCallbackTest.kt
@@ -69,9 +69,11 @@
         callback.onBackProgressed(backEventOf(0.6f, 32))
         assertTrue("Assert onBackProgressedCompat called", callback.backProgressedCalled)
         assertEquals("Assert interpolated progress", 0.6f, callback.progressEvent?.progress)
-        getInstrumentation().runOnMainSync { callback.onBackInvoked() }
-        // Assert that onBackInvoked is not called immediately...
-        assertFalse(callback.backInvokedCalled)
+        getInstrumentation().runOnMainSync {
+            callback.onBackInvoked()
+            // Assert that onBackInvoked is not called immediately.
+            assertFalse(callback.backInvokedCalled)
+        }
         // Instead the fling animation is played and eventually onBackInvoked is called.
         callback.backInvokedLatch.await(1000, TimeUnit.MILLISECONDS)
         assertTrue(callback.backInvokedCalled)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
index 5249620..a1d038a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/UdfpsControllerOverlayTest.kt
@@ -120,9 +120,7 @@
     private lateinit var deviceEntryUdfpsTouchOverlayViewModel:
         DeviceEntryUdfpsTouchOverlayViewModel
     @Mock private lateinit var defaultUdfpsTouchOverlayViewModel: DefaultUdfpsTouchOverlayViewModel
-    @Mock
-    private lateinit var udfpsKeyguardAccessibilityDelegate: UdfpsKeyguardAccessibilityDelegate
-    private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
+    @Mock private lateinit var keyguardTransitionRepository: FakeKeyguardTransitionRepository
     private lateinit var keyguardTransitionInteractor: KeyguardTransitionInteractor
     @Mock private lateinit var shadeInteractor: ShadeInteractor
     @Captor private lateinit var layoutParamsCaptor: ArgumentCaptor<WindowManager.LayoutParams>
@@ -185,7 +183,6 @@
                 primaryBouncerInteractor,
                 alternateBouncerInteractor,
                 isDebuggable,
-                udfpsKeyguardAccessibilityDelegate,
                 keyguardTransitionInteractor,
                 mSelectedUserInteractor,
                 { deviceEntryUdfpsTouchOverlayViewModel },
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt
index 9ae5715..2fc81eb 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/AudioSharingDeviceItemActionInteractorTest.kt
@@ -231,6 +231,11 @@
                 actionInteractorImpl.onActionIconClick(inAudioSharingMediaDeviceItem) {}
                 assertThat(bluetoothTileDialogAudioSharingRepository.audioSharingStarted)
                     .isEqualTo(false)
+                verify(bluetoothTileDialogLogger)
+                    .logAudioSharingButtonClick(
+                        AudioSharingButtonClick.CHECK_MARK,
+                        inAudioSharingMediaDeviceItem,
+                    )
             }
         }
     }
@@ -243,6 +248,11 @@
                 actionInteractorImpl.onActionIconClick(connectedAudioSharingMediaDeviceItem) {}
                 assertThat(bluetoothTileDialogAudioSharingRepository.audioSharingStarted)
                     .isEqualTo(true)
+                verify(bluetoothTileDialogLogger)
+                    .logAudioSharingButtonClick(
+                        AudioSharingButtonClick.PLUS_BUTTON,
+                        connectedAudioSharingMediaDeviceItem,
+                    )
             }
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
index 7c8822b..96ef8b6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/bluetooth/qsdialog/DeviceItemFactoryTest.kt
@@ -18,8 +18,6 @@
 
 import android.bluetooth.BluetoothDevice
 import android.graphics.drawable.Drawable
-import android.platform.test.annotations.DisableFlags
-import android.platform.test.annotations.EnableFlags
 import android.testing.TestableLooper
 import android.util.Pair
 import androidx.test.ext.junit.runners.AndroidJUnit4
@@ -29,7 +27,6 @@
 import com.android.settingslib.bluetooth.BluetoothUtils
 import com.android.settingslib.bluetooth.CachedBluetoothDevice
 import com.android.settingslib.bluetooth.LocalBluetoothManager
-import com.android.settingslib.flags.Flags
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.res.R
 import com.google.common.truth.Truth.assertThat
@@ -208,42 +205,6 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
-    fun testSavedFactory_isFilterMatched_bondedAndNotConnected_returnsTrue() {
-        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
-        `when`(cachedDevice.isConnected).thenReturn(false)
-
-        assertThat(
-                savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false)
-            )
-            .isTrue()
-    }
-
-    @Test
-    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
-    fun testSavedFactory_isFilterMatched_connected_returnsFalse() {
-        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_BONDED)
-        `when`(cachedDevice.isConnected).thenReturn(true)
-
-        assertThat(
-                savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false)
-            )
-            .isFalse()
-    }
-
-    @Test
-    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
-    fun testSavedFactory_isFilterMatched_notBonded_returnsFalse() {
-        `when`(cachedDevice.bondState).thenReturn(BluetoothDevice.BOND_NONE)
-
-        assertThat(
-                savedDeviceItemFactory.isFilterMatched(context, cachedDevice, isOngoingCall = false)
-            )
-            .isFalse()
-    }
-
-    @Test
-    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     fun testSavedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() {
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(true)
@@ -255,7 +216,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     fun testSavedFactory_isFilterMatched_notExclusiveManaged_returnsTrue() {
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
@@ -269,7 +229,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     fun testSavedFactory_isFilterMatched_notExclusivelyManaged_connected_returnsFalse() {
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
@@ -283,35 +242,6 @@
     }
 
     @Test
-    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
-    fun testConnectedFactory_isFilterMatched_bondedAndConnected_returnsTrue() {
-        `when`(BluetoothUtils.isConnectedBluetoothDevice(any(), any())).thenReturn(true)
-
-        assertThat(
-                connectedDeviceItemFactory.isFilterMatched(
-                    context,
-                    cachedDevice,
-                    isOngoingCall = false,
-                )
-            )
-            .isTrue()
-    }
-
-    @Test
-    @DisableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
-    fun testConnectedFactory_isFilterMatched_notConnected_returnsFalse() {
-        assertThat(
-                connectedDeviceItemFactory.isFilterMatched(
-                    context,
-                    cachedDevice,
-                    isOngoingCall = false,
-                )
-            )
-            .isFalse()
-    }
-
-    @Test
-    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     fun testConnectedFactory_isFilterMatched_exclusivelyManaged_returnsFalse() {
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(true)
@@ -327,7 +257,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     fun testConnectedFactory_isFilterMatched_noExclusiveManager_returnsTrue() {
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
@@ -344,7 +273,6 @@
     }
 
     @Test
-    @EnableFlags(Flags.FLAG_ENABLE_HIDE_EXCLUSIVELY_MANAGED_BLUETOOTH_DEVICE)
     fun testConnectedFactory_isFilterMatched_notExclusivelyManaged_notConnected_returnsFalse() {
         `when`(cachedDevice.device).thenReturn(bluetoothDevice)
         `when`(BluetoothUtils.isExclusivelyManagedBluetoothDevice(any(), any())).thenReturn(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
index 5624815..5c893da 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/clipboardoverlay/ClipboardOverlayControllerTest.java
@@ -28,7 +28,6 @@
 import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_EXPANDED;
 import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SHOWN_MINIMIZED;
 import static com.android.systemui.clipboardoverlay.ClipboardOverlayEvent.CLIPBOARD_OVERLAY_SWIPE_DISMISSED;
-import static com.android.systemui.flags.Flags.CLIPBOARD_IMAGE_TIMEOUT;
 
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -60,7 +59,6 @@
 import com.android.internal.logging.UiEventLogger;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.broadcast.BroadcastSender;
-import com.android.systemui.flags.FakeFeatureFlags;
 import com.android.systemui.screenshot.TimeoutHandler;
 import com.android.systemui.settings.FakeDisplayTracker;
 import com.android.systemui.util.concurrency.FakeExecutor;
@@ -102,7 +100,6 @@
     @Mock
     private UiEventLogger mUiEventLogger;
     private FakeDisplayTracker mDisplayTracker = new FakeDisplayTracker(mContext);
-    private FakeFeatureFlags mFeatureFlags = new FakeFeatureFlags();
 
     @Mock
     private Animator mAnimator;
@@ -152,8 +149,6 @@
 
         mSampleClipData = new ClipData("Test", new String[]{"text/plain"},
                 new ClipData.Item("Test Item"));
-
-        mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, true); // turned off for legacy tests
     }
 
     /**
@@ -170,13 +165,13 @@
                 getFakeBroadcastDispatcher(),
                 mBroadcastSender,
                 mTimeoutHandler,
-                mFeatureFlags,
                 mClipboardUtils,
                 mExecutor,
                 mClipboardImageLoader,
                 mClipboardTransitionExecutor,
                 mClipboardIndicationProvider,
-                mUiEventLogger);
+                mUiEventLogger,
+                new ActionIntentCreator());
         verify(mClipboardOverlayView).setCallbacks(mOverlayCallbacksCaptor.capture());
         mCallbacks = mOverlayCallbacksCaptor.getValue();
     }
@@ -193,7 +188,6 @@
 
         ClipData clipData = new ClipData("", new String[]{"image/png"},
                 new ClipData.Item(Uri.parse("")));
-        mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
 
         mOverlayController.setClipData(clipData, "");
 
@@ -208,7 +202,6 @@
 
         ClipData clipData = new ClipData("", new String[]{"resource/png"},
                 new ClipData.Item(Uri.parse("")));
-        mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
 
         mOverlayController.setClipData(clipData, "");
 
@@ -219,7 +212,6 @@
 
     @Test
     public void test_setClipData_textData_legacy() {
-        mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
         initController();
 
         mOverlayController.setClipData(mSampleClipData, "abc");
@@ -232,7 +224,6 @@
 
     @Test
     public void test_setClipData_sensitiveTextData_legacy() {
-        mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
         initController();
 
         ClipDescription description = mSampleClipData.getDescription();
@@ -250,7 +241,6 @@
     @Test
     public void test_setClipData_repeatedCalls_legacy() {
         when(mAnimator.isRunning()).thenReturn(true);
-        mFeatureFlags.set(CLIPBOARD_IMAGE_TIMEOUT, false);
         initController();
 
         mOverlayController.setClipData(mSampleClipData, "");
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt
index 2001a3e..dad08e0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaCarouselControllerTest.kt
@@ -422,25 +422,6 @@
         assertTrue(MediaPlayerData.playerKeys().elementAt(2).isSsMediaRec)
     }
 
-    @DisableSceneContainer
-    @Test
-    fun testOrderWithSmartspace_prioritized_updatingVisibleMediaPlayers() {
-        verify(mediaDataManager).addListener(capture(listener))
-
-        testPlayerOrdering()
-
-        // If smartspace is prioritized
-        listener.value.onSmartspaceMediaDataLoaded(
-            SMARTSPACE_KEY,
-            EMPTY_SMARTSPACE_MEDIA_DATA.copy(isActive = true),
-            true,
-        )
-
-        // Then it should be shown immediately after any actively playing controls
-        assertTrue(MediaPlayerData.playerKeys().elementAt(2).isSsMediaRec)
-        assertTrue(MediaPlayerData.visiblePlayerKeys().elementAt(2).isSsMediaRec)
-    }
-
     @Test
     fun testOrderWithSmartspace_notPrioritized() {
         testPlayerOrdering()
@@ -571,146 +552,6 @@
         verify(logger).logRecommendationRemoved(eq(packageName), eq(instanceId!!))
     }
 
-    @DisableSceneContainer
-    @Test
-    fun testMediaLoaded_ScrollToActivePlayer() {
-        verify(mediaDataManager).addListener(capture(listener))
-
-        listener.value.onMediaDataLoaded(
-            PLAYING_LOCAL,
-            null,
-            DATA.copy(
-                active = true,
-                isPlaying = true,
-                playbackLocation = MediaData.PLAYBACK_LOCAL,
-                resumption = false,
-            ),
-        )
-        listener.value.onMediaDataLoaded(
-            PAUSED_LOCAL,
-            null,
-            DATA.copy(
-                active = true,
-                isPlaying = false,
-                playbackLocation = MediaData.PLAYBACK_LOCAL,
-                resumption = false,
-            ),
-        )
-        runAllReady()
-        // adding a media recommendation card.
-        listener.value.onSmartspaceMediaDataLoaded(
-            SMARTSPACE_KEY,
-            EMPTY_SMARTSPACE_MEDIA_DATA,
-            false,
-        )
-        mediaCarouselController.shouldScrollToKey = true
-        // switching between media players.
-        listener.value.onMediaDataLoaded(
-            PLAYING_LOCAL,
-            PLAYING_LOCAL,
-            DATA.copy(
-                active = true,
-                isPlaying = false,
-                playbackLocation = MediaData.PLAYBACK_LOCAL,
-                resumption = true,
-            ),
-        )
-        listener.value.onMediaDataLoaded(
-            PAUSED_LOCAL,
-            PAUSED_LOCAL,
-            DATA.copy(
-                active = true,
-                isPlaying = true,
-                playbackLocation = MediaData.PLAYBACK_LOCAL,
-                resumption = false,
-            ),
-        )
-        runAllReady()
-
-        assertEquals(
-            MediaPlayerData.getMediaPlayerIndex(PAUSED_LOCAL),
-            mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex,
-        )
-    }
-
-    @DisableSceneContainer
-    @Test
-    fun testMediaLoadedFromRecommendationCard_ScrollToActivePlayer() {
-        verify(mediaDataManager).addListener(capture(listener))
-
-        listener.value.onSmartspaceMediaDataLoaded(
-            SMARTSPACE_KEY,
-            EMPTY_SMARTSPACE_MEDIA_DATA.copy(packageName = "PACKAGE_NAME", isActive = true),
-            false,
-        )
-        listener.value.onMediaDataLoaded(
-            PLAYING_LOCAL,
-            null,
-            DATA.copy(
-                active = true,
-                isPlaying = true,
-                playbackLocation = MediaData.PLAYBACK_LOCAL,
-                resumption = false,
-            ),
-        )
-        runAllReady()
-
-        var playerIndex = MediaPlayerData.getMediaPlayerIndex(PLAYING_LOCAL)
-        assertEquals(
-            playerIndex,
-            mediaCarouselController.mediaCarouselScrollHandler.visibleMediaIndex,
-        )
-        assertEquals(playerIndex, 0)
-
-        // Replaying the same media player one more time.
-        // And check that the card stays in its position.
-        mediaCarouselController.shouldScrollToKey = true
-        listener.value.onMediaDataLoaded(
-            PLAYING_LOCAL,
-            null,
-            DATA.copy(
-                active = true,
-                isPlaying = true,
-                playbackLocation = MediaData.PLAYBACK_LOCAL,
-                resumption = false,
-                packageName = "PACKAGE_NAME",
-            ),
-        )
-        runAllReady()
-        playerIndex = MediaPlayerData.getMediaPlayerIndex(PLAYING_LOCAL)
-        assertEquals(playerIndex, 0)
-    }
-
-    @DisableSceneContainer
-    @Test
-    fun testRecommendationRemovedWhileNotVisible_updateHostVisibility() {
-        verify(mediaDataManager).addListener(capture(listener))
-
-        var result = false
-        mediaCarouselController.updateHostVisibility = { result = true }
-
-        whenever(visualStabilityProvider.isReorderingAllowed).thenReturn(true)
-        listener.value.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY, false)
-
-        assertEquals(true, result)
-    }
-
-    @DisableSceneContainer
-    @Test
-    fun testRecommendationRemovedWhileVisible_thenReorders_updateHostVisibility() {
-        verify(mediaDataManager).addListener(capture(listener))
-
-        var result = false
-        mediaCarouselController.updateHostVisibility = { result = true }
-
-        whenever(visualStabilityProvider.isReorderingAllowed).thenReturn(false)
-        listener.value.onSmartspaceMediaDataRemoved(SMARTSPACE_KEY, false)
-        assertEquals(false, result)
-
-        visualStabilityCallback.value.onReorderingAllowed()
-        assertEquals(true, result)
-    }
-
     @Test
     fun testGetCurrentVisibleMediaContentIntent() {
         val clickIntent1 = mock(PendingIntent::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
index 9543032..88fcc70 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaControlPanelTest.kt
@@ -19,16 +19,12 @@
 import android.animation.Animator
 import android.animation.AnimatorSet
 import android.app.PendingIntent
-import android.app.smartspace.SmartspaceAction
-import android.content.Context
 import android.content.Intent
 import android.content.pm.ApplicationInfo
 import android.content.pm.PackageManager
-import android.content.res.Configuration
 import android.graphics.Bitmap
 import android.graphics.Canvas
 import android.graphics.Color
-import android.graphics.Matrix
 import android.graphics.drawable.Animatable2
 import android.graphics.drawable.AnimatedVectorDrawable
 import android.graphics.drawable.Drawable
@@ -47,7 +43,6 @@
 import android.provider.Settings
 import android.provider.Settings.ACTION_MEDIA_CONTROLS_SETTINGS
 import android.testing.TestableLooper
-import android.util.TypedValue
 import android.view.View
 import android.view.ViewGroup
 import android.view.animation.Interpolator
@@ -59,7 +54,6 @@
 import androidx.constraintlayout.widget.Barrier
 import androidx.constraintlayout.widget.ConstraintSet
 import androidx.lifecycle.LiveData
-import androidx.media.utils.MediaConstants
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.InstanceId
@@ -72,19 +66,15 @@
 import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor
 import com.android.systemui.flags.DisableSceneContainer
 import com.android.systemui.media.controls.MediaTestUtils
-import com.android.systemui.media.controls.domain.pipeline.EMPTY_SMARTSPACE_MEDIA_DATA
 import com.android.systemui.media.controls.domain.pipeline.MediaDataManager
-import com.android.systemui.media.controls.shared.model.KEY_SMARTSPACE_APP_NAME
 import com.android.systemui.media.controls.shared.model.MediaAction
 import com.android.systemui.media.controls.shared.model.MediaButton
 import com.android.systemui.media.controls.shared.model.MediaData
 import com.android.systemui.media.controls.shared.model.MediaDeviceData
 import com.android.systemui.media.controls.shared.model.MediaNotificationAction
-import com.android.systemui.media.controls.shared.model.SmartspaceMediaData
 import com.android.systemui.media.controls.ui.binder.SeekBarObserver
 import com.android.systemui.media.controls.ui.view.GutsViewHolder
 import com.android.systemui.media.controls.ui.view.MediaViewHolder
-import com.android.systemui.media.controls.ui.view.RecommendationViewHolder
 import com.android.systemui.media.controls.ui.viewmodel.SeekBarViewModel
 import com.android.systemui.media.controls.util.MediaUiEventLogger
 import com.android.systemui.media.dialog.MediaOutputDialogManager
@@ -216,32 +206,9 @@
 
     @Mock private lateinit var communalSceneInteractor: CommunalSceneInteractor
 
-    @Mock private lateinit var recommendationViewHolder: RecommendationViewHolder
-    @Mock private lateinit var smartspaceAction: SmartspaceAction
-    private lateinit var smartspaceData: SmartspaceMediaData
-    @Mock private lateinit var coverContainer1: ViewGroup
-    @Mock private lateinit var coverContainer2: ViewGroup
-    @Mock private lateinit var coverContainer3: ViewGroup
-    @Mock private lateinit var recAppIconItem: CachingIconView
-    @Mock private lateinit var recCardTitle: TextView
-    @Mock private lateinit var coverItem: ImageView
-    @Mock private lateinit var matrix: Matrix
-    private lateinit var recTitle1: TextView
-    private lateinit var recTitle2: TextView
-    private lateinit var recTitle3: TextView
-    private lateinit var recSubtitle1: TextView
-    private lateinit var recSubtitle2: TextView
-    private lateinit var recSubtitle3: TextView
-    @Mock private lateinit var recProgressBar1: SeekBar
-    @Mock private lateinit var recProgressBar2: SeekBar
-    @Mock private lateinit var recProgressBar3: SeekBar
     @Mock private lateinit var globalSettings: GlobalSettings
 
-    private val intent =
-        Intent().apply {
-            putExtras(Bundle().also { it.putString(KEY_SMARTSPACE_APP_NAME, REC_APP_NAME) })
-            setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-        }
+    private val intent = Intent().apply { setFlags(Intent.FLAG_ACTIVITY_NEW_TASK) }
     private val pendingIntent =
         PendingIntent.getActivity(
             mContext,
@@ -282,7 +249,6 @@
                     mediaOutputDialogManager,
                     mediaCarouselController,
                     falsingManager,
-                    clock,
                     logger,
                     keyguardStateController,
                     activityIntentHelper,
@@ -304,27 +270,6 @@
         initMediaViewHolderMocks()
 
         initDeviceMediaData(false, DEVICE_NAME)
-
-        // Set up recommendation view
-        initRecommendationViewHolderMocks()
-
-        // Set valid recommendation data
-        val extras = Bundle()
-        extras.putString(KEY_SMARTSPACE_APP_NAME, REC_APP_NAME)
-        val intent =
-            Intent().apply {
-                putExtras(extras)
-                setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
-            }
-        whenever(smartspaceAction.intent).thenReturn(intent)
-        whenever(smartspaceAction.extras).thenReturn(extras)
-        smartspaceData =
-            EMPTY_SMARTSPACE_MEDIA_DATA.copy(
-                packageName = PACKAGE,
-                instanceId = instanceId,
-                recommendations = listOf(smartspaceAction, smartspaceAction, smartspaceAction),
-                cardAction = smartspaceAction,
-            )
     }
 
     private fun initGutsViewHolderMocks() {
@@ -471,49 +416,6 @@
         whenever(viewHolder.loadingEffectView).thenReturn(loadingEffectView)
     }
 
-    /** Initialize elements for the recommendation view holder */
-    private fun initRecommendationViewHolderMocks() {
-        recTitle1 = TextView(context)
-        recTitle2 = TextView(context)
-        recTitle3 = TextView(context)
-        recSubtitle1 = TextView(context)
-        recSubtitle2 = TextView(context)
-        recSubtitle3 = TextView(context)
-
-        whenever(recommendationViewHolder.recommendations).thenReturn(view)
-        whenever(recommendationViewHolder.mediaAppIcons)
-            .thenReturn(listOf(recAppIconItem, recAppIconItem, recAppIconItem))
-        whenever(recommendationViewHolder.cardTitle).thenReturn(recCardTitle)
-        whenever(recommendationViewHolder.mediaCoverItems)
-            .thenReturn(listOf(coverItem, coverItem, coverItem))
-        whenever(recommendationViewHolder.mediaCoverContainers)
-            .thenReturn(listOf(coverContainer1, coverContainer2, coverContainer3))
-        whenever(recommendationViewHolder.mediaTitles)
-            .thenReturn(listOf(recTitle1, recTitle2, recTitle3))
-        whenever(recommendationViewHolder.mediaSubtitles)
-            .thenReturn(listOf(recSubtitle1, recSubtitle2, recSubtitle3))
-        whenever(recommendationViewHolder.mediaProgressBars)
-            .thenReturn(listOf(recProgressBar1, recProgressBar2, recProgressBar3))
-        whenever(coverItem.imageMatrix).thenReturn(matrix)
-
-        // set ids for recommendation containers
-        whenever(coverContainer1.id).thenReturn(1)
-        whenever(coverContainer2.id).thenReturn(2)
-        whenever(coverContainer3.id).thenReturn(3)
-
-        whenever(recommendationViewHolder.gutsViewHolder).thenReturn(gutsViewHolder)
-
-        val actionIcon = Icon.createWithResource(context, R.drawable.ic_android)
-        whenever(smartspaceAction.icon).thenReturn(actionIcon)
-
-        // Needed for card and item action click
-        val mockContext = mock(Context::class.java)
-        whenever(view.context).thenReturn(mockContext)
-        whenever(coverContainer1.context).thenReturn(mockContext)
-        whenever(coverContainer2.context).thenReturn(mockContext)
-        whenever(coverContainer3.context).thenReturn(mockContext)
-    }
-
     @After
     fun tearDown() {
         session.release()
@@ -1488,169 +1390,6 @@
 
     /* ***** END guts tests for the player ***** */
 
-    /* ***** Guts tests for the recommendations ***** */
-
-    @Test
-    fun recommendations_longClick_isFalse() {
-        whenever(falsingManager.isFalseLongTap(FalsingManager.LOW_PENALTY)).thenReturn(true)
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData)
-
-        val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
-        verify(viewHolder.player).onLongClickListener = captor.capture()
-
-        captor.value.onLongClick(viewHolder.player)
-        verify(mediaViewController, never()).openGuts()
-        verify(mediaViewController, never()).closeGuts()
-    }
-
-    @Test
-    fun recommendations_longClickWhenGutsClosed_gutsOpens() {
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData)
-        whenever(mediaViewController.isGutsVisible).thenReturn(false)
-
-        val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
-        verify(viewHolder.player).onLongClickListener = captor.capture()
-
-        captor.value.onLongClick(viewHolder.player)
-        verify(mediaViewController).openGuts()
-        verify(logger).logLongPressOpen(anyInt(), eq(PACKAGE), eq(instanceId))
-    }
-
-    @Test
-    fun recommendations_longClickWhenGutsOpen_gutsCloses() {
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData)
-        whenever(mediaViewController.isGutsVisible).thenReturn(true)
-
-        val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
-        verify(viewHolder.player).onLongClickListener = captor.capture()
-
-        captor.value.onLongClick(viewHolder.player)
-        verify(mediaViewController, never()).openGuts()
-        verify(mediaViewController).closeGuts(false)
-    }
-
-    @Test
-    fun recommendations_cancelButtonClick_animation() {
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData)
-
-        cancel.callOnClick()
-
-        verify(mediaViewController).closeGuts(false)
-    }
-
-    @Test
-    fun recommendations_settingsButtonClick() {
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData)
-
-        settings.callOnClick()
-        verify(logger).logLongPressSettings(anyInt(), eq(PACKAGE), eq(instanceId))
-
-        val captor = ArgumentCaptor.forClass(Intent::class.java)
-        verify(activityStarter).startActivity(captor.capture(), eq(true))
-
-        assertThat(captor.value.action).isEqualTo(ACTION_MEDIA_CONTROLS_SETTINGS)
-    }
-
-    @Test
-    fun recommendations_dismissButtonClick() {
-        val mediaKey = "key for dismissal"
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData.copy(targetId = mediaKey))
-
-        assertThat(dismiss.isEnabled).isEqualTo(true)
-        dismiss.callOnClick()
-        verify(logger).logLongPressDismiss(anyInt(), eq(PACKAGE), eq(instanceId))
-        verify(mediaDataManager).dismissSmartspaceRecommendation(eq(mediaKey), anyLong())
-    }
-
-    @Test
-    fun recommendation_gutsOpen_contentDescriptionIsForGuts() {
-        whenever(mediaViewController.isGutsVisible).thenReturn(true)
-        player.attachRecommendation(recommendationViewHolder)
-
-        val gutsTextString = "gutsText"
-        whenever(gutsText.text).thenReturn(gutsTextString)
-        player.bindRecommendation(smartspaceData)
-
-        val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
-        verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
-        val description = descriptionCaptor.value.toString()
-
-        assertThat(description).isEqualTo(gutsTextString)
-    }
-
-    @Test
-    fun recommendation_gutsClosed_contentDescriptionIsForPlayer() {
-        whenever(mediaViewController.isGutsVisible).thenReturn(false)
-        player.attachRecommendation(recommendationViewHolder)
-
-        player.bindRecommendation(smartspaceData)
-
-        val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
-        verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
-        val description = descriptionCaptor.value.toString()
-
-        assertThat(description)
-            .isEqualTo(context.getString(R.string.controls_media_smartspace_rec_header))
-    }
-
-    @Test
-    fun recommendation_gutsChangesFromOpenToClosed_contentDescriptionUpdated() {
-        // Start out open
-        whenever(mediaViewController.isGutsVisible).thenReturn(true)
-        whenever(gutsText.text).thenReturn("gutsText")
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData)
-
-        // Update to closed by long pressing
-        val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
-        verify(viewHolder.player).onLongClickListener = captor.capture()
-        reset(viewHolder.player)
-
-        whenever(mediaViewController.isGutsVisible).thenReturn(false)
-        captor.value.onLongClick(viewHolder.player)
-
-        // Then content description is now the player content description
-        val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
-        verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
-        val description = descriptionCaptor.value.toString()
-
-        assertThat(description)
-            .isEqualTo(context.getString(R.string.controls_media_smartspace_rec_header))
-    }
-
-    @Test
-    fun recommendation_gutsChangesFromClosedToOpen_contentDescriptionUpdated() {
-        // Start out closed
-        whenever(mediaViewController.isGutsVisible).thenReturn(false)
-        val gutsTextString = "gutsText"
-        whenever(gutsText.text).thenReturn(gutsTextString)
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData)
-
-        // Update to open by long pressing
-        val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
-        verify(viewHolder.player).onLongClickListener = captor.capture()
-        reset(viewHolder.player)
-
-        whenever(mediaViewController.isGutsVisible).thenReturn(true)
-        captor.value.onLongClick(viewHolder.player)
-
-        // Then content description is now the guts content description
-        val descriptionCaptor = ArgumentCaptor.forClass(CharSequence::class.java)
-        verify(viewHolder.player).contentDescription = descriptionCaptor.capture()
-        val description = descriptionCaptor.value.toString()
-
-        assertThat(description).isEqualTo(gutsTextString)
-    }
-
-    /* ***** END guts tests for the recommendations ***** */
-
     @Test
     fun actionPlayPauseClick_isLogged() {
         val semanticActions =
@@ -1887,578 +1626,6 @@
     }
 
     @Test
-    fun recommendation_gutsClosed_longPressOpens() {
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData)
-        whenever(mediaViewController.isGutsVisible).thenReturn(false)
-
-        val captor = ArgumentCaptor.forClass(View.OnLongClickListener::class.java)
-        verify(recommendationViewHolder.recommendations).setOnLongClickListener(captor.capture())
-
-        captor.value.onLongClick(recommendationViewHolder.recommendations)
-        verify(mediaViewController).openGuts()
-        verify(logger).logLongPressOpen(anyInt(), eq(PACKAGE), eq(instanceId))
-    }
-
-    @Test
-    fun recommendation_settingsButtonClick_isLogged() {
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData)
-
-        settings.callOnClick()
-        verify(logger).logLongPressSettings(anyInt(), eq(PACKAGE), eq(instanceId))
-
-        val captor = ArgumentCaptor.forClass(Intent::class.java)
-        verify(activityStarter).startActivity(captor.capture(), eq(true))
-
-        assertThat(captor.value.action).isEqualTo(ACTION_MEDIA_CONTROLS_SETTINGS)
-    }
-
-    @Test
-    fun recommendation_dismissButton_isLogged() {
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData)
-
-        dismiss.callOnClick()
-        verify(logger).logLongPressDismiss(anyInt(), eq(PACKAGE), eq(instanceId))
-    }
-
-    @Test
-    fun recommendation_tapOnCard_isLogged() {
-        val captor = ArgumentCaptor.forClass(View.OnClickListener::class.java)
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData)
-
-        verify(recommendationViewHolder.recommendations).setOnClickListener(captor.capture())
-        captor.value.onClick(recommendationViewHolder.recommendations)
-
-        verify(logger).logRecommendationCardTap(eq(PACKAGE), eq(instanceId))
-    }
-
-    @Test
-    fun recommendation_tapOnItem_isLogged() {
-        val captor = ArgumentCaptor.forClass(View.OnClickListener::class.java)
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(smartspaceData)
-
-        verify(coverContainer1).setOnClickListener(captor.capture())
-        captor.value.onClick(recommendationViewHolder.recommendations)
-
-        verify(logger).logRecommendationItemTap(eq(PACKAGE), eq(instanceId), eq(0))
-    }
-
-    @Test
-    fun bindRecommendation_listHasTooFewRecs_notDisplayed() {
-        player.attachRecommendation(recommendationViewHolder)
-        val icon =
-            Icon.createWithResource(context, com.android.settingslib.R.drawable.ic_1x_mobiledata)
-        val data =
-            smartspaceData.copy(
-                recommendations =
-                    listOf(
-                        SmartspaceAction.Builder("id1", "title1")
-                            .setSubtitle("subtitle1")
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id2", "title2")
-                            .setSubtitle("subtitle2")
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                    )
-            )
-
-        player.bindRecommendation(data)
-
-        assertThat(recTitle1.text).isEqualTo("")
-        verify(mediaViewController, never()).refreshState()
-    }
-
-    @Test
-    fun bindRecommendation_listHasTooFewRecsWithIcons_notDisplayed() {
-        player.attachRecommendation(recommendationViewHolder)
-        val icon =
-            Icon.createWithResource(context, com.android.settingslib.R.drawable.ic_1x_mobiledata)
-        val data =
-            smartspaceData.copy(
-                recommendations =
-                    listOf(
-                        SmartspaceAction.Builder("id1", "title1")
-                            .setSubtitle("subtitle1")
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id2", "title2")
-                            .setSubtitle("subtitle2")
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id2", "empty icon 1")
-                            .setSubtitle("subtitle2")
-                            .setIcon(null)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id2", "empty icon 2")
-                            .setSubtitle("subtitle2")
-                            .setIcon(null)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                    )
-            )
-
-        player.bindRecommendation(data)
-
-        assertThat(recTitle1.text).isEqualTo("")
-        verify(mediaViewController, never()).refreshState()
-    }
-
-    @Test
-    fun bindRecommendation_hasTitlesAndSubtitles() {
-        player.attachRecommendation(recommendationViewHolder)
-
-        val title1 = "Title1"
-        val title2 = "Title2"
-        val title3 = "Title3"
-        val subtitle1 = "Subtitle1"
-        val subtitle2 = "Subtitle2"
-        val subtitle3 = "Subtitle3"
-        val icon =
-            Icon.createWithResource(context, com.android.settingslib.R.drawable.ic_1x_mobiledata)
-
-        val data =
-            smartspaceData.copy(
-                recommendations =
-                    listOf(
-                        SmartspaceAction.Builder("id1", title1)
-                            .setSubtitle(subtitle1)
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id2", title2)
-                            .setSubtitle(subtitle2)
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id3", title3)
-                            .setSubtitle(subtitle3)
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                    )
-            )
-        player.bindRecommendation(data)
-
-        assertThat(recTitle1.text).isEqualTo(title1)
-        assertThat(recTitle2.text).isEqualTo(title2)
-        assertThat(recTitle3.text).isEqualTo(title3)
-        assertThat(recSubtitle1.text).isEqualTo(subtitle1)
-        assertThat(recSubtitle2.text).isEqualTo(subtitle2)
-        assertThat(recSubtitle3.text).isEqualTo(subtitle3)
-    }
-
-    @Test
-    fun bindRecommendation_noTitle_subtitleNotShown() {
-        player.attachRecommendation(recommendationViewHolder)
-
-        val data =
-            smartspaceData.copy(
-                recommendations =
-                    listOf(
-                        SmartspaceAction.Builder("id1", "")
-                            .setSubtitle("fake subtitle")
-                            .setIcon(
-                                Icon.createWithResource(
-                                    context,
-                                    com.android.settingslib.R.drawable.ic_1x_mobiledata,
-                                )
-                            )
-                            .setExtras(Bundle.EMPTY)
-                            .build()
-                    )
-            )
-        player.bindRecommendation(data)
-
-        assertThat(recSubtitle1.text).isEqualTo("")
-    }
-
-    @Test
-    fun bindRecommendation_someHaveTitles_allTitleViewsShown() {
-        useRealConstraintSets()
-        player.attachRecommendation(recommendationViewHolder)
-
-        val icon =
-            Icon.createWithResource(context, com.android.settingslib.R.drawable.ic_1x_mobiledata)
-        val data =
-            smartspaceData.copy(
-                recommendations =
-                    listOf(
-                        SmartspaceAction.Builder("id1", "")
-                            .setSubtitle("fake subtitle")
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id2", "title2")
-                            .setSubtitle("fake subtitle")
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id3", "")
-                            .setSubtitle("fake subtitle")
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                    )
-            )
-        player.bindRecommendation(data)
-
-        assertThat(expandedSet.getVisibility(recTitle1.id)).isEqualTo(ConstraintSet.VISIBLE)
-        assertThat(expandedSet.getVisibility(recTitle2.id)).isEqualTo(ConstraintSet.VISIBLE)
-        assertThat(expandedSet.getVisibility(recTitle3.id)).isEqualTo(ConstraintSet.VISIBLE)
-    }
-
-    @Test
-    fun bindRecommendation_someHaveSubtitles_allSubtitleViewsShown() {
-        useRealConstraintSets()
-        player.attachRecommendation(recommendationViewHolder)
-
-        val icon =
-            Icon.createWithResource(context, com.android.settingslib.R.drawable.ic_1x_mobiledata)
-        val data =
-            smartspaceData.copy(
-                recommendations =
-                    listOf(
-                        SmartspaceAction.Builder("id1", "")
-                            .setSubtitle("")
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id2", "title2")
-                            .setSubtitle("subtitle2")
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id3", "title3")
-                            .setSubtitle("")
-                            .setIcon(icon)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                    )
-            )
-        player.bindRecommendation(data)
-
-        assertThat(expandedSet.getVisibility(recSubtitle1.id)).isEqualTo(ConstraintSet.VISIBLE)
-        assertThat(expandedSet.getVisibility(recSubtitle2.id)).isEqualTo(ConstraintSet.VISIBLE)
-        assertThat(expandedSet.getVisibility(recSubtitle3.id)).isEqualTo(ConstraintSet.VISIBLE)
-    }
-
-    @Test
-    fun bindRecommendation_noneHaveSubtitles_subtitleViewsGone() {
-        useRealConstraintSets()
-        player.attachRecommendation(recommendationViewHolder)
-        val data =
-            smartspaceData.copy(
-                recommendations =
-                    listOf(
-                        SmartspaceAction.Builder("id1", "title1")
-                            .setSubtitle("")
-                            .setIcon(
-                                Icon.createWithResource(
-                                    context,
-                                    com.android.settingslib.R.drawable.ic_1x_mobiledata,
-                                )
-                            )
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id2", "title2")
-                            .setSubtitle("")
-                            .setIcon(Icon.createWithResource(context, R.drawable.ic_alarm))
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id3", "title3")
-                            .setSubtitle("")
-                            .setIcon(
-                                Icon.createWithResource(
-                                    context,
-                                    com.android.settingslib.R.drawable.ic_3g_mobiledata,
-                                )
-                            )
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                    )
-            )
-
-        player.bindRecommendation(data)
-
-        assertThat(expandedSet.getVisibility(recSubtitle1.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(expandedSet.getVisibility(recSubtitle2.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(expandedSet.getVisibility(recSubtitle3.id)).isEqualTo(ConstraintSet.GONE)
-    }
-
-    @Test
-    fun bindRecommendation_noneHaveTitles_titleAndSubtitleViewsGone() {
-        useRealConstraintSets()
-        player.attachRecommendation(recommendationViewHolder)
-        val data =
-            smartspaceData.copy(
-                recommendations =
-                    listOf(
-                        SmartspaceAction.Builder("id1", "")
-                            .setSubtitle("subtitle1")
-                            .setIcon(
-                                Icon.createWithResource(
-                                    context,
-                                    com.android.settingslib.R.drawable.ic_1x_mobiledata,
-                                )
-                            )
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id2", "")
-                            .setSubtitle("subtitle2")
-                            .setIcon(Icon.createWithResource(context, R.drawable.ic_alarm))
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id3", "")
-                            .setSubtitle("subtitle3")
-                            .setIcon(
-                                Icon.createWithResource(
-                                    context,
-                                    com.android.settingslib.R.drawable.ic_3g_mobiledata,
-                                )
-                            )
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                    )
-            )
-
-        player.bindRecommendation(data)
-
-        assertThat(expandedSet.getVisibility(recTitle1.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(expandedSet.getVisibility(recTitle2.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(expandedSet.getVisibility(recTitle3.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(expandedSet.getVisibility(recSubtitle1.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(expandedSet.getVisibility(recSubtitle2.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(expandedSet.getVisibility(recSubtitle3.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(collapsedSet.getVisibility(recTitle1.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(collapsedSet.getVisibility(recTitle2.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(collapsedSet.getVisibility(recTitle3.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(collapsedSet.getVisibility(recSubtitle1.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(collapsedSet.getVisibility(recSubtitle2.id)).isEqualTo(ConstraintSet.GONE)
-        assertThat(collapsedSet.getVisibility(recSubtitle3.id)).isEqualTo(ConstraintSet.GONE)
-    }
-
-    @Test
-    fun bindRecommendation_setAfterExecutors() {
-        val albumArt = getColorIcon(Color.RED)
-        val data =
-            smartspaceData.copy(
-                recommendations =
-                    listOf(
-                        SmartspaceAction.Builder("id1", "title1")
-                            .setSubtitle("subtitle1")
-                            .setIcon(albumArt)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id2", "title2")
-                            .setSubtitle("subtitle1")
-                            .setIcon(albumArt)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id3", "title3")
-                            .setSubtitle("subtitle1")
-                            .setIcon(albumArt)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                    )
-            )
-
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(data)
-        bgExecutor.runAllReady()
-        mainExecutor.runAllReady()
-
-        verify(recCardTitle).setTextColor(any<Int>())
-        verify(recAppIconItem, times(3)).setImageDrawable(any<Drawable>())
-        verify(coverItem, times(3)).setImageDrawable(any<Drawable>())
-        verify(coverItem, times(3)).imageMatrix = any()
-    }
-
-    @Test
-    fun bindRecommendationWithProgressBars() {
-        useRealConstraintSets()
-        val albumArt = getColorIcon(Color.RED)
-        val bundle =
-            Bundle().apply {
-                putInt(
-                    MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_STATUS,
-                    MediaConstants.DESCRIPTION_EXTRAS_VALUE_COMPLETION_STATUS_PARTIALLY_PLAYED,
-                )
-                putDouble(MediaConstants.DESCRIPTION_EXTRAS_KEY_COMPLETION_PERCENTAGE, 0.5)
-            }
-        val data =
-            smartspaceData.copy(
-                recommendations =
-                    listOf(
-                        SmartspaceAction.Builder("id1", "title1")
-                            .setSubtitle("subtitle1")
-                            .setIcon(albumArt)
-                            .setExtras(bundle)
-                            .build(),
-                        SmartspaceAction.Builder("id2", "title2")
-                            .setSubtitle("subtitle1")
-                            .setIcon(albumArt)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id3", "title3")
-                            .setSubtitle("subtitle1")
-                            .setIcon(albumArt)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                    )
-            )
-
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(data)
-
-        verify(recProgressBar1).setProgress(50)
-        verify(recProgressBar1).visibility = View.VISIBLE
-        verify(recProgressBar2).visibility = View.GONE
-        verify(recProgressBar3).visibility = View.GONE
-        assertThat(recSubtitle1.visibility).isEqualTo(View.GONE)
-        assertThat(recSubtitle2.visibility).isEqualTo(View.VISIBLE)
-        assertThat(recSubtitle3.visibility).isEqualTo(View.VISIBLE)
-    }
-
-    @Test
-    fun bindRecommendation_carouselNotFitThreeRecs_OrientationPortrait() {
-        useRealConstraintSets()
-        val albumArt = getColorIcon(Color.RED)
-        val data =
-            smartspaceData.copy(
-                recommendations =
-                    listOf(
-                        SmartspaceAction.Builder("id1", "title1")
-                            .setSubtitle("subtitle1")
-                            .setIcon(albumArt)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id2", "title2")
-                            .setSubtitle("subtitle1")
-                            .setIcon(albumArt)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id3", "title3")
-                            .setSubtitle("subtitle1")
-                            .setIcon(albumArt)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                    )
-            )
-
-        // set the screen width less than the width of media controls.
-        player.context.resources.configuration.screenWidthDp = 350
-        player.context.resources.configuration.orientation = Configuration.ORIENTATION_PORTRAIT
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(data)
-
-        val res = player.context.resources
-        val displayAvailableWidth =
-            TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 350f, res.displayMetrics).toInt()
-        val recCoverWidth: Int =
-            (res.getDimensionPixelSize(R.dimen.qs_media_rec_album_width) +
-                res.getDimensionPixelSize(R.dimen.qs_media_info_spacing) * 2)
-        val numOfRecs = displayAvailableWidth / recCoverWidth
-
-        assertThat(player.numberOfFittedRecommendations).isEqualTo(numOfRecs)
-        recommendationViewHolder.mediaCoverContainers.forEachIndexed { index, container ->
-            if (index < numOfRecs) {
-                assertThat(expandedSet.getVisibility(container.id)).isEqualTo(ConstraintSet.VISIBLE)
-                assertThat(collapsedSet.getVisibility(container.id))
-                    .isEqualTo(ConstraintSet.VISIBLE)
-            } else {
-                assertThat(expandedSet.getVisibility(container.id)).isEqualTo(ConstraintSet.GONE)
-                assertThat(collapsedSet.getVisibility(container.id)).isEqualTo(ConstraintSet.GONE)
-            }
-        }
-    }
-
-    @Test
-    fun bindRecommendation_carouselNotFitThreeRecs_OrientationLandscape() {
-        useRealConstraintSets()
-        val albumArt = getColorIcon(Color.RED)
-        val data =
-            smartspaceData.copy(
-                recommendations =
-                    listOf(
-                        SmartspaceAction.Builder("id1", "title1")
-                            .setSubtitle("subtitle1")
-                            .setIcon(albumArt)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id2", "title2")
-                            .setSubtitle("subtitle1")
-                            .setIcon(albumArt)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                        SmartspaceAction.Builder("id3", "title3")
-                            .setSubtitle("subtitle1")
-                            .setIcon(albumArt)
-                            .setExtras(Bundle.EMPTY)
-                            .build(),
-                    )
-            )
-
-        // set the screen width less than the width of media controls.
-        // We should have dp width less than 378 to test. In landscape we should have 2x.
-        player.context.resources.configuration.screenWidthDp = 700
-        player.context.resources.configuration.orientation = Configuration.ORIENTATION_LANDSCAPE
-        player.attachRecommendation(recommendationViewHolder)
-        player.bindRecommendation(data)
-
-        val res = player.context.resources
-        val displayAvailableWidth =
-            TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 350f, res.displayMetrics).toInt()
-        val recCoverWidth: Int =
-            (res.getDimensionPixelSize(R.dimen.qs_media_rec_album_width) +
-                res.getDimensionPixelSize(R.dimen.qs_media_info_spacing) * 2)
-        val numOfRecs = displayAvailableWidth / recCoverWidth
-
-        assertThat(player.numberOfFittedRecommendations).isEqualTo(numOfRecs)
-        recommendationViewHolder.mediaCoverContainers.forEachIndexed { index, container ->
-            if (index < numOfRecs) {
-                assertThat(expandedSet.getVisibility(container.id)).isEqualTo(ConstraintSet.VISIBLE)
-                assertThat(collapsedSet.getVisibility(container.id))
-                    .isEqualTo(ConstraintSet.VISIBLE)
-            } else {
-                assertThat(expandedSet.getVisibility(container.id)).isEqualTo(ConstraintSet.GONE)
-                assertThat(collapsedSet.getVisibility(container.id)).isEqualTo(ConstraintSet.GONE)
-            }
-        }
-    }
-
-    @Test
-    fun addTwoRecommendationGradients_differentStates() {
-        // Setup redArtwork and its color scheme.
-        val redArt = getColorIcon(Color.RED)
-        val redWallpaperColor = player.getWallpaperColor(redArt)
-        val redColorScheme = ColorScheme(redWallpaperColor, true, Style.CONTENT)
-
-        // Setup greenArt and its color scheme.
-        val greenArt = getColorIcon(Color.GREEN)
-        val greenWallpaperColor = player.getWallpaperColor(greenArt)
-        val greenColorScheme = ColorScheme(greenWallpaperColor, true, Style.CONTENT)
-
-        // Add gradient to both icons.
-        val redArtwork = player.addGradientToRecommendationAlbum(redArt, redColorScheme, 10, 10)
-        val greenArtwork =
-            player.addGradientToRecommendationAlbum(greenArt, greenColorScheme, 10, 10)
-
-        // They should have different constant states as they have different gradient color.
-        assertThat(redArtwork.getDrawable(1).constantState)
-            .isNotEqualTo(greenArtwork.getDrawable(1).constantState)
-    }
-
-    @Test
     fun onButtonClick_playsTouchRipple() {
         val semanticActions =
             MediaButton(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaViewControllerTest.kt
index e765b6f..760f73c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/controls/ui/controller/MediaViewControllerTest.kt
@@ -42,7 +42,6 @@
 import com.android.systemui.media.controls.ui.view.GutsViewHolder
 import com.android.systemui.media.controls.ui.view.MediaHost
 import com.android.systemui.media.controls.ui.view.MediaViewHolder
-import com.android.systemui.media.controls.ui.view.RecommendationViewHolder
 import com.android.systemui.media.controls.ui.viewmodel.SeekBarViewModel
 import com.android.systemui.res.R
 import com.android.systemui.surfaceeffects.loadingeffect.LoadingEffectView
@@ -79,7 +78,6 @@
     private val configurationController =
         com.android.systemui.statusbar.phone.ConfigurationControllerImpl(context)
     private var player = TransitionLayout(context, /* attrs */ null, /* defStyleAttr */ 0)
-    private var recommendation = TransitionLayout(context, /* attrs */ null, /* defStyleAttr */ 0)
     private val clock = FakeSystemClock()
     private lateinit var mainExecutor: FakeExecutor
     private lateinit var seekBar: SeekBar
@@ -110,9 +108,6 @@
     @Mock private lateinit var mockCopiedState: TransitionViewState
     @Mock private lateinit var detailWidgetState: WidgetState
     @Mock private lateinit var controlWidgetState: WidgetState
-    @Mock private lateinit var mediaTitleWidgetState: WidgetState
-    @Mock private lateinit var mediaSubTitleWidgetState: WidgetState
-    @Mock private lateinit var mediaContainerWidgetState: WidgetState
     @Mock private lateinit var seekBarViewModel: SeekBarViewModel
     @Mock private lateinit var seekBarData: LiveData<SeekBarViewModel.Progress>
     @Mock private lateinit var globalSettings: GlobalSettings
@@ -145,7 +140,7 @@
                     context: Context,
                     animId: Int,
                     motionInterpolator: Interpolator?,
-                    vararg targets: View?
+                    vararg targets: View?,
                 ): AnimatorSet {
                     return mockAnimator
                 }
@@ -158,7 +153,7 @@
     fun testOrientationChanged_heightOfPlayerIsUpdated() {
         val newConfig = Configuration()
 
-        mediaViewController.attach(player, MediaViewController.TYPE.PLAYER)
+        mediaViewController.attach(player)
         // Change the height to see the effect of orientation change.
         MediaViewHolder.backgroundIds.forEach { id ->
             mediaViewController.expandedLayout.getConstraint(id).layout.mHeight = 10
@@ -177,30 +172,8 @@
     }
 
     @Test
-    fun testOrientationChanged_heightOfRecCardIsUpdated() {
-        val newConfig = Configuration()
-
-        mediaViewController.attach(recommendation, MediaViewController.TYPE.RECOMMENDATION)
-        // Change the height to see the effect of orientation change.
-        mediaViewController.expandedLayout
-            .getConstraint(RecommendationViewHolder.backgroundId)
-            .layout
-            .mHeight = 10
-        newConfig.orientation = ORIENTATION_LANDSCAPE
-        configurationController.onConfigurationChanged(newConfig)
-
-        assertTrue(
-            mediaViewController.expandedLayout
-                .getConstraint(RecommendationViewHolder.backgroundId)
-                .layout
-                .mHeight ==
-                context.resources.getDimensionPixelSize(R.dimen.qs_media_session_height_expanded)
-        )
-    }
-
-    @Test
     fun testObtainViewState_applySquishFraction_toPlayerTransitionViewState_height() {
-        mediaViewController.attach(player, MediaViewController.TYPE.PLAYER)
+        mediaViewController.attach(player)
         player.measureState =
             TransitionViewState().apply {
                 this.height = 100
@@ -224,29 +197,8 @@
     }
 
     @Test
-    fun testObtainViewState_applySquishFraction_toRecommendationTransitionViewState_height() {
-        mediaViewController.attach(recommendation, MediaViewController.TYPE.RECOMMENDATION)
-        recommendation.measureState = TransitionViewState().apply { this.height = 100 }
-        mediaHostStateHolder.expansion = 1f
-        val widthMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
-        val heightMeasureSpec = View.MeasureSpec.makeMeasureSpec(100, View.MeasureSpec.EXACTLY)
-        mediaHostStateHolder.measurementInput =
-            MeasurementInput(widthMeasureSpec, heightMeasureSpec)
-
-        // Test no squish
-        mediaHostStateHolder.squishFraction = 1f
-        assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 100)
-        assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.measureHeight == 100)
-
-        // Test half squish
-        mediaHostStateHolder.squishFraction = 0.5f
-        assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.height == 50)
-        assertTrue(mediaViewController.obtainViewState(mediaHostStateHolder)!!.measureHeight == 100)
-    }
-
-    @Test
     fun testObtainViewState_expandedMatchesParentHeight() {
-        mediaViewController.attach(player, MediaViewController.TYPE.PLAYER)
+        mediaViewController.attach(player)
         player.measureState =
             TransitionViewState().apply {
                 this.height = 100
@@ -283,7 +235,7 @@
             .thenReturn(
                 mutableMapOf(
                     R.id.media_progress_bar to controlWidgetState,
-                    R.id.header_artist to detailWidgetState
+                    R.id.header_artist to detailWidgetState,
                 )
             )
         whenever(mockCopiedState.measureHeight).thenReturn(200)
@@ -311,7 +263,7 @@
             .thenReturn(
                 mutableMapOf(
                     R.id.media_progress_bar to controlWidgetState,
-                    R.id.header_artist to detailWidgetState
+                    R.id.header_artist to detailWidgetState,
                 )
             )
         whenever(mockCopiedState.measureHeight).thenReturn(200)
@@ -332,46 +284,6 @@
         verify(detailWidgetState, never()).alpha = floatThat { it > 0 }
     }
 
-    @Test
-    fun testSquishViewState_applySquishFraction_toTransitionViewState_alpha_forRecommendation() {
-        whenever(mockViewState.copy()).thenReturn(mockCopiedState)
-        whenever(mockCopiedState.widgetStates)
-            .thenReturn(
-                mutableMapOf(
-                    R.id.media_title to mediaTitleWidgetState,
-                    R.id.media_subtitle to mediaSubTitleWidgetState,
-                    R.id.media_cover1_container to mediaContainerWidgetState
-                )
-            )
-        whenever(mockCopiedState.measureHeight).thenReturn(360)
-        // media container widgets occupy [20, 300]
-        whenever(mediaContainerWidgetState.y).thenReturn(20F)
-        whenever(mediaContainerWidgetState.height).thenReturn(280)
-        whenever(mediaContainerWidgetState.alpha).thenReturn(1F)
-        // media title widgets occupy [320, 330]
-        whenever(mediaTitleWidgetState.y).thenReturn(320F)
-        whenever(mediaTitleWidgetState.height).thenReturn(10)
-        whenever(mediaTitleWidgetState.alpha).thenReturn(1F)
-        // media subtitle widgets occupy [340, 350]
-        whenever(mediaSubTitleWidgetState.y).thenReturn(340F)
-        whenever(mediaSubTitleWidgetState.height).thenReturn(10)
-        whenever(mediaSubTitleWidgetState.alpha).thenReturn(1F)
-
-        // in current beizer, when the progress reach 0.38, the result will be 0.5
-        mediaViewController.squishViewState(mockViewState, 307.6F / 360F)
-        verify(mediaContainerWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
-        mediaViewController.squishViewState(mockViewState, 320F / 360F)
-        verify(mediaContainerWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
-        // media title and media subtitle are in same widget group, should be calculate together and
-        // have same alpha
-        mediaViewController.squishViewState(mockViewState, 353.8F / 360F)
-        verify(mediaTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
-        verify(mediaSubTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 0.5F) < delta }
-        mediaViewController.squishViewState(mockViewState, 360F / 360F)
-        verify(mediaTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
-        verify(mediaSubTitleWidgetState).alpha = floatThat { kotlin.math.abs(it - 1.0F) < delta }
-    }
-
     @EnableSceneContainer
     @Test
     fun attachPlayer_seekBarDisabled_seekBarVisibilityIsSetToInvisible() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
index 5c26dac..88c2697 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dialog/MediaSwitchingControllerTest.java
@@ -1573,25 +1573,6 @@
         assertThat(items.get(1).isFirstDeviceInGroup()).isFalse();
     }
 
-    @EnableFlags(Flags.FLAG_ENABLE_OUTPUT_SWITCHER_DEVICE_GROUPING)
-    @Test
-    public void deviceListUpdateWithDifferentDevices_firstSelectedDeviceIsFirstDeviceInGroup() {
-        when(mLocalMediaManager.isPreferenceRouteListingExist()).thenReturn(true);
-        doReturn(mMediaDevices)
-                .when(mLocalMediaManager)
-                .getSelectedMediaDevice();
-        mMediaSwitchingController.start(mCb);
-        reset(mCb);
-        mMediaSwitchingController.getMediaItemList().clear();
-        mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
-        mMediaDevices.clear();
-        mMediaDevices.add(mMediaDevice2);
-        mMediaSwitchingController.onDeviceListUpdate(mMediaDevices);
-
-        List<MediaItem> items = mMediaSwitchingController.getMediaItemList();
-        assertThat(items.get(0).isFirstDeviceInGroup()).isTrue();
-    }
-
     private int getNumberOfConnectDeviceButtons() {
         int numberOfConnectDeviceButtons = 0;
         for (MediaItem item : mMediaSwitchingController.getMediaItemList()) {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/EditModeTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/EditModeTest.kt
index 8c09b81..e76be82c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/EditModeTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/EditModeTest.kt
@@ -25,6 +25,8 @@
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.test.junit4.ComposeContentTestRule
 import androidx.compose.ui.test.junit4.createComposeRule
+import androidx.compose.ui.test.onAllNodesWithText
+import androidx.compose.ui.test.onFirst
 import androidx.compose.ui.test.onNodeWithContentDescription
 import androidx.compose.ui.test.onNodeWithText
 import androidx.compose.ui.test.performClick
@@ -80,7 +82,9 @@
         composeRule.assertCurrentTilesGridContainsExactly(
             listOf("tileA", "tileB", "tileC", "tileD_large", "tileE", "tileF")
         )
-        composeRule.assertAvailableTilesGridContainsExactly(listOf("tileG_large"))
+        composeRule.assertAvailableTilesGridContainsExactly(
+            TestEditTiles.map { it.tile.tileSpec.spec }
+        )
     }
 
     @Test
@@ -88,7 +92,8 @@
         composeRule.setContent { EditTileGridUnderTest() }
         composeRule.waitForIdle()
 
-        composeRule.onNodeWithContentDescription("tileA").performClick() // Selects
+        // Selects first "tileA", i.e. the one in the current grid
+        composeRule.onAllNodesWithText("tileA").onFirst().performClick()
         composeRule.onNodeWithText("Remove").performClick() // Removes
 
         composeRule.waitForIdle()
@@ -96,7 +101,9 @@
         composeRule.assertCurrentTilesGridContainsExactly(
             listOf("tileB", "tileC", "tileD_large", "tileE")
         )
-        composeRule.assertAvailableTilesGridContainsExactly(listOf("tileA", "tileF", "tileG_large"))
+        composeRule.assertAvailableTilesGridContainsExactly(
+            TestEditTiles.map { it.tile.tileSpec.spec }
+        )
     }
 
     private fun ComposeContentTestRule.assertCurrentTilesGridContainsExactly(specs: List<String>) =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
index bd4c5f5..021be32 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/panels/ui/compose/ResizingTest.kt
@@ -25,7 +25,8 @@
 import androidx.compose.ui.test.ExperimentalTestApi
 import androidx.compose.ui.test.click
 import androidx.compose.ui.test.junit4.createComposeRule
-import androidx.compose.ui.test.onNodeWithContentDescription
+import androidx.compose.ui.test.onAllNodesWithText
+import androidx.compose.ui.test.onFirst
 import androidx.compose.ui.test.performClick
 import androidx.compose.ui.test.performCustomAccessibilityActionWithLabel
 import androidx.compose.ui.test.performTouchInput
@@ -85,7 +86,8 @@
         composeRule.waitForIdle()
 
         composeRule
-            .onNodeWithContentDescription("tileA")
+            .onAllNodesWithText("tileA")
+            .onFirst()
             .performCustomAccessibilityActionWithLabel(
                 context.getString(R.string.accessibility_qs_edit_toggle_tile_size_action)
             )
@@ -103,7 +105,8 @@
         composeRule.waitForIdle()
 
         composeRule
-            .onNodeWithContentDescription("tileD_large")
+            .onAllNodesWithText("tileD_large")
+            .onFirst()
             .performCustomAccessibilityActionWithLabel(
                 context.getString(R.string.accessibility_qs_edit_toggle_tile_size_action)
             )
@@ -121,7 +124,8 @@
         composeRule.waitForIdle()
 
         composeRule
-            .onNodeWithContentDescription("tileA")
+            .onAllNodesWithText("tileA")
+            .onFirst()
             .performClick() // Select
             .performTouchInput { // Tap on resizing handle
                 click(centerRight)
@@ -141,7 +145,8 @@
         composeRule.waitForIdle()
 
         composeRule
-            .onNodeWithContentDescription("tileD_large")
+            .onAllNodesWithText("tileD_large")
+            .onFirst()
             .performClick() // Select
             .performTouchInput { // Tap on resizing handle
                 click(centerRight)
@@ -161,7 +166,8 @@
         composeRule.waitForIdle()
 
         composeRule
-            .onNodeWithContentDescription("tileA")
+            .onAllNodesWithText("tileA")
+            .onFirst()
             .performClick() // Select
             .performTouchInput { // Resize up
                 swipeRight(startX = right, endX = right * 2)
@@ -181,7 +187,8 @@
         composeRule.waitForIdle()
 
         composeRule
-            .onNodeWithContentDescription("tileD_large")
+            .onAllNodesWithText("tileD_large")
+            .onFirst()
             .performClick() // Select
             .performTouchInput { // Resize down
                 swipeLeft()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt b/packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt
index 40547c2..2d3f538 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/LauncherProxyServiceTest.kt
@@ -24,6 +24,7 @@
 import android.os.UserManager
 import android.testing.TestableContext
 import android.testing.TestableLooper
+import android.view.Display
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.internal.app.AssistUtils
@@ -35,8 +36,7 @@
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.keyguard.ui.view.InWindowLauncherUnlockAnimationManager
-import com.android.systemui.model.SysUiState
-import com.android.systemui.model.sceneContainerPlugin
+import com.android.systemui.model.sysUiState
 import com.android.systemui.navigationbar.NavigationBarController
 import com.android.systemui.navigationbar.NavigationModeController
 import com.android.systemui.process.ProcessWrapper
@@ -67,6 +67,7 @@
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers
+import org.mockito.ArgumentMatchers.eq
 import org.mockito.Mock
 import org.mockito.Mockito.any
 import org.mockito.Mockito.anyInt
@@ -93,7 +94,7 @@
     @Mock private lateinit var processWrapper: ProcessWrapper
     private val displayTracker = FakeDisplayTracker(mContext)
     private val fakeSystemClock = FakeSystemClock()
-    private val sysUiState = SysUiState(displayTracker, kosmos.sceneContainerPlugin)
+    private val sysUiState = kosmos.sysUiState
     private val wakefulnessLifecycle =
         WakefulnessLifecycle(mContext, null, fakeSystemClock, dumpManager)
 
@@ -165,7 +166,8 @@
 
         verify(launcherProxy)
             .onSystemUiStateChanged(
-                longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_AWAKE }
+                longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_AWAKE },
+                eq(Display.DEFAULT_DISPLAY),
             )
     }
 
@@ -175,7 +177,8 @@
 
         verify(launcherProxy)
             .onSystemUiStateChanged(
-                longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_WAKING }
+                longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_WAKING },
+                eq(Display.DEFAULT_DISPLAY),
             )
     }
 
@@ -185,7 +188,8 @@
 
         verify(launcherProxy)
             .onSystemUiStateChanged(
-                longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_ASLEEP }
+                longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_ASLEEP },
+                eq(Display.DEFAULT_DISPLAY),
             )
     }
 
@@ -197,7 +201,8 @@
 
         verify(launcherProxy)
             .onSystemUiStateChanged(
-                longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_GOING_TO_SLEEP }
+                longThat { it and SYSUI_STATE_WAKEFULNESS_MASK == WAKEFULNESS_GOING_TO_SLEEP },
+                eq(Display.DEFAULT_DISPLAY),
             )
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
index 6005725..1f189a5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/screenshot/ActionIntentCreatorTest.kt
@@ -35,6 +35,10 @@
 import com.android.systemui.util.mockito.mock
 import com.google.common.truth.Truth.assertThat
 import com.google.common.truth.Truth.assertWithMessage
+import kotlinx.coroutines.test.TestCoroutineScheduler
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.UnconfinedTestDispatcher
+import kotlinx.coroutines.test.runTest
 import org.junit.Test
 import org.junit.runner.RunWith
 import org.mockito.ArgumentMatchers.anyInt
@@ -43,9 +47,13 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class ActionIntentCreatorTest : SysuiTestCase() {
+    private val scheduler = TestCoroutineScheduler()
+    private val mainDispatcher = UnconfinedTestDispatcher(scheduler)
+    private val testScope = TestScope(mainDispatcher)
     val context = mock<Context>()
     val packageManager = mock<PackageManager>()
-    private val actionIntentCreator = ActionIntentCreator(context, packageManager)
+    private val actionIntentCreator =
+        ActionIntentCreator(context, packageManager, testScope.backgroundScope, mainDispatcher)
 
     @Test
     fun testCreateShare() {
@@ -132,7 +140,7 @@
 
     @Test
     @DisableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
-    fun testCreateEditLegacy() {
+    fun testCreateEditLegacy() = runTest {
         val uri = Uri.parse("content://fake")
 
         whenever(context.getString(eq(R.string.config_screenshotEditor))).thenReturn("")
@@ -155,7 +163,7 @@
 
     @Test
     @DisableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
-    fun testCreateEditLegacy_embeddedUserIdRemoved() {
+    fun testCreateEditLegacy_embeddedUserIdRemoved() = runTest {
         val uri = Uri.parse("content://555@fake")
         whenever(context.getString(eq(R.string.config_screenshotEditor))).thenReturn("")
 
@@ -166,7 +174,7 @@
 
     @Test
     @DisableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
-    fun testCreateEditLegacy_withEditor() {
+    fun testCreateEditLegacy_withEditor() = runTest {
         val uri = Uri.parse("content://fake")
         val component = ComponentName("com.android.foo", "com.android.foo.Something")
 
@@ -180,7 +188,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
-    fun testCreateEdit() {
+    fun testCreateEdit() = runTest {
         val uri = Uri.parse("content://fake")
 
         whenever(context.getString(eq(R.string.config_screenshotEditor))).thenReturn("")
@@ -203,7 +211,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
-    fun testCreateEdit_embeddedUserIdRemoved() {
+    fun testCreateEdit_embeddedUserIdRemoved() = runTest {
         val uri = Uri.parse("content://555@fake")
         whenever(context.getString(eq(R.string.config_screenshotEditor))).thenReturn("")
 
@@ -214,7 +222,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
-    fun testCreateEdit_withPreferredEditorEnabled() {
+    fun testCreateEdit_withPreferredEditorEnabled() = runTest {
         val uri = Uri.parse("content://fake")
         val fallbackComponent = ComponentName("com.android.foo", "com.android.foo.Something")
         val preferredComponent = ComponentName("com.android.bar", "com.android.bar.Something")
@@ -243,7 +251,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
-    fun testCreateEdit_withPreferredEditorDisabled() {
+    fun testCreateEdit_withPreferredEditorDisabled() = runTest {
         val uri = Uri.parse("content://fake")
         val fallbackComponent = ComponentName("com.android.foo", "com.android.foo.Something")
         val preferredComponent = ComponentName("com.android.bar", "com.android.bar.Something")
@@ -266,7 +274,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_USE_PREFERRED_IMAGE_EDITOR)
-    fun testCreateEdit_withFallbackEditor() {
+    fun testCreateEdit_withFallbackEditor() = runTest {
         val uri = Uri.parse("content://fake")
         val component = ComponentName("com.android.foo", "com.android.foo.Something")
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index e42bf19..51bb38f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -23,7 +23,6 @@
 import android.testing.TestableLooper
 import android.testing.TestableLooper.RunWithLooper
 import android.view.Choreographer
-import android.view.KeyEvent
 import android.view.MotionEvent
 import android.view.View
 import android.view.ViewGroup
@@ -54,6 +53,7 @@
 import com.android.systemui.kosmos.testScope
 import com.android.systemui.qs.flags.QSComposeFragment
 import com.android.systemui.res.R
+import com.android.systemui.scene.ui.view.WindowRootViewKeyEventHandler
 import com.android.systemui.settings.brightness.data.repository.BrightnessMirrorShowingRepository
 import com.android.systemui.settings.brightness.domain.interactor.BrightnessMirrorShowingInteractorPassThrough
 import com.android.systemui.shade.NotificationShadeWindowView.InteractionEventHandler
@@ -96,7 +96,6 @@
 import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import kotlinx.coroutines.test.setMain
-import org.junit.Assert.assertEquals
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -245,7 +244,7 @@
                 notificationLaunchAnimationInteractor,
                 featureFlagsClassic,
                 fakeClock,
-                sysUIKeyEventHandler,
+                WindowRootViewKeyEventHandler({ sysUIKeyEventHandler }, falsingCollector),
                 quickSettingsController,
                 primaryBouncerInteractor,
                 alternateBouncerInteractor,
@@ -591,34 +590,6 @@
     }
 
     @Test
-    fun forwardsDispatchKeyEvent() {
-        val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
-        interactionEventHandler.dispatchKeyEvent(keyEvent)
-        verify(sysUIKeyEventHandler).dispatchKeyEvent(keyEvent)
-    }
-
-    @Test
-    fun forwardsDispatchKeyEventPreIme() {
-        val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_B)
-        interactionEventHandler.dispatchKeyEventPreIme(keyEvent)
-        verify(sysUIKeyEventHandler).dispatchKeyEventPreIme(keyEvent)
-    }
-
-    @Test
-    fun forwardsInterceptMediaKey() {
-        val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_VOLUME_UP)
-        interactionEventHandler.interceptMediaKey(keyEvent)
-        verify(sysUIKeyEventHandler).interceptMediaKey(keyEvent)
-    }
-
-    @Test
-    fun forwardsCollectKeyEvent() {
-        val keyEvent = KeyEvent(KeyEvent.ACTION_DOWN, KeyEvent.KEYCODE_A)
-        interactionEventHandler.collectKeyEvent(keyEvent)
-        assertEquals(keyEvent, falsingCollector.lastKeyEvent)
-    }
-
-    @Test
     fun cancelCurrentTouch_callsDragDownHelper() {
         underTest.cancelCurrentTouch()
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
index 8418598..116a2ca 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shared/condition/CombinedConditionTest.kt
@@ -19,9 +19,9 @@
 import androidx.test.ext.junit.runners.AndroidJUnit4
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
-import com.android.systemui.shared.condition.Condition.START_EAGERLY
-import com.android.systemui.shared.condition.Condition.START_LAZILY
-import com.android.systemui.shared.condition.Condition.START_WHEN_NEEDED
+import com.android.systemui.shared.condition.Condition.Companion.START_EAGERLY
+import com.android.systemui.shared.condition.Condition.Companion.START_LAZILY
+import com.android.systemui.shared.condition.Condition.Companion.START_WHEN_NEEDED
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.Dispatchers
@@ -40,7 +40,7 @@
         scope: CoroutineScope,
         initialValue: Boolean?,
         overriding: Boolean = false,
-        @StartStrategy private val startStrategy: Int = START_WHEN_NEEDED,
+        @StartStrategy override val startStrategy: Int = START_WHEN_NEEDED,
     ) : Condition(scope, initialValue, overriding) {
         private var _started = false
         val started: Boolean
@@ -54,10 +54,6 @@
             _started = false
         }
 
-        override fun getStartStrategy(): Int {
-            return startStrategy
-        }
-
         fun setValue(value: Boolean?) {
             value?.also { updateCondition(value) } ?: clearCondition()
         }
@@ -75,13 +71,8 @@
         val combinedCondition =
             CombinedCondition(
                 scope = this,
-                conditions =
-                    listOf(
-                        eagerCondition,
-                        lazyCondition,
-                        startWhenNeededCondition,
-                    ),
-                operand = Evaluator.OP_OR
+                conditions = listOf(eagerCondition, lazyCondition, startWhenNeededCondition),
+                operand = Evaluator.OP_OR,
             )
 
         val callback = Condition.Callback {}
@@ -124,13 +115,8 @@
         val combinedCondition =
             CombinedCondition(
                 scope = this,
-                conditions =
-                    listOf(
-                        startWhenNeededCondition,
-                        lazyCondition,
-                        eagerCondition,
-                    ),
-                operand = Evaluator.OP_AND
+                conditions = listOf(startWhenNeededCondition, lazyCondition, eagerCondition),
+                operand = Evaluator.OP_AND,
             )
 
         val callback = Condition.Callback {}
@@ -175,7 +161,7 @@
                     FakeCondition(
                         scope = this,
                         initialValue = false,
-                        startStrategy = START_WHEN_NEEDED
+                        startStrategy = START_WHEN_NEEDED,
                     )
                 }
                 .toList()
@@ -214,7 +200,7 @@
                     FakeCondition(
                         scope = this,
                         initialValue = false,
-                        startStrategy = START_WHEN_NEEDED
+                        startStrategy = START_WHEN_NEEDED,
                     )
                 }
                 .toList()
@@ -262,7 +248,7 @@
                     FakeCondition(
                         scope = this,
                         initialValue = false,
-                        startStrategy = START_WHEN_NEEDED
+                        startStrategy = START_WHEN_NEEDED,
                     )
                 }
                 .toList()
@@ -300,9 +286,9 @@
                         overridingCondition1,
                         lazyCondition,
                         startWhenNeededCondition,
-                        overridingCondition2
+                        overridingCondition2,
                     ),
-                operand = Evaluator.OP_OR
+                operand = Evaluator.OP_OR,
             )
 
         val callback = Condition.Callback {}
@@ -414,11 +400,7 @@
     fun testEmptyConditions() = runSelfCancelingTest {
         for (operand in intArrayOf(Evaluator.OP_OR, Evaluator.OP_AND)) {
             val combinedCondition =
-                CombinedCondition(
-                    scope = this,
-                    conditions = emptyList(),
-                    operand = operand,
-                )
+                CombinedCondition(scope = this, conditions = emptyList(), operand = operand)
 
             val callback = Condition.Callback {}
             combinedCondition.addCallback(callback)
@@ -435,9 +417,7 @@
      * Executes the given block of execution within the scope of a dedicated [CoroutineScope] which
      * is then automatically canceled and cleaned-up.
      */
-    private fun runSelfCancelingTest(
-        block: suspend CoroutineScope.() -> Unit,
-    ) =
+    private fun runSelfCancelingTest(block: suspend CoroutineScope.() -> Unit) =
         runBlocking(IMMEDIATE) {
             val scope = CoroutineScope(coroutineContext + Job())
             block(scope)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
index acfa94a..cd2ea7d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowTest.java
@@ -67,6 +67,7 @@
 import com.android.systemui.flags.Flags;
 import com.android.systemui.plugins.statusbar.NotificationMenuRowPlugin;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.notification.AboveShelfChangedListener;
 import com.android.systemui.statusbar.notification.FeedbackIcon;
 import com.android.systemui.statusbar.notification.SourceType;
@@ -1128,6 +1129,30 @@
         assertThat(row.mustStayOnScreen()).isFalse();
     }
 
+    @Test
+    @DisableFlags(StatusBarNotifChips.FLAG_NAME)
+    public void hasStatusBarChipDuringHeadsUpAnimation_flagOff_false() throws Exception {
+        final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+
+        row.setHasStatusBarChipDuringHeadsUpAnimation(true);
+
+        assertThat(row.hasStatusBarChipDuringHeadsUpAnimation()).isFalse();
+    }
+
+    @Test
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    public void hasStatusBarChipDuringHeadsUpAnimation_flagOn_returnsValue() throws Exception {
+        final ExpandableNotificationRow row = mNotificationTestHelper.createRow();
+
+        assertThat(row.hasStatusBarChipDuringHeadsUpAnimation()).isFalse();
+
+        row.setHasStatusBarChipDuringHeadsUpAnimation(true);
+        assertThat(row.hasStatusBarChipDuringHeadsUpAnimation()).isTrue();
+
+        row.setHasStatusBarChipDuringHeadsUpAnimation(false);
+        assertThat(row.hasStatusBarChipDuringHeadsUpAnimation()).isFalse();
+    }
+
     private void setDrawableIconsInImageView(CachingIconView icon, Drawable iconDrawable,
             Drawable rightIconDrawable) {
         ImageView iconView = mock(ImageView.class);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt
index 86689cb..d035760 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/row/RowImageInflaterTest.kt
@@ -21,6 +21,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.statusbar.notification.promoted.PromotedNotificationUiAod
+import com.android.systemui.statusbar.notification.row.shared.IconData
 import com.android.systemui.statusbar.notification.row.shared.ImageModel
 import com.android.systemui.statusbar.notification.row.shared.ImageModelProvider.ImageSizeClass.SmallSquare
 import com.google.common.truth.Truth.assertThat
@@ -38,20 +39,22 @@
     private val resIcon2 = Icon.createWithResource(context, android.R.drawable.ic_delete)
     private val badUriIcon = Icon.createWithContentUri("content://com.test/does_not_exist")
 
+    private var latestImageModelIndex: ImageModelIndex? = null
+
     @Before
     fun setUp() {
-        rowImageInflater = RowImageInflater.newInstance(null)
+        rowImageInflater = RowImageInflater.newInstance(null, reinflating = false)
     }
 
     @Test
     fun getNewImageIndex_returnsNullWhenUnused() {
-        assertThat(rowImageInflater.getNewImageIndex()).isNull()
+        assertThat(getNewImageIndex()).isNull()
     }
 
     @Test
     fun getNewImageIndex_returnsEmptyIndexWhenZeroImagesLoaded() {
         assertThat(getImageModelsForIcons()).isEmpty()
-        val result = rowImageInflater.getNewImageIndex()
+        val result = getNewImageIndex()
         assertThat(result).isNotNull()
         assertThat(result?.contentsForTesting).isEmpty()
     }
@@ -59,7 +62,7 @@
     @Test
     fun getNewImageIndex_returnsSingleImageWhenOneImageLoaded() {
         assertThat(getImageModelsForIcons(resIcon1)).hasSize(1)
-        val result = rowImageInflater.getNewImageIndex()
+        val result = getNewImageIndex()
         assertThat(result).isNotNull()
         assertThat(result?.contentsForTesting).hasSize(1)
     }
@@ -85,7 +88,7 @@
         assertThat(providedModels[3].drawable).isNotNull()
 
         // VERIFY the returned index has all 3 entries, 2 of which have drawables
-        val indexGen1 = rowImageInflater.getNewImageIndex()
+        val indexGen1 = getNewImageIndex()
         assertThat(indexGen1).isNotNull()
         assertThat(indexGen1?.contentsForTesting).hasSize(3)
         assertThat(indexGen1?.contentsForTesting?.mapNotNull { it.drawable }).hasSize(2)
@@ -96,7 +99,7 @@
         exampleFirstGeneration()
 
         // THEN start a new generation of the inflation
-        rowImageInflater = RowImageInflater.newInstance(rowImageInflater.getNewImageIndex())
+        rowImageInflater = RowImageInflater.newInstance(getNewImageIndex(), reinflating = false)
 
         getNewImageIndex_returnsEmptyIndexWhenZeroImagesLoaded()
     }
@@ -104,13 +107,47 @@
     @Test
     fun exampleSecondGeneration_whichLoadsOneImage() {
         exampleFirstGeneration()
+        val gen1Index = latestImageModelIndex!!
 
         // THEN start a new generation of the inflation
-        rowImageInflater = RowImageInflater.newInstance(rowImageInflater.getNewImageIndex())
+        rowImageInflater = RowImageInflater.newInstance(gen1Index, reinflating = false)
 
         getNewImageIndex_returnsSingleImageWhenOneImageLoaded()
+        val gen2Index = latestImageModelIndex!!
+
+        // VERIFY that the drawable was copied from the previous index
+        val gen1model = gen1Index.findModel(resIcon1)
+        val gen2model = gen2Index.findModel(resIcon1)
+        assertThat(gen2model).isNotSameInstanceAs(gen1model)
+        assertThat(gen2model.drawable).isSameInstanceAs(gen1model.drawable)
     }
 
+    @Test
+    fun exampleSecondGeneration_reinflating_whichLoadsOneImage() {
+        exampleFirstGeneration()
+        val gen1Index = latestImageModelIndex!!
+
+        // THEN start a new generation of the inflation
+        rowImageInflater = RowImageInflater.newInstance(gen1Index, reinflating = true)
+
+        getNewImageIndex_returnsSingleImageWhenOneImageLoaded()
+        val gen2Index = latestImageModelIndex!!
+
+        // VERIFY that the drawable was reloaded rather than copied from the previous index
+        val gen1model = gen1Index.findModel(resIcon1)
+        val gen2model = gen2Index.findModel(resIcon1)
+        assertThat(gen2model).isNotSameInstanceAs(gen1model)
+        assertThat(gen2model.drawable).isNotSameInstanceAs(gen1model.drawable)
+    }
+
+    private fun ImageModelIndex.findModel(icon: Icon): LazyImage =
+        IconData.fromIcon(icon)
+            .let { iconData -> contentsForTesting.find { it.icon == iconData } }
+            .also { assertThat(it).isNotNull() }!!
+
+    private fun getNewImageIndex(): ImageModelIndex? =
+        rowImageInflater.getNewImageIndex().also { latestImageModelIndex = it }
+
     private fun getImageModelsForIcons(vararg icons: Icon): List<ImageModel> {
         val provider = rowImageInflater.useForContentModel()
         return icons.map { icon ->
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 2a58890..8fb2a24 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -82,6 +82,7 @@
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
+import com.android.systemui.statusbar.chips.notification.shared.StatusBarNotifChips;
 import com.android.systemui.statusbar.notification.collection.EntryAdapter;
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.notification.collection.render.GroupExpansionManager;
@@ -92,6 +93,7 @@
 import com.android.systemui.statusbar.notification.footer.ui.view.FooterView;
 import com.android.systemui.statusbar.notification.headsup.AvalancheController;
 import com.android.systemui.statusbar.notification.headsup.HeadsUpManager;
+import com.android.systemui.statusbar.notification.headsup.NotificationsHunSharedAnimationValues;
 import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow;
 import com.android.systemui.statusbar.notification.row.ExpandableView;
 import com.android.systemui.statusbar.notification.shared.NotificationThrottleHun;
@@ -1260,7 +1262,8 @@
         prepareStackScrollerForHunAnimations(headsUpAnimatingAwayListener);
 
         // WHEN we generate a disappear event
-        mStackScroller.generateHeadsUpAnimation(row, /* isHeadsUp = */ false);
+        mStackScroller.generateHeadsUpAnimation(
+                row, /* isHeadsUp = */ false, /* hasStatusBarChip= */ false);
 
         // THEN headsUpAnimatingAway is true
         verify(headsUpAnimatingAwayListener).accept(true);
@@ -1269,6 +1272,51 @@
 
     @Test
     @EnableSceneContainer
+    @DisableFlags(StatusBarNotifChips.FLAG_NAME)
+    public void testGenerateHeadsUpDisappearEvent_notifChipsFlagOff_statusBarChipNotSet() {
+        // GIVEN NSSL is ready for HUN animations
+        Consumer<Boolean> headsUpAnimatingAwayListener = mock(BooleanConsumer.class);
+        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+        prepareStackScrollerForHunAnimations(headsUpAnimatingAwayListener);
+
+        mStackScroller.generateHeadsUpAnimation(
+                row, /* isHeadsUp = */ false, /* hasStatusBarChip= */ true);
+
+        verify(row, never()).setHasStatusBarChipDuringHeadsUpAnimation(anyBoolean());
+    }
+
+    @Test
+    @EnableSceneContainer
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    public void testGenerateHeadsUpDisappearEvent_notifChipsFlagOn_statusBarChipSetToFalse() {
+        // GIVEN NSSL is ready for HUN animations
+        Consumer<Boolean> headsUpAnimatingAwayListener = mock(BooleanConsumer.class);
+        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+        prepareStackScrollerForHunAnimations(headsUpAnimatingAwayListener);
+
+        mStackScroller.generateHeadsUpAnimation(
+                row, /* isHeadsUp = */ false, /* hasStatusBarChip= */ false);
+
+        verify(row).setHasStatusBarChipDuringHeadsUpAnimation(false);
+    }
+
+    @Test
+    @EnableSceneContainer
+    @EnableFlags(StatusBarNotifChips.FLAG_NAME)
+    public void testGenerateHeadsUpDisappearEvent_notifChipsFlagOn_statusBarChipSetToTrue() {
+        // GIVEN NSSL is ready for HUN animations
+        Consumer<Boolean> headsUpAnimatingAwayListener = mock(BooleanConsumer.class);
+        ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
+        prepareStackScrollerForHunAnimations(headsUpAnimatingAwayListener);
+
+        mStackScroller.generateHeadsUpAnimation(
+                row, /* isHeadsUp = */ false, /* hasStatusBarChip= */ true);
+
+        verify(row).setHasStatusBarChipDuringHeadsUpAnimation(true);
+    }
+
+    @Test
+    @EnableSceneContainer
     public void testGenerateHeadsUpDisappearEvent_stackExpanded_headsUpAnimatingAwayNotSet() {
         // GIVEN NSSL would be ready for HUN animations, BUT it is expanded
         Consumer<Boolean> headsUpAnimatingAwayListener = mock(BooleanConsumer.class);
@@ -1279,7 +1327,8 @@
         mStackScroller.setHeadsUpGoingAwayAnimationsAllowed(true);
 
         // WHEN we generate a disappear event
-        mStackScroller.generateHeadsUpAnimation(row, /* isHeadsUp = */ false);
+        mStackScroller.generateHeadsUpAnimation(
+                row, /* isHeadsUp = */ false, /* hasStatusBarChip= */ false);
 
         // THEN nothing happens
         verify(headsUpAnimatingAwayListener, never()).accept(anyBoolean());
@@ -1294,10 +1343,12 @@
         ExpandableNotificationRow row = mock(ExpandableNotificationRow.class);
         prepareStackScrollerForHunAnimations(headsUpAnimatingAwayListener);
         // BUT there is a pending appear event
-        mStackScroller.generateHeadsUpAnimation(row, /* isHeadsUp = */ true);
+        mStackScroller.generateHeadsUpAnimation(
+                row, /* isHeadsUp = */ true, /* hasStatusBarChip= */ false);
 
         // WHEN we generate a disappear event
-        mStackScroller.generateHeadsUpAnimation(row, /* isHeadsUp = */ false);
+        mStackScroller.generateHeadsUpAnimation(
+                row, /* isHeadsUp = */ false, /* hasStatusBarChip= */ false);
 
         // THEN nothing happens
         verify(headsUpAnimatingAwayListener, never()).accept(anyBoolean());
@@ -1313,7 +1364,8 @@
         prepareStackScrollerForHunAnimations(headsUpAnimatingAwayListener);
 
         // WHEN we generate a disappear event
-        mStackScroller.generateHeadsUpAnimation(row, /* isHeadsUp = */ true);
+        mStackScroller.generateHeadsUpAnimation(
+                row, /* isHeadsUp = */ true, /* hasStatusBarChip= */ false);
 
         // THEN headsUpAnimatingWay is not set
         verify(headsUpAnimatingAwayListener, never()).accept(anyBoolean());
@@ -1335,7 +1387,8 @@
         when(row.getEntry()).thenReturn(entry);
 
         // WHEN we generate an add event
-        mStackScroller.generateHeadsUpAnimation(row, /* isHeadsUp = */ true);
+        mStackScroller.generateHeadsUpAnimation(
+                row, /* isHeadsUp = */ true, /* hasStatusBarChip= */ false);
 
         // THEN nothing happens
         assertThat(mStackScroller.isAddOrRemoveAnimationPending()).isFalse();
@@ -1350,7 +1403,8 @@
         prepareStackScrollerForHunAnimations(headsUpAnimatingAwayListener);
 
         // AND there is a HUN animating away
-        mStackScroller.generateHeadsUpAnimation(row, /* isHeadsUp = */ false);
+        mStackScroller.generateHeadsUpAnimation(
+                row, /* isHeadsUp = */ false,  /* hasStatusBarChip= */ false);
         assertTrue("a HUN should be animating away", mStackScroller.mHeadsUpAnimatingAway);
 
         // WHEN the child animations are finished
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractorTest.kt
index df45e2e..7946a68 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/domain/interactor/BatteryInteractorTest.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.collectLastValue
 import com.android.systemui.kosmos.runTest
+import com.android.systemui.kosmos.useUnconfinedTestDispatcher
 import com.android.systemui.statusbar.policy.batteryController
 import com.android.systemui.statusbar.policy.fake
 import com.android.systemui.testKosmos
@@ -32,7 +33,7 @@
 @SmallTest
 @RunWith(AndroidJUnit4::class)
 class BatteryInteractorTest : SysuiTestCase() {
-    val kosmos = testKosmos()
+    val kosmos = testKosmos().useUnconfinedTestDispatcher()
     val Kosmos.underTest by Kosmos.Fixture { batteryInteractor }
 
     @Test
@@ -50,12 +51,62 @@
 
             assertThat(latest).isEqualTo(BatteryAttributionModel.Defend)
 
+            batteryController.fake._isDefender = false
             batteryController.fake._isPowerSave = true
 
             assertThat(latest).isEqualTo(BatteryAttributionModel.PowerSave)
 
+            batteryController.fake._isPowerSave = false
             batteryController.fake._isPluggedIn = true
 
             assertThat(latest).isEqualTo(BatteryAttributionModel.Charging)
         }
+
+    @Test
+    fun attributionType_prioritizesPowerSaveOverCharging() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.batteryAttributionType)
+
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isDefender = true
+            batteryController.fake._isPowerSave = true
+
+            assertThat(latest).isEqualTo(BatteryAttributionModel.PowerSave)
+        }
+
+    @Test
+    fun attributionType_prioritizesPowerSaveOverDefender() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.batteryAttributionType)
+
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isPowerSave = true
+            batteryController.fake._isDefender = false
+
+            assertThat(latest).isEqualTo(BatteryAttributionModel.PowerSave)
+        }
+
+    @Test
+    fun attributionType_prioritizesDefenderOverCharging() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.batteryAttributionType)
+
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isPowerSave = false
+            batteryController.fake._isDefender = true
+
+            assertThat(latest).isEqualTo(BatteryAttributionModel.Defend)
+        }
+
+    @Test
+    fun attributionType_prioritizesChargingOnly() =
+        kosmos.runTest {
+            val latest by collectLastValue(underTest.batteryAttributionType)
+
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isDefender = false
+            batteryController.fake._isPowerSave = false
+
+            assertThat(latest).isEqualTo(BatteryAttributionModel.Charging)
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModelTest.kt
index 6f4c745..d817348 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/battery/ui/viewmodel/BatteryViewModelTest.kt
@@ -97,4 +97,39 @@
 
             assertThat(underTest.glyphList).isEqualTo(listOf(BatteryGlyph.BoltLarge))
         }
+
+    @Test
+    fun glyphList_attributionOrdering_prioritizesDefendOverCharging() =
+        kosmos.runTest {
+            fakeSystemSettingsRepository.setInt(Settings.System.SHOW_BATTERY_PERCENT, 0)
+            batteryController.fake._level = 39
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isDefender = true
+
+            assertThat(underTest.glyphList).isEqualTo(listOf(BatteryGlyph.DefendLarge))
+        }
+
+    @Test
+    fun glyphList_attributionOrdering_prioritizesPowerSaveOverDefend() =
+        kosmos.runTest {
+            fakeSystemSettingsRepository.setInt(Settings.System.SHOW_BATTERY_PERCENT, 0)
+            batteryController.fake._level = 39
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isDefender = true
+            batteryController.fake._isPowerSave = true
+
+            assertThat(underTest.glyphList).isEqualTo(listOf(BatteryGlyph.PlusLarge))
+        }
+
+    @Test
+    fun glyphList_attributionOrdering_prioritizesPowerSaveOverCharging() =
+        kosmos.runTest {
+            fakeSystemSettingsRepository.setInt(Settings.System.SHOW_BATTERY_PERCENT, 0)
+            batteryController.fake._level = 39
+            batteryController.fake._isPluggedIn = true
+            batteryController.fake._isDefender = false
+            batteryController.fake._isPowerSave = true
+
+            assertThat(underTest.glyphList).isEqualTo(listOf(BatteryGlyph.PlusLarge))
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt
index df74404..db948e9 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigTest.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.pipeline.mobile.data.model
 
 import android.os.PersistableBundle
-import android.telephony.CarrierConfigManager
 import android.telephony.CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL
 import android.telephony.CarrierConfigManager.KEY_SHOW_5G_SLICE_ICON_BOOL
 import android.telephony.CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL
@@ -37,7 +36,7 @@
 
     @Before
     fun setUp() {
-        underTest = SystemUiCarrierConfig(SUB_1_ID, createTestConfig())
+        underTest = SystemUiCarrierConfig(SUB_1_ID, testCarrierConfig())
     }
 
     @Test
@@ -46,7 +45,7 @@
         assertThat(underTest.isUsingDefault).isTrue()
 
         // ANY new config means we're no longer tracking defaults
-        underTest.processNewCarrierConfig(createTestConfig())
+        underTest.processNewCarrierConfig(testCarrierConfig())
 
         assertThat(underTest.isUsingDefault).isFalse()
     }
@@ -58,7 +57,7 @@
         assertThat(underTest.allowNetworkSliceIndicator.value).isTrue()
 
         underTest.processNewCarrierConfig(
-            configWithOverrides(
+            testCarrierConfigWithOverrides(
                 KEY_INFLATE_SIGNAL_STRENGTH_BOOL to true,
                 KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL to true,
                 KEY_SHOW_5G_SLICE_ICON_BOOL to false,
@@ -81,11 +80,11 @@
         underTest =
             SystemUiCarrierConfig(
                 SUB_1_ID,
-                configWithOverrides(
+                testCarrierConfigWithOverrides(
                     KEY_INFLATE_SIGNAL_STRENGTH_BOOL to true,
                     KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL to true,
                     KEY_SHOW_5G_SLICE_ICON_BOOL to true,
-                )
+                ),
             )
 
         assertThat(underTest.isUsingDefault).isTrue()
@@ -104,26 +103,5 @@
 
     companion object {
         private const val SUB_1_ID = 1
-
-        /**
-         * In order to keep us from having to update every place that might want to create a config,
-         * make sure to add new keys here
-         */
-        fun createTestConfig() =
-            PersistableBundle().also {
-                it.putBoolean(CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
-                it.putBoolean(CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, false)
-                it.putBoolean(CarrierConfigManager.KEY_SHOW_5G_SLICE_ICON_BOOL, true)
-            }
-
-        /** Override the default config with the given (key, value) pair */
-        fun configWithOverride(key: String, override: Boolean): PersistableBundle =
-            createTestConfig().also { it.putBoolean(key, override) }
-
-        /** Override any number of configs from the default */
-        fun configWithOverrides(vararg overrides: Pair<String, Boolean>) =
-            createTestConfig().also { config ->
-                overrides.forEach { (key, value) -> config.putBoolean(key, value) }
-            }
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt
index d074fc2..e1cc259 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/CarrierConfigRepositoryImplTest.kt
@@ -26,7 +26,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
-import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig
 import com.android.systemui.util.mockito.whenever
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.flow.launchIn
@@ -163,8 +163,8 @@
         private const val SUB_ID_1 = 1
         private const val SUB_ID_2 = 2
 
-        private val DEFAULT_CONFIG = createTestConfig()
-        private val CONFIG_1 = createTestConfig()
-        private val CONFIG_2 = createTestConfig()
+        private val DEFAULT_CONFIG = testCarrierConfig()
+        private val CONFIG_1 = testCarrierConfig()
+        private val CONFIG_2 = testCarrierConfig()
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
index a51e919..ed8be9b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionRepositoryTest.kt
@@ -86,8 +86,8 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType.UnknownNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
-import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.configWithOverride
-import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest.Companion.createTestConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfigWithOverride
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.telephonyDisplayInfo
@@ -129,7 +129,7 @@
     @Mock private lateinit var context: Context
 
     private val mobileMappings = FakeMobileMappingsProxy()
-    private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, createTestConfig())
+    private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, testCarrierConfig())
 
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
@@ -1314,13 +1314,13 @@
             assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
 
             systemUiCarrierConfig.processNewCarrierConfig(
-                configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
+                testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
             )
 
             assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS + 1)
 
             systemUiCarrierConfig.processNewCarrierConfig(
-                configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
+                testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
             )
 
             assertThat(latest).isEqualTo(DEFAULT_NUM_LEVELS)
@@ -1336,13 +1336,13 @@
             assertThat(latest).isEqualTo(false)
 
             systemUiCarrierConfig.processNewCarrierConfig(
-                configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
+                testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, true)
             )
 
             assertThat(latest).isEqualTo(true)
 
             systemUiCarrierConfig.processNewCarrierConfig(
-                configWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
+                testCarrierConfigWithOverride(KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
             )
 
             assertThat(latest).isEqualTo(false)
@@ -1354,13 +1354,13 @@
             val latest by collectLastValue(underTest.allowNetworkSliceIndicator)
 
             systemUiCarrierConfig.processNewCarrierConfig(
-                configWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, true)
+                testCarrierConfigWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, true)
             )
 
             assertThat(latest).isTrue()
 
             systemUiCarrierConfig.processNewCarrierConfig(
-                configWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, false)
+                testCarrierConfigWithOverride(KEY_SHOW_5G_SLICE_ICON_BOOL, false)
             )
 
             assertThat(latest).isFalse()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
index ec260fc..6f21e79 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/prod/MobileConnectionTelephonySmokeTests.kt
@@ -41,7 +41,7 @@
 import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
 import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfig
-import com.android.systemui.statusbar.pipeline.mobile.data.model.SystemUiCarrierConfigTest
+import com.android.systemui.statusbar.pipeline.mobile.data.model.testCarrierConfig
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.getTelephonyCallbackForType
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileTelephonyHelpers.signalStrength
 import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
@@ -105,11 +105,7 @@
     @Mock private lateinit var subscriptionModel: StateFlow<SubscriptionModel?>
 
     private val mobileMappings = FakeMobileMappingsProxy()
-    private val systemUiCarrierConfig =
-        SystemUiCarrierConfig(
-            SUB_1_ID,
-            SystemUiCarrierConfigTest.createTestConfig(),
-        )
+    private val systemUiCarrierConfig = SystemUiCarrierConfig(SUB_1_ID, testCarrierConfig())
 
     private val testDispatcher = UnconfinedTestDispatcher()
     private val testScope = TestScope(testDispatcher)
@@ -185,12 +181,7 @@
             val job = underTest.dataActivityDirection.onEach { latest = it }.launchIn(this)
 
             assertThat(latest)
-                .isEqualTo(
-                    DataActivityModel(
-                        hasActivityIn = true,
-                        hasActivityOut = true,
-                    )
-                )
+                .isEqualTo(DataActivityModel(hasActivityIn = true, hasActivityOut = true))
 
             displayInfoJob.cancel()
             job.cancel()
@@ -209,7 +200,7 @@
 
             connectionCallback.onDataConnectionStateChanged(
                 TelephonyManager.DATA_CONNECTED,
-                200 /* unused */
+                200, /* unused */
             )
 
             flipActivity(100, activityCallback)
@@ -320,10 +311,7 @@
             job.cancel()
         }
 
-    private fun flipActivity(
-        times: Int,
-        callback: DataActivityListener,
-    ) {
+    private fun flipActivity(times: Int, callback: DataActivityListener) {
         repeat(times) { index -> callback.onDataActivity(index % 4) }
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
index 8281132..341bd3a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/wmshell/BubblesTest.java
@@ -33,8 +33,6 @@
 
 import static com.google.common.truth.Truth.assertThat;
 
-import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
-
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotNull;
@@ -57,6 +55,8 @@
 import static org.mockito.Mockito.verifyNoMoreInteractions;
 import static org.mockito.Mockito.when;
 
+import static kotlinx.coroutines.flow.StateFlowKt.MutableStateFlow;
+
 import android.app.ActivityManager;
 import android.app.IActivityManager;
 import android.app.INotificationManager;
@@ -464,8 +464,8 @@
         mZenModeConfig.suppressedVisualEffects = 0;
         when(mZenModeController.getConfig()).thenReturn(mZenModeConfig);
 
-        mSysUiState = new SysUiState(mDisplayTracker, mKosmos.getSceneContainerPlugin());
-        mSysUiState.addCallback(sysUiFlags -> {
+        mSysUiState = mKosmos.getSysuiState();
+        mSysUiState.addCallback((sysUiFlags, displayId) -> {
             mSysUiStateBubblesManageMenuExpanded =
                     (sysUiFlags
                             & QuickStepContract.SYSUI_STATE_BUBBLES_MANAGE_MENU_EXPANDED) != 0;
@@ -624,7 +624,8 @@
                     TAG,
                     String.format("waiting for animations to complete. attempt %d", retryCount));
             // post a message to the looper and wait for it to be processed
-            mTestableLooper.runWithLooper(() -> {});
+            mTestableLooper.runWithLooper(() -> {
+            });
             retryCount++;
         }
         mTestableLooper.processAllMessages();
@@ -2996,9 +2997,11 @@
         }
 
         @Override
-        public void onDragItemOverBubbleBarDragZone(@NonNull BubbleBarLocation location) {}
+        public void onDragItemOverBubbleBarDragZone(@NonNull BubbleBarLocation location) {
+        }
 
         @Override
-        public void onItemDraggedOutsideBubbleBarDropZone() {}
+        public void onItemDraggedOutsideBubbleBarDropZone() {
+        }
     }
 }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/tests/utils/src/android/net/ConnectivityManagerKosmos.kt
similarity index 69%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/tests/utils/src/android/net/ConnectivityManagerKosmos.kt
index 9b7cd70..516053d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/tests/utils/src/android/net/ConnectivityManagerKosmos.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,8 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package android.net
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.util.mockito.mockFixture
+
+var Kosmos.connectivityManager: ConnectivityManager by mockFixture()
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorKosmos.kt
index e0c0fbd..bc8e62c 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/AudioSharingInteractorKosmos.kt
@@ -26,6 +26,7 @@
             applicationContext,
             localBluetoothManager,
             bluetoothTileDialogAudioSharingRepository,
+            bluetoothTileDialogLogger,
             testDispatcher,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/FakeAudioSharingRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/FakeAudioSharingRepository.kt
index c744eac..0f6f191 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/FakeAudioSharingRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/bluetooth/qsdialog/FakeAudioSharingRepository.kt
@@ -28,7 +28,7 @@
 
     private val mutableInAudioSharing: MutableStateFlow<Boolean> = MutableStateFlow(false)
 
-    private val mutableAudioSourceStateUpdate = MutableSharedFlow<Unit>()
+    private val mutableAudioSourceStateUpdate = MutableSharedFlow<Unit>(replay = 1)
 
     var sourceAdded: Boolean = false
         private set
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/development/domain/interactor/BuildNumberInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/development/domain/interactor/BuildNumberInteractorKosmos.kt
index aa4dd18..74d53b0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/development/domain/interactor/BuildNumberInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/development/domain/interactor/BuildNumberInteractorKosmos.kt
@@ -20,6 +20,7 @@
 import android.content.res.mainResources
 import com.android.systemui.development.data.repository.developmentSettingRepository
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.user.data.repository.userRepository
 
@@ -31,5 +32,6 @@
             userRepository,
             { clipboardManager },
             testDispatcher,
+            applicationCoroutineScope,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
index d6f0e06..663a853 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/FakeDisplayRepository.kt
@@ -53,6 +53,7 @@
         MutableSharedFlow<DisplayRepository.PendingDisplay?>(replay = 1)
     private val displayAdditionEventFlow = MutableSharedFlow<Display?>(replay = 0)
     private val displayRemovalEventFlow = MutableSharedFlow<Int>(replay = 0)
+    private val displayIdsWithSystemDecorationsFlow = MutableStateFlow<Set<Int>>(emptySet())
 
     suspend fun addDisplay(displayId: Int, type: Int = Display.TYPE_EXTERNAL) {
         addDisplay(display(type, id = displayId))
@@ -62,10 +63,19 @@
         displays.forEach { addDisplay(it) }
     }
 
+    suspend operator fun plusAssign(display: Display) {
+        addDisplay(display)
+    }
+
+    suspend operator fun minusAssign(displayId: Int) {
+        removeDisplay(displayId)
+    }
+
     suspend fun addDisplay(display: Display) {
         flow.value += display
         displayIdFlow.value += display.displayId
         displayAdditionEventFlow.emit(display)
+        displayIdsWithSystemDecorationsFlow.value += display.displayId
     }
 
     suspend fun removeDisplay(displayId: Int) {
@@ -74,6 +84,16 @@
         displayRemovalEventFlow.emit(displayId)
     }
 
+    suspend fun triggerAddDisplaySystemDecorationEvent(displayId: Int) {
+        displayIdsWithSystemDecorationsFlow.value += displayId
+        displayIdsWithSystemDecorationsFlow.emit(displayIdsWithSystemDecorationsFlow.value)
+    }
+
+    suspend fun triggerRemoveSystemDecorationEvent(displayId: Int) {
+        displayIdsWithSystemDecorationsFlow.value -= displayId
+        displayIdsWithSystemDecorationsFlow.emit(displayIdsWithSystemDecorationsFlow.value)
+    }
+
     /** Emits [value] as [displayAdditionEvent] flow value. */
     suspend fun emit(value: Display?) = displayAdditionEventFlow.emit(value)
 
@@ -104,7 +124,8 @@
     private val _displayChangeEvent = MutableSharedFlow<Int>(replay = 1)
     override val displayChangeEvent: Flow<Int> = _displayChangeEvent
 
-    override val displayIdsWithSystemDecorations: StateFlow<Set<Int>> = MutableStateFlow(emptySet())
+    override val displayIdsWithSystemDecorations: StateFlow<Set<Int>> =
+        displayIdsWithSystemDecorationsFlow
 
     suspend fun emitDisplayChangeEvent(displayId: Int) = _displayChangeEvent.emit(displayId)
 
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt
index e379726..aa23aa3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/display/data/repository/PerDisplayStoreKosmos.kt
@@ -16,8 +16,10 @@
 
 package com.android.systemui.display.data.repository
 
+import com.android.systemui.dump.dumpManager
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
 import kotlinx.coroutines.CoroutineScope
 
 class FakePerDisplayStore(
@@ -47,3 +49,30 @@
             displayRepository = displayRepository,
         )
     }
+
+class FakePerDisplayInstanceProviderWithTeardown :
+    PerDisplayInstanceProviderWithTeardown<TestPerDisplayInstance> {
+    val destroyed = mutableListOf<TestPerDisplayInstance>()
+
+    override fun destroyInstance(instance: TestPerDisplayInstance) {
+        destroyed += instance
+    }
+
+    override fun createInstance(displayId: Int): TestPerDisplayInstance? {
+        return TestPerDisplayInstance(displayId)
+    }
+}
+
+val Kosmos.fakePerDisplayInstanceProviderWithTeardown by
+    Kosmos.Fixture { FakePerDisplayInstanceProviderWithTeardown() }
+
+val Kosmos.fakePerDisplayInstanceRepository by
+    Kosmos.Fixture {
+        PerDisplayInstanceRepositoryImpl(
+            debugName = "fakePerDisplayInstanceRepository",
+            instanceProvider = fakePerDisplayInstanceProviderWithTeardown,
+            testScope.backgroundScope,
+            displayRepository,
+            dumpManager,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kairos/CollectLastValue.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kairos/CollectLastValue.kt
new file mode 100644
index 0000000..927209f
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kairos/CollectLastValue.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.
+ */
+
+@file:OptIn(ExperimentalCoroutinesApi::class)
+
+package com.android.systemui.kairos
+
+import com.android.systemui.coroutines.collectLastValue
+import kotlin.properties.ReadOnlyProperty
+import kotlin.reflect.KProperty
+import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
+
+/**
+ * Collect [state] in a new [Job] and return a getter for the collection of values collected.
+ *
+ * ```
+ * fun myTest() = runTest {
+ *   // ...
+ *   val values by collectValues(underTest.flow)
+ *   assertThat(values).isEqualTo(listOf(expected1, expected2, ...))
+ * }
+ * ```
+ */
+@ExperimentalKairosApi
+fun <T> TestScope.collectLastValue(state: State<T>, kairosNetwork: KairosNetwork): KairosValue<T?> {
+    var value: T? = null
+    backgroundScope.launch { kairosNetwork.activateSpec { state.observe { value = it } } }
+    return KairosValueImpl {
+        runCurrent()
+        value
+    }
+}
+
+/**
+ * Collect [flow] in a new [Job] and return a getter for the collection of values collected.
+ *
+ * ```
+ * fun myTest() = runTest {
+ *   // ...
+ *   val values by collectValues(underTest.flow)
+ *   assertThat(values).isEqualTo(listOf(expected1, expected2, ...))
+ * }
+ * ```
+ */
+@ExperimentalKairosApi
+fun <T> TestScope.collectLastValue(flow: Events<T>, kairosNetwork: KairosNetwork): KairosValue<T?> {
+    var value: T? = null
+    backgroundScope.launch { kairosNetwork.activateSpec { flow.observe { value = it } } }
+    return KairosValueImpl {
+        runCurrent()
+        value
+    }
+}
+
+/**
+ * Collect [flow] in a new [Job] and return a getter for the collection of values collected.
+ *
+ * ```
+ * fun myTest() = runTest {
+ *   // ...
+ *   val values by collectValues(underTest.flow)
+ *   assertThat(values).isEqualTo(listOf(expected1, expected2, ...))
+ * }
+ * ```
+ */
+@ExperimentalKairosApi
+fun <T> TestScope.collectValues(
+    flow: Events<T>,
+    kairosNetwork: KairosNetwork,
+): KairosValue<List<T>> {
+    val values = mutableListOf<T>()
+    backgroundScope.launch { kairosNetwork.activateSpec { flow.observe { values.add(it) } } }
+    return KairosValueImpl {
+        runCurrent()
+        values.toList()
+    }
+}
+
+/** @see collectLastValue */
+interface KairosValue<T> : ReadOnlyProperty<Any?, T> {
+    val value: T
+}
+
+private class KairosValueImpl<T>(private val block: () -> T) : KairosValue<T> {
+    override val value: T
+        get() = block()
+
+    override fun getValue(thisRef: Any?, property: KProperty<*>): T = value
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kairos/KairosKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kairos/KairosKosmos.kt
new file mode 100644
index 0000000..d7f2041
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kairos/KairosKosmos.kt
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.kairos
+
+import com.android.systemui.KairosActivatable
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.applicationCoroutineScope
+import com.android.systemui.kosmos.testScope
+import kotlin.time.Duration
+import kotlin.time.Duration.Companion.seconds
+import kotlinx.coroutines.launch
+import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runTest
+
+@ExperimentalKairosApi
+val Kosmos.kairos: KairosNetwork by Fixture { applicationCoroutineScope.launchKairosNetwork() }
+
+@ExperimentalKairosApi
+fun Kosmos.activateKairosActivatable(activatable: KairosActivatable) {
+    applicationCoroutineScope.launch { kairos.activateSpec { activatable.run { activate() } } }
+}
+
+@ExperimentalKairosApi
+fun <T : KairosActivatable> ActivatedKairosFixture(block: Kosmos.() -> T) = Fixture {
+    block().also { activateKairosActivatable(it) }
+}
+
+@ExperimentalKairosApi
+fun Kosmos.runKairosTest(timeout: Duration = 5.seconds, block: suspend KairosTestScope.() -> Unit) =
+    testScope.runTest(timeout) { KairosTestScopeImpl(this@runKairosTest, this, kairos).block() }
+
+@ExperimentalKairosApi
+interface KairosTestScope : Kosmos {
+    fun <T> State<T>.collectLastValue(): KairosValue<T?>
+
+    suspend fun <T> State<T>.sample(): T
+
+    fun <T : KairosActivatable> T.activated(): T
+}
+
+@ExperimentalKairosApi
+private class KairosTestScopeImpl(
+    kosmos: Kosmos,
+    val testScope: TestScope,
+    val kairos: KairosNetwork,
+) : KairosTestScope, Kosmos by kosmos {
+    override fun <T> State<T>.collectLastValue(): KairosValue<T?> =
+        testScope.collectLastValue(this@collectLastValue, kairos)
+
+    override suspend fun <T> State<T>.sample(): T = kairos.transact { sample() }
+
+    override fun <T : KairosActivatable> T.activated(): T =
+        this.also { activateKairosActivatable(it) }
+}
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerKosmos.kt
similarity index 61%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerKosmos.kt
index 9b7cd70..6fd7ef31 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyevent/domain/interactor/SysUIKeyEventHandlerKosmos.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,8 +13,11 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.keyevent.domain.interactor
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import com.android.systemui.kosmos.Kosmos
+import org.mockito.kotlin.mock
+
+var Kosmos.mockSysUIKeyEventHandler by Kosmos.Fixture { mock<SysUIKeyEventHandler>() }
+var Kosmos.sysUIKeyEventHandler by Kosmos.Fixture { mockSysUIKeyEventHandler }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt
index 697e7b9..3f3c3c0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/ui/binder/AlternateBouncerViewBinderKosmos.kt
@@ -19,6 +19,7 @@
 import android.content.applicationContext
 import android.view.mockedLayoutInflater
 import android.view.windowManager
+import com.android.systemui.accessibility.domain.interactor.accessibilityInteractor
 import com.android.systemui.biometrics.domain.interactor.fingerprintPropertyInteractor
 import com.android.systemui.biometrics.domain.interactor.udfpsOverlayInteractor
 import com.android.systemui.common.ui.domain.interactor.configurationInteractor
@@ -37,6 +38,7 @@
 import com.android.systemui.log.logcatLogBuffer
 import com.android.systemui.power.domain.interactor.powerInteractor
 import com.android.systemui.statusbar.gesture.TapGestureDetector
+import com.android.systemui.statusbar.phone.statusBarKeyguardViewManager
 import com.android.systemui.util.mockito.mock
 
 val Kosmos.alternateBouncerViewBinder by
@@ -76,5 +78,7 @@
             fingerprintPropertyInteractor = fingerprintPropertyInteractor,
             udfpsOverlayInteractor = udfpsOverlayInteractor,
             alternateBouncerViewModel = alternateBouncerViewModel,
+            statusBarKeyguardViewManager = statusBarKeyguardViewManager,
+            accessibilityInteractor = accessibilityInteractor,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
index dff9f3a..623989e 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/kosmos/KosmosJavaAdapter.kt
@@ -53,6 +53,8 @@
 import com.android.systemui.keyguard.ui.viewmodel.glanceableHubToLockscreenTransitionViewModel
 import com.android.systemui.keyguard.ui.viewmodel.lockscreenToGlanceableHubTransitionViewModel
 import com.android.systemui.model.sceneContainerPlugin
+import com.android.systemui.model.sysUIStateDispatcher
+import com.android.systemui.model.sysUiState
 import com.android.systemui.plugins.statusbar.statusBarStateController
 import com.android.systemui.power.data.repository.fakePowerRepository
 import com.android.systemui.power.domain.interactor.powerInteractor
@@ -64,6 +66,8 @@
 import com.android.systemui.scene.shared.model.sceneDataSource
 import com.android.systemui.scene.ui.view.mockWindowRootViewProvider
 import com.android.systemui.settings.brightness.data.repository.brightnessMirrorShowingRepository
+import com.android.systemui.settings.displayTracker
+import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository
 import com.android.systemui.shade.data.repository.shadeRepository
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.shade.domain.interactor.shadeLayoutParams
@@ -198,4 +202,8 @@
     val fakeDisableFlagsRepository by lazy { kosmos.fakeDisableFlagsRepository }
     val mockWindowRootViewProvider by lazy { kosmos.mockWindowRootViewProvider }
     val windowRootViewBlurInteractor by lazy { kosmos.windowRootViewBlurInteractor }
+    val sysuiState by lazy { kosmos.sysUiState }
+    val displayTracker by lazy { kosmos.displayTracker }
+    val fakeShadeDisplaysRepository by lazy { kosmos.fakeShadeDisplaysRepository }
+    val sysUIStateDispatcher by lazy { kosmos.sysUIStateDispatcher }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaRecommendationsInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaRecommendationsInteractorKosmos.kt
deleted file mode 100644
index 1edd405..0000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/domain/pipeline/interactor/MediaRecommendationsInteractorKosmos.kt
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.controls.domain.pipeline.interactor
-
-import android.content.applicationContext
-import com.android.systemui.broadcast.broadcastSender
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.applicationCoroutineScope
-import com.android.systemui.media.controls.data.repository.mediaFilterRepository
-import com.android.systemui.media.controls.domain.pipeline.mediaDataProcessor
-import com.android.systemui.plugins.activityStarter
-
-val Kosmos.mediaRecommendationsInteractor by
-    Kosmos.Fixture {
-        MediaRecommendationsInteractor(
-            applicationScope = applicationCoroutineScope,
-            applicationContext = applicationContext,
-            repository = mediaFilterRepository,
-            mediaDataProcessor = mediaDataProcessor,
-            broadcastSender = broadcastSender,
-            activityStarter = activityStarter,
-        )
-    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelKosmos.kt
index 5e6434d..976b404 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaCarouselViewModelKosmos.kt
@@ -37,7 +37,6 @@
             visualStabilityProvider = visualStabilityProvider,
             interactor = mediaCarouselInteractor,
             controlInteractorFactory = mediaControlInteractorFactory,
-            recommendationsViewModel = mediaRecommendationsViewModel,
             logger = mediaUiEventLogger,
             mediaLogger = mediaLogger,
         )
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModelKosmos.kt
deleted file mode 100644
index 34a5277..0000000
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/media/controls/ui/viewmodel/MediaRecommendationsViewModelKosmos.kt
+++ /dev/null
@@ -1,33 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.systemui.media.controls.ui.viewmodel
-
-import android.content.applicationContext
-import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.testDispatcher
-import com.android.systemui.media.controls.domain.pipeline.interactor.mediaRecommendationsInteractor
-import com.android.systemui.media.controls.util.mediaUiEventLogger
-
-val Kosmos.mediaRecommendationsViewModel by
-    Kosmos.Fixture {
-        MediaRecommendationsViewModel(
-            applicationContext = applicationContext,
-            backgroundDispatcher = testDispatcher,
-            interactor = mediaRecommendationsInteractor,
-            logger = mediaUiEventLogger,
-        )
-    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/model/SceneContainerPluginKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/model/SceneContainerPluginKosmos.kt
index d19dfe8..79506f9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/model/SceneContainerPluginKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/model/SceneContainerPluginKosmos.kt
@@ -20,10 +20,12 @@
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.data.repository.fakeShadeDisplaysRepository
 
 val Kosmos.sceneContainerPlugin by Fixture {
     SceneContainerPlugin(
         sceneInteractor = { sceneInteractor },
         occlusionInteractor = { sceneContainerOcclusionInteractor },
+        shadeDisplaysRepository = { fakeShadeDisplaysRepository },
     )
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/model/SysUiStateKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/model/SysUiStateKosmos.kt
index 6ddf633..11bd4c7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/model/SysUiStateKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/model/SysUiStateKosmos.kt
@@ -16,16 +16,42 @@
 
 package com.android.systemui.model
 
+import android.view.Display
+import com.android.systemui.common.domain.interactor.SysUIStateDisplaysInteractor
+import com.android.systemui.display.data.repository.FakePerDisplayRepository
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.dump.dumpManager
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.Kosmos.Fixture
-import com.android.systemui.settings.displayTracker
 import org.mockito.Mockito.spy
 
-val Kosmos.sysUiState by Fixture {
-    spy(
-        SysUiState(
-            displayTracker,
+val Kosmos.sysUiState by Fixture { sysUiStateFactory.create(Display.DEFAULT_DISPLAY) }
+val Kosmos.sysUIStateDispatcher by Fixture { SysUIStateDispatcher() }
+
+val Kosmos.sysUiStateFactory by Fixture {
+    object : SysUiStateImpl.Factory {
+        override fun create(displayId: Int): SysUiStateImpl {
+            return spy(
+                SysUiStateImpl(displayId, sceneContainerPlugin, dumpManager, sysUIStateDispatcher)
+            )
+        }
+    }
+}
+
+val Kosmos.fakeSysUIStatePerDisplayRepository by Fixture { FakePerDisplayRepository<SysUiState>() }
+
+val Kosmos.sysuiStateInteractor by Fixture {
+    SysUIStateDisplaysInteractor(fakeSysUIStatePerDisplayRepository, displayRepository)
+}
+
+val Kosmos.sysUiStateOverrideFactory by Fixture {
+    { displayId: Int ->
+        SysUIStateOverride(
+            displayId,
             sceneContainerPlugin,
+            dumpManager,
+            sysUiState,
+            sysUIStateDispatcher,
         )
-    )
+    }
 }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt
index 4330770..4618dc7 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/qs/footer/FooterActionsTestUtils.kt
@@ -58,7 +58,7 @@
 import com.android.systemui.util.settings.FakeGlobalSettings
 import com.android.systemui.util.settings.GlobalSettings
 import kotlinx.coroutines.CoroutineDispatcher
-import kotlinx.coroutines.flow.flowOf
+import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestCoroutineScheduler
 
@@ -94,7 +94,7 @@
         return createFooterActionsViewModel(
             context,
             footerActionsInteractor,
-            flowOf(shadeMode),
+            MutableStateFlow(shadeMode),
             falsingManager,
             globalActionsDialogLite,
             mockActivityStarter,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/ui/view/WindowRootViewKeyEventHandlerKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/ui/view/WindowRootViewKeyEventHandlerKosmos.kt
new file mode 100644
index 0000000..9369057
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/ui/view/WindowRootViewKeyEventHandlerKosmos.kt
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.scene.ui.view
+
+import com.android.systemui.classifier.falsingCollector
+import com.android.systemui.keyevent.domain.interactor.sysUIKeyEventHandler
+import com.android.systemui.kosmos.Kosmos
+
+val Kosmos.windowRootViewKeyEventHandler by
+    Kosmos.Fixture {
+        WindowRootViewKeyEventHandler(
+            sysUIKeyEventHandlerLazy = { sysUIKeyEventHandler },
+            falsingCollector = falsingCollector,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarOrchestratorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarOrchestratorKosmos.kt
index 9776fd9..66a1751 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarOrchestratorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/core/StatusBarOrchestratorKosmos.kt
@@ -17,7 +17,6 @@
 package com.android.systemui.statusbar.core
 
 import android.content.testableContext
-import android.view.mockIWindowManager
 import com.android.systemui.bouncer.domain.interactor.primaryBouncerInteractor
 import com.android.systemui.display.data.repository.displayRepository
 import com.android.systemui.display.data.repository.displayScopeRepository
@@ -94,6 +93,5 @@
             statusBarInitializerStore,
             privacyDotWindowControllerStore,
             lightBarControllerStore,
-            mockIWindowManager,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayStoreKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayStoreKosmos.kt
new file mode 100644
index 0000000..0db8ee8
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/data/repository/StatusBarPerDisplayStoreKosmos.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.data.repository
+
+import com.android.systemui.display.data.repository.DisplayRepository
+import com.android.systemui.display.data.repository.displayRepository
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.applicationCoroutineScope
+import kotlinx.coroutines.CoroutineScope
+
+class FakeStatusBarPerDisplayStore(
+    backgroundApplicationScope: CoroutineScope,
+    displayRepository: DisplayRepository,
+) :
+    StatusBarPerDisplayStoreImpl<TestPerDisplayInstance>(
+        backgroundApplicationScope,
+        displayRepository,
+    ) {
+
+    val removalActions = mutableListOf<TestPerDisplayInstance>()
+
+    override fun createInstanceForDisplay(displayId: Int): TestPerDisplayInstance {
+        return TestPerDisplayInstance(displayId)
+    }
+
+    override val instanceClass = TestPerDisplayInstance::class.java
+
+    override suspend fun onDisplayRemovalAction(instance: TestPerDisplayInstance) {
+        removalActions += instance
+    }
+}
+
+data class TestPerDisplayInstance(val displayId: Int)
+
+val Kosmos.fakeStatusBarPerDisplayStore by
+    Kosmos.Fixture {
+        FakeStatusBarPerDisplayStore(
+            backgroundApplicationScope = applicationCoroutineScope,
+            displayRepository = displayRepository,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelKosmos.kt
index 7145907..39391d0 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/media/ui/viewmodel/MediaControlChipViewModelKosmos.kt
@@ -18,14 +18,19 @@
 
 import android.content.testableContext
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.statusbar.featurepods.media.domain.interactor.mediaControlChipInteractor
 
-val Kosmos.mediaControlChipViewModel: MediaControlChipViewModel by
+private val Kosmos.mediaControlChipViewModel: MediaControlChipViewModel by
     Kosmos.Fixture {
         MediaControlChipViewModel(
-            backgroundScope = applicationCoroutineScope,
             applicationContext = testableContext,
             mediaControlChipInteractor = mediaControlChipInteractor,
         )
     }
+
+val Kosmos.mediaControlChipViewModelFactory by
+    Kosmos.Fixture {
+        object : MediaControlChipViewModel.Factory {
+            override fun create(): MediaControlChipViewModel = mediaControlChipViewModel
+        }
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt
index b876095..2a3167cb 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/featurepods/popups/ui/viewmodel/StatusBarPopupChipsViewModelKosmos.kt
@@ -17,10 +17,12 @@
 package com.android.systemui.statusbar.featurepods.popups.ui.viewmodel
 
 import com.android.systemui.kosmos.Kosmos
-import com.android.systemui.statusbar.featurepods.media.ui.viewmodel.mediaControlChipViewModel
+import com.android.systemui.statusbar.featurepods.media.ui.viewmodel.mediaControlChipViewModelFactory
 
 private val Kosmos.statusBarPopupChipsViewModel: StatusBarPopupChipsViewModel by
-    Kosmos.Fixture { StatusBarPopupChipsViewModel(mediaControlChip = mediaControlChipViewModel) }
+    Kosmos.Fixture {
+        StatusBarPopupChipsViewModel(mediaControlChipFactory = mediaControlChipViewModelFactory)
+    }
 
 val Kosmos.statusBarPopupChipsViewModelFactory by
     Kosmos.Fixture {
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationActivityStarterKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationActivityStarterKosmos.kt
index c337ac2..8e98fe3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationActivityStarterKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/NotificationActivityStarterKosmos.kt
@@ -18,6 +18,10 @@
 
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.statusbar.phone.statusBarNotificationActivityStarter
+import org.mockito.kotlin.mock
 
 var Kosmos.notificationActivityStarter: NotificationActivityStarter by
     Kosmos.Fixture { statusBarNotificationActivityStarter }
+
+var Kosmos.mockNotificationActivityStarter: NotificationActivityStarter by
+Kosmos.Fixture { mock<NotificationActivityStarter>() }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerKosmos.kt
similarity index 66%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerKosmos.kt
index 9b7cd70..f3cdabb 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/collection/render/GroupMembershipManagerKosmos.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,8 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.statusbar.notification.collection.render
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import com.android.systemui.kosmos.Kosmos
+import org.mockito.kotlin.mock
+
+var Kosmos.groupMembershipManager by Kosmos.Fixture { mock<GroupMembershipManager>() }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractorKosmos.kt
similarity index 66%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractorKosmos.kt
index 9b7cd70..c263c5d 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/people/NotificationPersonExtractorKosmos.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open 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,8 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.statusbar.notification.people
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import com.android.systemui.kosmos.Kosmos
+import org.mockito.kotlin.mock
+
+val Kosmos.notificationPersonExtractor by Kosmos.Fixture { mock<NotificationPersonExtractor>() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierKosmos.kt
new file mode 100644
index 0000000..20982eb
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/people/PeopleNotificationIdentifierKosmos.kt
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.people
+
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.notification.collection.render.groupMembershipManager
+
+val Kosmos.peopleNotificationIdentifier by
+    Kosmos.Fixture {
+        PeopleNotificationIdentifierImpl(notificationPersonExtractor, groupMembershipManager)
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
index da879d9..2b3158d 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/promoted/PromotedNotificationContentExtractorKosmos.kt
@@ -39,7 +39,8 @@
         promotedNotificationContentExtractor.extractContent(
             entry,
             Notification.Builder.recoverBuilder(applicationContext, entry.sbn.notification),
-            RowImageInflater.newInstance(null).useForContentModel(),
+            RowImageInflater.newInstance(previousIndex = null, reinflating = false)
+                .useForContentModel(),
         )
     entry.promotedNotificationContentModel =
         requireNotNull(extractedContent) { "extractContent returned null" }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt
new file mode 100644
index 0000000..e99f61e
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/EntryAdapterFactoryKosmos.kt
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.row
+
+import com.android.internal.logging.metricsLogger
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl
+import com.android.systemui.statusbar.notification.collection.coordinator.visualStabilityCoordinator
+import com.android.systemui.statusbar.notification.mockNotificationActivityStarter
+import com.android.systemui.statusbar.notification.people.peopleNotificationIdentifier
+import com.android.systemui.statusbar.notification.row.icon.notificationIconStyleProvider
+
+val Kosmos.entryAdapterFactory by
+Kosmos.Fixture {
+    EntryAdapterFactoryImpl(
+        mockNotificationActivityStarter,
+        metricsLogger,
+        peopleNotificationIdentifier,
+        notificationIconStyleProvider,
+        visualStabilityCoordinator,
+    )
+}
\ No newline at end of file
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
index 771e1a5..ff4fbf9 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/row/ExpandableNotificationRowBuilder.kt
@@ -53,8 +53,11 @@
 import com.android.systemui.statusbar.notification.ColorUpdateLogger
 import com.android.systemui.statusbar.notification.ConversationNotificationManager
 import com.android.systemui.statusbar.notification.ConversationNotificationProcessor
+import com.android.systemui.statusbar.notification.NotificationActivityStarter
+import com.android.systemui.statusbar.notification.collection.EntryAdapterFactoryImpl
 import com.android.systemui.statusbar.notification.collection.NotificationEntry
 import com.android.systemui.statusbar.notification.collection.NotificationEntryBuilder
+import com.android.systemui.statusbar.notification.collection.coordinator.VisualStabilityCoordinator
 import com.android.systemui.statusbar.notification.collection.notifcollection.CommonNotifCollection
 import com.android.systemui.statusbar.notification.collection.notifcollection.NotifCollectionListener
 import com.android.systemui.statusbar.notification.collection.provider.NotificationDismissibilityProvider
@@ -76,6 +79,7 @@
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.FLAG_CONTENT_VIEW_HEADS_UP
 import com.android.systemui.statusbar.notification.row.NotificationRowContentBinder.InflationFlag
 import com.android.systemui.statusbar.notification.row.icon.AppIconProviderImpl
+import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProvider
 import com.android.systemui.statusbar.notification.row.icon.NotificationIconStyleProviderImpl
 import com.android.systemui.statusbar.notification.row.icon.NotificationRowIconViewInflaterFactory
 import com.android.systemui.statusbar.notification.row.shared.NotificationRowContentBinderRefactor
@@ -364,11 +368,22 @@
             )
         val row = rowInflaterTask.inflateSynchronously(context, null, entry)
 
+        val entryAdapter =
+            EntryAdapterFactoryImpl(
+                    Mockito.mock(NotificationActivityStarter::class.java),
+                    Mockito.mock(MetricsLogger::class.java),
+                    Mockito.mock(PeopleNotificationIdentifier::class.java),
+                    Mockito.mock(NotificationIconStyleProvider::class.java),
+                    Mockito.mock(VisualStabilityCoordinator::class.java),
+                )
+                .create(entry)
+
         entry.row = row
         mIconManager.createIcons(entry)
         mBindPipelineEntryListener.onEntryInit(entry)
         mBindPipeline.manageRow(entry, row)
         row.initialize(
+            entryAdapter,
             entry,
             Mockito.mock(RemoteInputViewSubcomponent.Factory::class.java, STUB_ONLY),
             APP_NAME,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
index fbc2a21..219ecbf 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationListViewModelKosmos.kt
@@ -21,6 +21,7 @@
 import com.android.systemui.kosmos.Kosmos.Fixture
 import com.android.systemui.kosmos.testDispatcher
 import com.android.systemui.shade.domain.interactor.shadeInteractor
+import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
 import com.android.systemui.statusbar.domain.interactor.remoteInputInteractor
 import com.android.systemui.statusbar.notification.domain.interactor.activeNotificationsInteractor
 import com.android.systemui.statusbar.notification.emptyshade.ui.viewmodel.emptyShadeViewModelFactory
@@ -35,6 +36,7 @@
     NotificationListViewModel(
         notificationShelfViewModel,
         hideListViewModel,
+        ongoingActivityChipsViewModel,
         footerViewModelFactory,
         emptyShadeViewModelFactory,
         Optional.of(notificationListLoggerViewModel),
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinderKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinderKosmos.kt
index 6a995c0..2c5aed4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinderKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/notification/ui/viewbinder/HeadsUpNotificationViewBinderKosmos.kt
@@ -17,7 +17,13 @@
 package com.android.systemui.statusbar.notification.ui.viewbinder
 
 import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
 import com.android.systemui.statusbar.notification.stack.ui.viewmodel.notificationListViewModel
 
 val Kosmos.headsUpNotificationViewBinder by
-    Kosmos.Fixture { HeadsUpNotificationViewBinder(viewModel = notificationListViewModel) }
+    Kosmos.Fixture {
+        HeadsUpNotificationViewBinder(
+            viewModel = notificationListViewModel,
+            ongoingActivityChipsViewModel = ongoingActivityChipsViewModel,
+        )
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigFakes.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigFakes.kt
new file mode 100644
index 0000000..13b01634
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/model/SystemUiCarrierConfigFakes.kt
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.model
+
+import android.os.PersistableBundle
+import android.telephony.CarrierConfigManager
+
+/**
+ * In order to keep us from having to update every place that might want to create a config, make
+ * sure to add new keys here
+ */
+fun testCarrierConfig() =
+    PersistableBundle().also {
+        it.putBoolean(CarrierConfigManager.KEY_INFLATE_SIGNAL_STRENGTH_BOOL, false)
+        it.putBoolean(CarrierConfigManager.KEY_SHOW_OPERATOR_NAME_IN_STATUSBAR_BOOL, false)
+        it.putBoolean(CarrierConfigManager.KEY_SHOW_5G_SLICE_ICON_BOOL, true)
+    }
+
+/** Override the default config with the given (key, value) pair */
+fun testCarrierConfigWithOverride(key: String, override: Boolean): PersistableBundle =
+    testCarrierConfig().also { it.putBoolean(key, override) }
+
+/** Override any number of configs from the default */
+fun testCarrierConfigWithOverrides(vararg overrides: Pair<String, Boolean>) =
+    testCarrierConfig().also { config ->
+        overrides.forEach { (key, value) -> config.putBoolean(key, value) }
+    }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepositoryKairos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepositoryKairos.kt
new file mode 100644
index 0000000..8cf3ee8
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionRepositoryKairos.kt
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosNetwork
+import com.android.systemui.kairos.MutableState
+import com.android.systemui.kairos.State
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.DataConnectionState
+import com.android.systemui.statusbar.pipeline.mobile.data.model.NetworkNameModel
+import com.android.systemui.statusbar.pipeline.mobile.data.model.ResolvedNetworkType
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionRepository.Companion.DEFAULT_NETWORK_NAME
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionRepository.Companion.DEFAULT_NUM_LEVELS
+import com.android.systemui.statusbar.pipeline.shared.data.model.DataActivityModel
+
+@ExperimentalKairosApi
+class FakeMobileConnectionRepositoryKairos(
+    override val subId: Int,
+    kairos: KairosNetwork,
+    override val tableLogBuffer: TableLogBuffer,
+) : MobileConnectionRepositoryKairos {
+    override val carrierId = MutableState(kairos, 0)
+    override val inflateSignalStrength = MutableState(kairos, false)
+    override val allowNetworkSliceIndicator = MutableState(kairos, true)
+    override val isEmergencyOnly = MutableState(kairos, false)
+    override val isRoaming = MutableState(kairos, false)
+    override val operatorAlphaShort = MutableState<String?>(kairos, null)
+    override val isInService = MutableState(kairos, false)
+    override val isNonTerrestrial = MutableState(kairos, false)
+    override val isGsm = MutableState(kairos, false)
+    override val cdmaLevel = MutableState(kairos, 0)
+    override val primaryLevel = MutableState(kairos, 0)
+    override val satelliteLevel = MutableState(kairos, 0)
+    override val dataConnectionState = MutableState(kairos, DataConnectionState.Disconnected)
+    override val dataActivityDirection =
+        MutableState(kairos, DataActivityModel(hasActivityIn = false, hasActivityOut = false))
+    override val carrierNetworkChangeActive = MutableState(kairos, false)
+    override val resolvedNetworkType =
+        MutableState<ResolvedNetworkType>(kairos, ResolvedNetworkType.UnknownNetworkType)
+    override val numberOfLevels = MutableState(kairos, DEFAULT_NUM_LEVELS)
+    override val dataEnabled = MutableState(kairos, true)
+    override val cdmaRoaming = MutableState(kairos, false)
+    override val networkName =
+        MutableState<NetworkNameModel>(kairos, NetworkNameModel.Default(DEFAULT_NETWORK_NAME))
+    override val carrierName =
+        MutableState<NetworkNameModel>(kairos, NetworkNameModel.Default(DEFAULT_NETWORK_NAME))
+    override val isAllowedDuringAirplaneMode = MutableState(kairos, false)
+    override val hasPrioritizedNetworkCapabilities = MutableState(kairos, false)
+    override val isInEcmMode: State<Boolean> = MutableState(kairos, false)
+
+    /**
+     * Set [primaryLevel] and [cdmaLevel]. Convenient when you don't care about the connection type
+     */
+    fun setAllLevels(level: Int) {
+        cdmaLevel.setValue(level)
+        primaryLevel.setValue(level)
+    }
+
+    /** Set the correct [resolvedNetworkType] for the given group via its lookup key */
+    fun setNetworkTypeKey(key: String) {
+        resolvedNetworkType.setValue(ResolvedNetworkType.DefaultNetworkType(key))
+    }
+
+    /**
+     * Set both [isRoaming] and [cdmaRoaming] properties, in the event that you don't care about the
+     * connection type
+     */
+    fun setAllRoaming(roaming: Boolean) {
+        isRoaming.setValue(roaming)
+        cdmaRoaming.setValue(roaming)
+    }
+}
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepositoryKairos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepositoryKairos.kt
new file mode 100644
index 0000000..624b2cc
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/FakeMobileConnectionsRepositoryKairos.kt
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import android.telephony.SubscriptionManager.INVALID_SUBSCRIPTION_ID
+import android.telephony.TelephonyDisplayInfo
+import android.telephony.TelephonyManager
+import com.android.settingslib.SignalIcon
+import com.android.settingslib.mobile.MobileMappings
+import com.android.settingslib.mobile.TelephonyIcons
+import com.android.systemui.KairosBuilder
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosNetwork
+import com.android.systemui.kairos.MutableEvents
+import com.android.systemui.kairos.MutableState
+import com.android.systemui.kairos.State
+import com.android.systemui.kairos.asIncremental
+import com.android.systemui.kairos.buildSpec
+import com.android.systemui.kairos.combine
+import com.android.systemui.kairos.map
+import com.android.systemui.kairos.mapValues
+import com.android.systemui.kairosBuilder
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.statusbar.pipeline.mobile.data.model.SubscriptionModel
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeMobileMappingsProxy
+import com.android.systemui.statusbar.pipeline.mobile.util.MobileMappingsProxy
+
+// TODO(b/261632894): remove this in favor of the real impl or DemoMobileConnectionsRepositoryKairos
+@ExperimentalKairosApi
+class FakeMobileConnectionsRepositoryKairos(
+    kairos: KairosNetwork,
+    val tableLogBuffer: TableLogBuffer,
+    mobileMappings: MobileMappingsProxy = FakeMobileMappingsProxy(),
+) : MobileConnectionsRepositoryKairos, KairosBuilder by kairosBuilder() {
+
+    val GSM_KEY = mobileMappings.toIconKey(GSM)
+    val LTE_KEY = mobileMappings.toIconKey(LTE)
+    val UMTS_KEY = mobileMappings.toIconKey(UMTS)
+    val LTE_ADVANCED_KEY = mobileMappings.toIconKeyOverride(LTE_ADVANCED_PRO)
+
+    /**
+     * To avoid a reliance on [MobileMappings], we'll build a simpler map from network type to
+     * mobile icon. See TelephonyManager.NETWORK_TYPES for a list of types and [TelephonyIcons] for
+     * the exhaustive set of icons
+     */
+    val TEST_MAPPING: Map<String, SignalIcon.MobileIconGroup> =
+        mapOf(
+            GSM_KEY to TelephonyIcons.THREE_G,
+            LTE_KEY to TelephonyIcons.LTE,
+            UMTS_KEY to TelephonyIcons.FOUR_G,
+            LTE_ADVANCED_KEY to TelephonyIcons.NR_5G,
+        )
+
+    override val subscriptions = MutableState(kairos, emptyList<SubscriptionModel>())
+
+    override val mobileConnectionsBySubId = buildIncremental {
+        subscriptions
+            .map { it.associate { sub -> sub.subscriptionId to Unit } }
+            .asIncremental()
+            .mapValues { (subId, _) ->
+                buildSpec {
+                    FakeMobileConnectionRepositoryKairos(subId, kairosNetwork, tableLogBuffer)
+                }
+            }
+            .applyLatestSpecForKey()
+    }
+
+    private val _activeMobileDataSubscriptionId = MutableState<Int?>(kairos, null)
+    override val activeMobileDataSubscriptionId: State<Int?> = _activeMobileDataSubscriptionId
+
+    override val activeMobileDataRepository: State<MobileConnectionRepositoryKairos?> =
+        combine(mobileConnectionsBySubId, activeMobileDataSubscriptionId) { conns, activeSub ->
+            conns[activeSub]
+        }
+
+    override val activeSubChangedInGroupEvent = MutableEvents<Unit>(kairos)
+
+    override val defaultDataSubId = MutableState(kairos, INVALID_SUBSCRIPTION_ID)
+
+    override val mobileIsDefault = MutableState(kairos, false)
+
+    override val hasCarrierMergedConnection = MutableState(kairos, false)
+
+    override val defaultConnectionIsValidated = MutableState(kairos, false)
+
+    override val defaultDataSubRatConfig = MutableState(kairos, MobileMappings.Config())
+
+    override val defaultMobileIconMapping = MutableState(kairos, TEST_MAPPING)
+
+    override val defaultMobileIconGroup = MutableState(kairos, DEFAULT_ICON)
+
+    override val isDeviceEmergencyCallCapable = MutableState(kairos, false)
+
+    override val isAnySimSecure = MutableState(kairos, false)
+
+    override val isInEcmMode: State<Boolean> = MutableState(kairos, false)
+
+    fun setActiveMobileDataSubscriptionId(subId: Int) {
+        // Simulate the filtering that the repo does
+        if (subId == INVALID_SUBSCRIPTION_ID) {
+            _activeMobileDataSubscriptionId.setValue(null)
+        } else {
+            _activeMobileDataSubscriptionId.setValue(subId)
+        }
+    }
+
+    companion object {
+        val DEFAULT_ICON = TelephonyIcons.G
+
+        // Use [MobileMappings] to define some simple definitions
+        const val GSM = TelephonyManager.NETWORK_TYPE_GSM
+        const val LTE = TelephonyManager.NETWORK_TYPE_LTE
+        const val UMTS = TelephonyManager.NETWORK_TYPE_UMTS
+        const val LTE_ADVANCED_PRO = TelephonyDisplayInfo.OVERRIDE_NETWORK_TYPE_LTE_ADVANCED_PRO
+    }
+}
+
+@ExperimentalKairosApi
+val MobileConnectionsRepositoryKairos.fake
+    get() = this as FakeMobileConnectionsRepositoryKairos
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileDataRepositoryKairosKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileDataRepositoryKairosKosmos.kt
new file mode 100644
index 0000000..f57cf99
--- /dev/null
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/data/repository/MobileDataRepositoryKairosKosmos.kt
@@ -0,0 +1,149 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.statusbar.pipeline.mobile.data.repository
+
+import android.content.applicationContext
+import android.telephony.SubscriptionManager
+import android.telephony.telephonyManager
+import com.android.keyguard.keyguardUpdateMonitor
+import com.android.systemui.broadcast.broadcastDispatcher
+import com.android.systemui.demoModeController
+import com.android.systemui.dump.dumpManager
+import com.android.systemui.kairos.ActivatedKairosFixture
+import com.android.systemui.kairos.ExperimentalKairosApi
+import com.android.systemui.kairos.KairosNetwork
+import com.android.systemui.kairos.MutableEvents
+import com.android.systemui.kairos.buildSpec
+import com.android.systemui.kairos.kairos
+import com.android.systemui.kosmos.Kosmos
+import com.android.systemui.kosmos.Kosmos.Fixture
+import com.android.systemui.kosmos.testDispatcher
+import com.android.systemui.log.table.TableLogBuffer
+import com.android.systemui.log.table.logcatTableLogBuffer
+import com.android.systemui.log.table.tableLogBufferFactory
+import com.android.systemui.statusbar.pipeline.airplane.data.repository.airplaneModeRepository
+import com.android.systemui.statusbar.pipeline.mobile.data.MobileInputLogger
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoMobileConnectionsRepositoryKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.DemoModeMobileConnectionDataSourceKairos
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.demo.model.FakeNetworkEventModel
+import com.android.systemui.statusbar.pipeline.mobile.data.repository.prod.MobileConnectionsRepositoryKairosImpl
+import com.android.systemui.statusbar.pipeline.mobile.util.FakeSubscriptionManagerProxy
+import com.android.systemui.statusbar.pipeline.mobile.util.SubscriptionManagerProxy
+import com.android.systemui.statusbar.pipeline.shared.data.repository.connectivityRepository
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.demo.DemoModeWifiDataSource
+import com.android.systemui.statusbar.pipeline.wifi.data.repository.wifiRepository
+import com.android.systemui.util.mockito.mockFixture
+import org.mockito.kotlin.mock
+
+@ExperimentalKairosApi
+var Kosmos.mobileConnectionsRepositoryKairos: MobileConnectionsRepositoryKairos by Fixture {
+    mobileRepositorySwitcherKairos
+}
+
+@ExperimentalKairosApi
+val Kosmos.fakeMobileConnectionsRepositoryKairos by ActivatedKairosFixture {
+    FakeMobileConnectionsRepositoryKairos(kairos, logcatTableLogBuffer(this), mobileMappingsProxy)
+}
+
+@ExperimentalKairosApi
+val Kosmos.demoMobileConnectionsRepositoryKairos by ActivatedKairosFixture {
+    DemoMobileConnectionsRepositoryKairos(
+        mobileDataSource = demoModeMobileConnectionDataSourceKairos,
+        wifiDataSource = wifiDataSource,
+        context = applicationContext,
+        logFactory = tableLogBufferFactory,
+    )
+}
+
+@ExperimentalKairosApi
+val Kosmos.demoModeMobileConnectionDataSourceKairos:
+    DemoModeMobileConnectionDataSourceKairos by Fixture {
+    FakeDemoModeMobileConnectionDataSourceKairos(kairos)
+}
+
+val Kosmos.wifiDataSource: DemoModeWifiDataSource by mockFixture()
+
+@ExperimentalKairosApi
+class FakeDemoModeMobileConnectionDataSourceKairos(kairos: KairosNetwork) :
+    DemoModeMobileConnectionDataSourceKairos {
+    override val mobileEvents = MutableEvents<FakeNetworkEventModel?>(kairos)
+}
+
+@ExperimentalKairosApi
+val DemoModeMobileConnectionDataSourceKairos.fake
+    get() = this as FakeDemoModeMobileConnectionDataSourceKairos
+
+@ExperimentalKairosApi
+val Kosmos.mobileRepositorySwitcherKairos:
+    MobileRepositorySwitcherKairos by ActivatedKairosFixture {
+    MobileRepositorySwitcherKairos(
+        realRepository = mobileConnectionsRepositoryKairosImpl,
+        demoRepositoryFactory = demoMobileConnectionsRepositoryKairosFactory,
+        demoModeController = demoModeController,
+    )
+}
+
+@ExperimentalKairosApi
+val Kosmos.demoMobileConnectionsRepositoryKairosFactory:
+    DemoMobileConnectionsRepositoryKairos.Factory by Fixture {
+    DemoMobileConnectionsRepositoryKairos.Factory {
+        DemoMobileConnectionsRepositoryKairos(
+            mobileDataSource = demoModeMobileConnectionDataSourceKairos,
+            wifiDataSource = wifiDataSource,
+            context = applicationContext,
+            logFactory = tableLogBufferFactory,
+        )
+    }
+}
+
+@ExperimentalKairosApi
+val Kosmos.mobileConnectionsRepositoryKairosImpl:
+    MobileConnectionsRepositoryKairosImpl by ActivatedKairosFixture {
+    MobileConnectionsRepositoryKairosImpl(
+        connectivityRepository = connectivityRepository,
+        subscriptionManager = subscriptionManager,
+        subscriptionManagerProxy = subscriptionManagerProxy,
+        telephonyManager = telephonyManager,
+        logger = mobileInputLogger,
+        tableLogger = summaryLogger,
+        mobileMappingsProxy = mobileMappingsProxy,
+        broadcastDispatcher = broadcastDispatcher,
+        context = applicationContext,
+        bgDispatcher = testDispatcher,
+        mainDispatcher = testDispatcher,
+        airplaneModeRepository = airplaneModeRepository,
+        wifiRepository = wifiRepository,
+        keyguardUpdateMonitor = keyguardUpdateMonitor,
+        dumpManager = dumpManager,
+        mobileRepoFactory = { mobileConnectionRepositoryKairosFactory },
+    )
+}
+
+val Kosmos.subscriptionManager: SubscriptionManager by mockFixture()
+val Kosmos.mobileInputLogger: MobileInputLogger by mockFixture()
+val Kosmos.summaryLogger: TableLogBuffer by Fixture { logcatTableLogBuffer(this, "summaryLogger") }
+
+@ExperimentalKairosApi
+val Kosmos.mobileConnectionRepositoryKairosFactory by Fixture {
+    MobileConnectionsRepositoryKairosImpl.ConnectionRepoFactory { subId ->
+        buildSpec { FakeMobileConnectionRepositoryKairos(subId, kairos, mock()) }
+    }
+}
+
+val Kosmos.subscriptionManagerProxy: SubscriptionManagerProxy by Fixture {
+    FakeSubscriptionManagerProxy()
+}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt
similarity index 88%
rename from packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt
index a802381..a391c44 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/mobile/util/FakeSubscriptionManagerProxy.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2025 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -23,7 +23,7 @@
 class FakeSubscriptionManagerProxy(
     /** Set the default data subId to be returned in [getDefaultDataSubscriptionId] */
     var defaultDataSubId: Int = INVALID_SUBSCRIPTION_ID,
-    var activeSubscriptionInfo: SubscriptionInfo? = null
+    var activeSubscriptionInfo: SubscriptionInfo? = null,
 ) : SubscriptionManagerProxy {
     override fun getDefaultDataSubscriptionId(): Int = defaultDataSubId
 
@@ -41,3 +41,6 @@
             SubscriptionInfo.Builder().setId(subId).setEmbedded(isEmbedded).build()
     }
 }
+
+val SubscriptionManagerProxy.fake
+    get() = this as FakeSubscriptionManagerProxy
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt
index 00bfa99..bb254a1 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/data/repository/ConnectivityRepositoryKosmos.kt
@@ -18,5 +18,5 @@
 
 import com.android.systemui.kosmos.Kosmos
 
-val Kosmos.connectivityRepository: ConnectivityRepository by
+var Kosmos.connectivityRepository: ConnectivityRepository by
     Kosmos.Fixture { FakeConnectivityRepository() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
index a97c651..5c4deaa 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/shared/ui/viewmodel/HomeStatusBarViewModelKosmos.kt
@@ -25,6 +25,7 @@
 import com.android.systemui.log.table.tableLogBufferFactory
 import com.android.systemui.scene.domain.interactor.sceneContainerOcclusionInteractor
 import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.domain.interactor.shadeDisplaysInteractor
 import com.android.systemui.shade.domain.interactor.shadeInteractor
 import com.android.systemui.statusbar.chips.sharetoapp.ui.viewmodel.shareToAppChipViewModel
 import com.android.systemui.statusbar.chips.ui.viewmodel.ongoingActivityChipsViewModel
@@ -40,29 +41,34 @@
 import com.android.systemui.statusbar.pipeline.shared.domain.interactor.homeStatusBarInteractor
 
 var Kosmos.homeStatusBarViewModel: HomeStatusBarViewModel by
+    Kosmos.Fixture { homeStatusBarViewModelFactory.invoke(testableContext.displayId) }
+var Kosmos.homeStatusBarViewModelFactory: (Int) -> HomeStatusBarViewModel by
     Kosmos.Fixture {
-        HomeStatusBarViewModelImpl(
-            testableContext.displayId,
-            batteryViewModelFactory,
-            tableLogBufferFactory,
-            homeStatusBarInteractor,
-            homeStatusBarIconBlockListInteractor,
-            lightsOutInteractor,
-            activeNotificationsInteractor,
-            darkIconInteractor,
-            headsUpNotificationInteractor,
-            keyguardTransitionInteractor,
-            keyguardInteractor,
-            statusBarOperatorNameViewModel,
-            sceneInteractor,
-            sceneContainerOcclusionInteractor,
-            shadeInteractor,
-            shareToAppChipViewModel,
-            ongoingActivityChipsViewModel,
-            statusBarPopupChipsViewModelFactory,
-            systemStatusEventAnimationInteractor,
-            multiDisplayStatusBarContentInsetsViewModelStore,
-            backgroundScope,
-            testDispatcher,
-        )
+        { displayId ->
+            HomeStatusBarViewModelImpl(
+                displayId,
+                batteryViewModelFactory,
+                tableLogBufferFactory,
+                homeStatusBarInteractor,
+                homeStatusBarIconBlockListInteractor,
+                lightsOutInteractor,
+                activeNotificationsInteractor,
+                darkIconInteractor,
+                headsUpNotificationInteractor,
+                keyguardTransitionInteractor,
+                keyguardInteractor,
+                statusBarOperatorNameViewModel,
+                sceneInteractor,
+                sceneContainerOcclusionInteractor,
+                shadeInteractor,
+                shareToAppChipViewModel,
+                ongoingActivityChipsViewModel,
+                statusBarPopupChipsViewModelFactory,
+                systemStatusEventAnimationInteractor,
+                multiDisplayStatusBarContentInsetsViewModelStore,
+                backgroundScope,
+                testDispatcher,
+                { shadeDisplaysInteractor },
+            )
+        }
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryKosmos.kt
index e44061a..f560c50 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/statusbar/pipeline/wifi/data/repository/WifiRepositoryKosmos.kt
@@ -19,4 +19,4 @@
 import com.android.systemui.kosmos.Kosmos
 
 val Kosmos.fakeWifiRepository: FakeWifiRepository by Kosmos.Fixture { FakeWifiRepository() }
-val Kosmos.wifiRepository: WifiRepository by Kosmos.Fixture { fakeWifiRepository }
+var Kosmos.wifiRepository: WifiRepository by Kosmos.Fixture { fakeWifiRepository }
diff --git a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/MockitoKosmos.kt
similarity index 69%
copy from packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
copy to packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/MockitoKosmos.kt
index 9b7cd70..1638cb7 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/dagger/qualifiers/Tracing.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/MockitoKosmos.kt
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2023 The Android Open Source Project
+ * Copyright (C) 2024 The Android Open Source Project
  *
  * Licensed under the Apache License, Version 2.0 (the "License");
  * you may not use this file except in compliance with the License.
@@ -13,8 +13,10 @@
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */
-package com.android.systemui.dagger.qualifiers
 
-import javax.inject.Qualifier
+package com.android.systemui.util.mockito
 
-@Qualifier @MustBeDocumented @Retention(AnnotationRetention.RUNTIME) annotation class Tracing
+import com.android.systemui.kosmos.Kosmos.Fixture
+import org.mockito.kotlin.mock
+
+inline fun <reified T> mockFixture(): Fixture<T> = Fixture { mock() }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt
index 4ca044d..3421864 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/volume/dialog/sliders/dagger/VolumeDialogSliderComponentKosmos.kt
@@ -33,6 +33,8 @@
 import com.android.systemui.volume.dialog.sliders.domain.model.volumeDialogSliderType
 import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogOverscrollViewBinder
 import com.android.systemui.volume.dialog.sliders.ui.VolumeDialogSliderViewBinder
+import com.android.systemui.volume.dialog.sliders.ui.viewmodel.VolumeDialogSliderViewModel
+import com.android.systemui.volume.dialog.sliders.ui.viewmodel.volumeDialogSliderViewModel
 import com.android.systemui.volume.dialog.sliders.ui.volumeDialogOverscrollViewBinder
 import com.android.systemui.volume.dialog.sliders.ui.volumeDialogSliderViewBinder
 import com.android.systemui.volume.mediaControllerRepository
@@ -60,6 +62,9 @@
                     }
                 }
 
+        override fun sliderViewModel(): VolumeDialogSliderViewModel =
+            localKosmos.volumeDialogSliderViewModel
+
         override fun sliderViewBinder(): VolumeDialogSliderViewBinder =
             localKosmos.volumeDialogSliderViewBinder
 
diff --git a/packages/Vcn/service-b/Android.bp b/packages/Vcn/service-b/Android.bp
index 97574e6..aad534c3 100644
--- a/packages/Vcn/service-b/Android.bp
+++ b/packages/Vcn/service-b/Android.bp
@@ -29,7 +29,10 @@
             "vcn-location-flag/platform/com/android/server/vcn/VcnLocation.java",
         ],
     }),
-    visibility: ["//frameworks/base/services/core"],
+    visibility: [
+        "//frameworks/base/services/core",
+        "//packages/modules/Connectivity/service-t",
+    ],
 }
 
 // TODO: b/374174952 This library is only used in "service-connectivity-b-platform"
diff --git a/packages/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java b/packages/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java
index b9dcc61..aac217b 100644
--- a/packages/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java
+++ b/packages/Vcn/service-b/src/com/android/server/ConnectivityServiceInitializerB.java
@@ -37,9 +37,27 @@
     private static final String TAG = ConnectivityServiceInitializerB.class.getSimpleName();
     private final VcnManagementService mVcnManagementService;
 
+    // STOPSHIP: b/385203616 This static flag is for handling a temporary case when the mainline
+    // module prebuilt has updated to register the VCN but the platform change to remove
+    // registration is not merged. After mainline prebuilt is updated, we should merge the platform
+    // ASAP and remove this static check. This check is safe because both mainline and platform
+    // registration are triggered from the same method on the same thread.
+    private static boolean sIsRegistered = false;
+
     public ConnectivityServiceInitializerB(Context context) {
         super(context);
-        mVcnManagementService = VcnManagementService.create(context);
+
+        if (!sIsRegistered) {
+            mVcnManagementService = VcnManagementService.create(context);
+            sIsRegistered = true;
+        } else {
+            mVcnManagementService = null;
+            Log.e(
+                    TAG,
+                    "Ignore this registration since VCN is already registered. It will happen when"
+                        + " the mainline module prebuilt has updated to register the VCN but the"
+                        + " platform change to remove registration is not merged.");
+        }
     }
 
     @Override
diff --git a/ravenwood/scripts/list-ravenwood-tests.sh b/ravenwood/scripts/list-ravenwood-tests.sh
index 05f3fdf..5d7daeb 100755
--- a/ravenwood/scripts/list-ravenwood-tests.sh
+++ b/ravenwood/scripts/list-ravenwood-tests.sh
@@ -15,4 +15,20 @@
 
 # List all the ravenwood test modules.
 
-jq -r 'to_entries[] | select( .value.compatibility_suites | index("ravenwood-tests") ) | .key' "$OUT/module-info.json" | sort
+set -e
+
+in="$OUT/module-info.json"
+cache="$OUT/ravenwood-test-list.cached.tmp"
+cache_temp="$OUT/ravenwood-test-list.temp.tmp"
+
+if [[ "$in" -nt "$cache" ]] ; then
+    rm -f "$cache_temp" "$cache"
+
+    # First, create to a temp file, and once it's completed, rename it
+    # to the actual cache file, so that if the command failed or is interrupted,
+    # we don't update the cache.
+    jq -r 'to_entries[] | select( .value.compatibility_suites | index("ravenwood-tests") ) | .key' "$OUT/module-info.json" | sort > "$cache_temp"
+    mv "$cache_temp" "$cache"
+fi
+
+cat "$cache"
diff --git a/ravenwood/tools/hoststubgen/Android.bp b/ravenwood/tools/hoststubgen/Android.bp
index a5ff496..004834e 100644
--- a/ravenwood/tools/hoststubgen/Android.bp
+++ b/ravenwood/tools/hoststubgen/Android.bp
@@ -90,11 +90,9 @@
 java_library_host {
     name: "hoststubgen-lib",
     defaults: ["ravenwood-internal-only-visibility-java"],
-    srcs: ["src/**/*.kt"],
+    srcs: ["lib/**/*.kt"],
     static_libs: [
         "hoststubgen-helper-runtime",
-    ],
-    libs: [
         "junit",
         "ow2-asm",
         "ow2-asm-analysis",
@@ -108,15 +106,8 @@
 java_binary_host {
     name: "hoststubgen",
     main_class: "com.android.hoststubgen.HostStubGenMain",
-    static_libs: [
-        "hoststubgen-lib",
-        "junit",
-        "ow2-asm",
-        "ow2-asm-analysis",
-        "ow2-asm-commons",
-        "ow2-asm-tree",
-        "ow2-asm-util",
-    ],
+    srcs: ["src/**/*.kt"],
+    static_libs: ["hoststubgen-lib"],
     visibility: ["//visibility:public"],
 }
 
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Exceptions.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Exceptions.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Exceptions.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Exceptions.kt
diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessor.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessor.kt
new file mode 100644
index 0000000..4fe21ea
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessor.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+import com.android.hoststubgen.asm.ClassNodes
+import com.android.hoststubgen.filters.AnnotationBasedFilter
+import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter
+import com.android.hoststubgen.filters.ConstantFilter
+import com.android.hoststubgen.filters.DefaultHookInjectingFilter
+import com.android.hoststubgen.filters.FilterRemapper
+import com.android.hoststubgen.filters.ImplicitOutputFilter
+import com.android.hoststubgen.filters.KeepNativeFilter
+import com.android.hoststubgen.filters.OutputFilter
+import com.android.hoststubgen.filters.SanitizationFilter
+import com.android.hoststubgen.filters.TextFileFilterPolicyBuilder
+import com.android.hoststubgen.utils.ClassPredicate
+import com.android.hoststubgen.visitors.BaseAdapter
+import com.android.hoststubgen.visitors.PackageRedirectRemapper
+import org.objectweb.asm.ClassReader
+import org.objectweb.asm.ClassVisitor
+import org.objectweb.asm.ClassWriter
+import org.objectweb.asm.commons.ClassRemapper
+import org.objectweb.asm.util.CheckClassAdapter
+
+/**
+ * This class implements bytecode transformation of HostStubGen.
+ */
+class HostStubGenClassProcessor(
+    private val options: HostStubGenClassProcessorOptions,
+    private val allClasses: ClassNodes,
+    private val errors: HostStubGenErrors = HostStubGenErrors(),
+    private val stats: HostStubGenStats? = null,
+) {
+    val filter = buildFilter()
+    val remapper = FilterRemapper(filter)
+
+    private val packageRedirector = PackageRedirectRemapper(options.packageRedirects)
+
+    /**
+     * Build the filter, which decides what classes/methods/fields should be put in stub or impl
+     * jars, and "how". (e.g. with substitution?)
+     */
+    private fun buildFilter(): OutputFilter {
+        // We build a "chain" of multiple filters here.
+        //
+        // The filters are build in from "inside", meaning the first filter created here is
+        // the last filter used, so it has the least precedence.
+        //
+        // So, for example, the "remove" annotation, which is handled by AnnotationBasedFilter,
+        // can override a class-wide annotation, which is handled by
+        // ClassWidePolicyPropagatingFilter, and any annotations can be overridden by the
+        // text-file based filter, which is handled by parseTextFilterPolicyFile.
+
+        // The first filter is for the default policy from the command line options.
+        var filter: OutputFilter = ConstantFilter(options.defaultPolicy.get, "default-by-options")
+
+        // Next, we build a filter that preserves all native methods by default
+        filter = KeepNativeFilter(allClasses, filter)
+
+        // Next, we need a filter that resolves "class-wide" policies.
+        // This is used when a member (methods, fields, nested classes) don't get any policies
+        // from upper filters. e.g. when a method has no annotations, then this filter will apply
+        // the class-wide policy, if any. (if not, we'll fall back to the above filter.)
+        filter = ClassWidePolicyPropagatingFilter(allClasses, filter)
+
+        // Inject default hooks from options.
+        filter = DefaultHookInjectingFilter(
+            allClasses,
+            options.defaultClassLoadHook.get,
+            options.defaultMethodCallHook.get,
+            filter
+        )
+
+        val annotationAllowedPredicate = options.annotationAllowedClassesFile.get.let { file ->
+            if (file == null) {
+                ClassPredicate.newConstantPredicate(true) // Allow all classes
+            } else {
+                ClassPredicate.loadFromFile(file, false)
+            }
+        }
+
+        // Next, Java annotation based filter.
+        val annotFilter = AnnotationBasedFilter(
+            errors,
+            allClasses,
+            options.keepAnnotations,
+            options.keepClassAnnotations,
+            options.throwAnnotations,
+            options.removeAnnotations,
+            options.ignoreAnnotations,
+            options.substituteAnnotations,
+            options.redirectAnnotations,
+            options.redirectionClassAnnotations,
+            options.classLoadHookAnnotations,
+            options.partiallyAllowedAnnotations,
+            options.keepStaticInitializerAnnotations,
+            annotationAllowedPredicate,
+            filter
+        )
+        filter = annotFilter
+
+        // Next, "text based" filter, which allows to override policies without touching
+        // the target code.
+        if (options.policyOverrideFiles.isNotEmpty()) {
+            val builder = TextFileFilterPolicyBuilder(allClasses, filter)
+            options.policyOverrideFiles.forEach(builder::parse)
+            filter = builder.createOutputFilter()
+            annotFilter.annotationAllowedMembers = builder.annotationAllowedMembersFilter
+        }
+
+        // Apply the implicit filter.
+        filter = ImplicitOutputFilter(errors, allClasses, filter)
+
+        // Add a final sanitization step.
+        filter = SanitizationFilter(errors, allClasses, filter)
+
+        return filter
+    }
+
+    fun processClassBytecode(bytecode: ByteArray): ByteArray {
+        val cr = ClassReader(bytecode)
+
+        // COMPUTE_FRAMES wouldn't be happy if code uses
+        val flags = ClassWriter.COMPUTE_MAXS // or ClassWriter.COMPUTE_FRAMES
+        val cw = ClassWriter(flags)
+
+        // Connect to the class writer
+        var outVisitor: ClassVisitor = cw
+        if (options.enableClassChecker.get) {
+            outVisitor = CheckClassAdapter(outVisitor)
+        }
+
+        // Remapping should happen at the end.
+        outVisitor = ClassRemapper(outVisitor, remapper)
+
+        val visitorOptions = BaseAdapter.Options(
+            errors = errors,
+            stats = stats,
+            enablePreTrace = options.enablePreTrace.get,
+            enablePostTrace = options.enablePostTrace.get,
+            deleteClassFinals = options.deleteFinals.get,
+            deleteMethodFinals = options.deleteFinals.get,
+        )
+        outVisitor = BaseAdapter.getVisitor(
+            cr.className, allClasses, outVisitor, filter,
+            packageRedirector, visitorOptions
+        )
+
+        cr.accept(outVisitor, ClassReader.EXPAND_FRAMES)
+        return cw.toByteArray()
+    }
+}
diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessorOptions.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessorOptions.kt
new file mode 100644
index 0000000..c7c45e6
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenClassProcessorOptions.kt
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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
+
+import com.android.hoststubgen.filters.FilterPolicy
+import com.android.hoststubgen.utils.ArgIterator
+import com.android.hoststubgen.utils.BaseOptions
+import com.android.hoststubgen.utils.SetOnce
+
+private fun parsePackageRedirect(fromColonTo: String): Pair<String, String> {
+    val colon = fromColonTo.indexOf(':')
+    if ((colon < 1) || (colon + 1 >= fromColonTo.length)) {
+        throw ArgumentsException("--package-redirect must be a colon-separated string")
+    }
+    // TODO check for duplicates
+    return Pair(fromColonTo.substring(0, colon), fromColonTo.substring(colon + 1))
+}
+
+/**
+ * Options to configure [HostStubGenClassProcessor].
+ */
+open class HostStubGenClassProcessorOptions(
+    var keepAnnotations: MutableSet<String> = mutableSetOf(),
+    var throwAnnotations: MutableSet<String> = mutableSetOf(),
+    var removeAnnotations: MutableSet<String> = mutableSetOf(),
+    var ignoreAnnotations: MutableSet<String> = mutableSetOf(),
+    var keepClassAnnotations: MutableSet<String> = mutableSetOf(),
+    var partiallyAllowedAnnotations: MutableSet<String> = mutableSetOf(),
+    var redirectAnnotations: MutableSet<String> = mutableSetOf(),
+
+    var substituteAnnotations: MutableSet<String> = mutableSetOf(),
+    var redirectionClassAnnotations: MutableSet<String> = mutableSetOf(),
+    var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(),
+    var keepStaticInitializerAnnotations: MutableSet<String> = mutableSetOf(),
+
+    var packageRedirects: MutableList<Pair<String, String>> = mutableListOf(),
+
+    var annotationAllowedClassesFile: SetOnce<String?> = SetOnce(null),
+
+    var defaultClassLoadHook: SetOnce<String?> = SetOnce(null),
+    var defaultMethodCallHook: SetOnce<String?> = SetOnce(null),
+
+    var policyOverrideFiles: MutableList<String> = mutableListOf(),
+
+    var defaultPolicy: SetOnce<FilterPolicy> = SetOnce(FilterPolicy.Remove),
+
+    var deleteFinals: SetOnce<Boolean> = SetOnce(false),
+
+    var enableClassChecker: SetOnce<Boolean> = SetOnce(false),
+    var enablePreTrace: SetOnce<Boolean> = SetOnce(false),
+    var enablePostTrace: SetOnce<Boolean> = SetOnce(false),
+) : BaseOptions() {
+
+    private val allAnnotations = mutableSetOf<String>()
+
+    private fun ensureUniqueAnnotation(name: String): String {
+        if (!allAnnotations.add(name)) {
+            throw DuplicateAnnotationException(name)
+        }
+        return name
+    }
+
+    override fun parseOption(option: String, ai: ArgIterator): Boolean {
+        // Define some shorthands...
+        fun nextArg(): String = ai.nextArgRequired(option)
+        fun MutableSet<String>.addUniqueAnnotationArg(): String =
+            nextArg().also { this += ensureUniqueAnnotation(it) }
+
+        when (option) {
+            "--policy-override-file" ->
+                policyOverrideFiles.add(nextArg().ensureFileExists())
+
+            "--default-remove" -> defaultPolicy.set(FilterPolicy.Remove)
+            "--default-throw" -> defaultPolicy.set(FilterPolicy.Throw)
+            "--default-keep" -> defaultPolicy.set(FilterPolicy.Keep)
+
+            "--keep-annotation" ->
+                keepAnnotations.addUniqueAnnotationArg()
+
+            "--keep-class-annotation" ->
+                keepClassAnnotations.addUniqueAnnotationArg()
+
+            "--partially-allowed-annotation" ->
+                partiallyAllowedAnnotations.addUniqueAnnotationArg()
+
+            "--throw-annotation" ->
+                throwAnnotations.addUniqueAnnotationArg()
+
+            "--remove-annotation" ->
+                removeAnnotations.addUniqueAnnotationArg()
+
+            "--ignore-annotation" ->
+                ignoreAnnotations.addUniqueAnnotationArg()
+
+            "--substitute-annotation" ->
+                substituteAnnotations.addUniqueAnnotationArg()
+
+            "--redirect-annotation" ->
+                redirectAnnotations.addUniqueAnnotationArg()
+
+            "--redirection-class-annotation" ->
+                redirectionClassAnnotations.addUniqueAnnotationArg()
+
+            "--class-load-hook-annotation" ->
+                classLoadHookAnnotations.addUniqueAnnotationArg()
+
+            "--keep-static-initializer-annotation" ->
+                keepStaticInitializerAnnotations.addUniqueAnnotationArg()
+
+            "--package-redirect" ->
+                packageRedirects += parsePackageRedirect(nextArg())
+
+            "--annotation-allowed-classes-file" ->
+                annotationAllowedClassesFile.set(nextArg())
+
+            "--default-class-load-hook" ->
+                defaultClassLoadHook.set(nextArg())
+
+            "--default-method-call-hook" ->
+                defaultMethodCallHook.set(nextArg())
+
+            "--delete-finals" -> deleteFinals.set(true)
+
+            // Following options are for debugging.
+            "--enable-class-checker" -> enableClassChecker.set(true)
+            "--no-class-checker" -> enableClassChecker.set(false)
+
+            "--enable-pre-trace" -> enablePreTrace.set(true)
+            "--no-pre-trace" -> enablePreTrace.set(false)
+
+            "--enable-post-trace" -> enablePostTrace.set(true)
+            "--no-post-trace" -> enablePostTrace.set(false)
+
+            else -> return false
+        }
+
+        return true
+    }
+
+    override fun dumpFields(): String {
+        return """
+            keepAnnotations=$keepAnnotations,
+            throwAnnotations=$throwAnnotations,
+            removeAnnotations=$removeAnnotations,
+            ignoreAnnotations=$ignoreAnnotations,
+            keepClassAnnotations=$keepClassAnnotations,
+            partiallyAllowedAnnotations=$partiallyAllowedAnnotations,
+            substituteAnnotations=$substituteAnnotations,
+            nativeSubstituteAnnotations=$redirectionClassAnnotations,
+            classLoadHookAnnotations=$classLoadHookAnnotations,
+            keepStaticInitializerAnnotations=$keepStaticInitializerAnnotations,
+            packageRedirects=$packageRedirects,
+            annotationAllowedClassesFile=$annotationAllowedClassesFile,
+            defaultClassLoadHook=$defaultClassLoadHook,
+            defaultMethodCallHook=$defaultMethodCallHook,
+            policyOverrideFiles=${policyOverrideFiles.toTypedArray().contentToString()},
+            defaultPolicy=$defaultPolicy,
+            deleteFinals=$deleteFinals,
+            enableClassChecker=$enableClassChecker,
+            enablePreTrace=$enablePreTrace,
+            enablePostTrace=$enablePostTrace,
+        """.trimIndent()
+    }
+}
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenErrors.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenErrors.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenErrors.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenLogger.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenLogger.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenLogger.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenStats.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenStats.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/HostStubGenStats.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Utils.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Utils.kt
similarity index 84%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Utils.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Utils.kt
index 10179ee..b2af782 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/Utils.kt
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/Utils.kt
@@ -15,6 +15,8 @@
  */
 package com.android.hoststubgen
 
+import java.io.PrintWriter
+
 /**
  * Name of this executable. Set it in the main method.
  */
@@ -96,3 +98,23 @@
 fun csvEscape(value: String): String {
     return "\"" + value.replace("\"", "\"\"") + "\""
 }
+
+inline fun runMainWithBoilerplate(realMain: () -> Unit) {
+    var success = false
+
+    try {
+        realMain()
+
+        success = true
+    } catch (e: Throwable) {
+        log.e("$executableName: Error: ${e.message}")
+        if (e !is UserErrorException) {
+            e.printStackTrace(PrintWriter(log.getWriter(LogLevel.Error)))
+        }
+    } finally {
+        log.i("$executableName finished")
+        log.flush()
+    }
+
+    System.exit(if (success) 0 else 1 )
+}
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/AsmUtils.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/AsmUtils.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/AsmUtils.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/ClassNodes.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/asm/ClassNodes.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/asm/ClassNodes.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/dumper/ApiDumper.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/dumper/ApiDumper.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/dumper/ApiDumper.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/dumper/ApiDumper.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
similarity index 97%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
index 6b360b7..b225209 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/AndroidHeuristicsFilter.kt
@@ -66,7 +66,7 @@
             || className.endsWith("/FeatureFlags")
             || className.endsWith("/FeatureFlagsImpl")
             || className.endsWith("/CustomFeatureFlags")
-            || className.endsWith("/FakeFeatureFlagsImpl");
+            || className.endsWith("/FakeFeatureFlagsImpl")
 }
 
 /**
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/AnnotationBasedFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ClassWidePolicyPropagatingFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ConstantFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ConstantFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ConstantFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/DefaultHookInjectingFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/DelegatingFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/DelegatingFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/DelegatingFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicy.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicy.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicy.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterPolicyWithReason.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterRemapper.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/FilterRemapper.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/FilterRemapper.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/ImplicitOutputFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/InMemoryOutputFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/KeepNativeFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/KeepNativeFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/KeepNativeFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/KeepNativeFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/OutputFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/OutputFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/OutputFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/PackageFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/PackageFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/PackageFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/SanitizationFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/SanitizationFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/SanitizationFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/SanitizationFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/SubclassFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/SubclassFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/SubclassFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/SubclassFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFileFilterPolicyParser.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyMethodReplaceFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/filters/TextFilePolicyRemapperFilter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/ClassPredicate.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/ClassPredicate.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/ClassPredicate.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/ClassPredicate.kt
diff --git a/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/OptionUtils.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/OptionUtils.kt
new file mode 100644
index 0000000..0b17879
--- /dev/null
+++ b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/OptionUtils.kt
@@ -0,0 +1,206 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.utils
+
+import com.android.hoststubgen.ArgumentsException
+import com.android.hoststubgen.ensureFileExists
+import com.android.hoststubgen.log
+import com.android.hoststubgen.normalizeTextLine
+import java.io.BufferedReader
+import java.io.FileReader
+
+/**
+ * Base class for parsing arguments from commandline.
+ */
+abstract class BaseOptions {
+    /**
+     * Parse all arguments.
+     *
+     * This method should remain final. For customization in subclasses, override [parseOption].
+     */
+    fun parseArgs(args: List<String>) {
+        val ai = ArgIterator.withAtFiles(args)
+        while (true) {
+            val arg = ai.nextArgOptional() ?: break
+
+            if (log.maybeHandleCommandLineArg(arg) { ai.nextArgRequired(arg) }) {
+                continue
+            }
+            try {
+                if (!parseOption(arg, ai)) {
+                    throw ArgumentsException("Unknown option: $arg")
+                }
+            } catch (e: SetOnce.SetMoreThanOnceException) {
+                throw ArgumentsException("Duplicate or conflicting argument found: $arg")
+            }
+        }
+
+        checkArgs()
+    }
+
+    /**
+     * Print out all fields in this class.
+     *
+     * This method should remain final. For customization in subclasses, override [dumpFields].
+     */
+    final override fun toString(): String {
+        val fields = dumpFields().prependIndent("  ")
+        return "${this::class.simpleName} {\n$fields\n}"
+    }
+
+    /**
+     * Check whether the parsed options are in a correct state.
+     *
+     * This method is called as the last step in [parseArgs].
+     */
+    open fun checkArgs() {}
+
+    /**
+     * Parse a single option. Return true if the option is accepted, otherwise return false.
+     *
+     * Subclasses override/extend this method to support more options.
+     */
+    abstract fun parseOption(option: String, ai: ArgIterator): Boolean
+
+    abstract fun dumpFields(): String
+}
+
+class ArgIterator(
+    private val args: List<String>,
+    private var currentIndex: Int = -1
+) {
+    val current: String
+        get() = args[currentIndex]
+
+    /**
+     * Get the next argument, or [null] if there's no more arguments.
+     */
+    fun nextArgOptional(): String? {
+        if ((currentIndex + 1) >= args.size) {
+            return null
+        }
+        return args[++currentIndex]
+    }
+
+    /**
+     * Get the next argument, or throw if
+     */
+    fun nextArgRequired(argName: String): String {
+        nextArgOptional().let {
+            if (it == null) {
+                throw ArgumentsException("Missing parameter for option $argName")
+            }
+            if (it.isEmpty()) {
+                throw ArgumentsException("Parameter can't be empty for option $argName")
+            }
+            return it
+        }
+    }
+
+    companion object {
+        fun withAtFiles(args: List<String>): ArgIterator {
+            return ArgIterator(expandAtFiles(args))
+        }
+
+        /**
+         * Scan the arguments, and if any of them starts with an `@`, then load from the file
+         * and use its content as arguments.
+         *
+         * In order to pass an argument that starts with an '@', use '@@' instead.
+         *
+         * In this file, each line is treated as a single argument.
+         *
+         * The file can contain '#' as comments.
+         */
+        private fun expandAtFiles(args: List<String>): List<String> {
+            val ret = mutableListOf<String>()
+
+            args.forEach { arg ->
+                if (arg.startsWith("@@")) {
+                    ret += arg.substring(1)
+                    return@forEach
+                } else if (!arg.startsWith('@')) {
+                    ret += arg
+                    return@forEach
+                }
+                // Read from the file, and add each line to the result.
+                val filename = arg.substring(1).ensureFileExists()
+
+                log.v("Expanding options file $filename")
+
+                BufferedReader(FileReader(filename)).use { reader ->
+                    while (true) {
+                        var line = reader.readLine() ?: break // EOF
+
+                        line = normalizeTextLine(line)
+                        if (line.isNotEmpty()) {
+                            ret += line
+                        }
+                    }
+                }
+            }
+            return ret
+        }
+    }
+}
+
+/**
+ * A single value that can only set once.
+ */
+open class SetOnce<T>(private var value: T) {
+    class SetMoreThanOnceException : Exception()
+
+    private var set = false
+
+    fun set(v: T): T {
+        if (set) {
+            throw SetMoreThanOnceException()
+        }
+        if (v == null) {
+            throw NullPointerException("This shouldn't happen")
+        }
+        set = true
+        value = v
+        return v
+    }
+
+    val get: T
+        get() = this.value
+
+    val isSet: Boolean
+        get() = this.set
+
+    fun <R> ifSet(block: (T & Any) -> R): R? {
+        if (isSet) {
+            return block(value!!)
+        }
+        return null
+    }
+
+    override fun toString(): String {
+        return "$value"
+    }
+}
+
+class IntSetOnce(value: Int) : SetOnce<Int>(value) {
+    fun set(v: String): Int {
+        try {
+            return this.set(v.toInt())
+        } catch (e: NumberFormatException) {
+            throw ArgumentsException("Invalid integer $v")
+        }
+    }
+}
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/Trie.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/utils/Trie.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/utils/Trie.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/BaseAdapter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BaseAdapter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/BaseAdapter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/BodyReplacingMethodVisitor.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/Helper.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/Helper.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/Helper.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/ImplGeneratingAdapter.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt b/ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt
similarity index 100%
rename from ravenwood/tools/hoststubgen/src/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt
rename to ravenwood/tools/hoststubgen/lib/com/android/hoststubgen/visitors/PackageRedirectRemapper.kt
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
index 7e294ed..3335405 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
+++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGen.kt
@@ -17,36 +17,15 @@
 
 import com.android.hoststubgen.asm.ClassNodes
 import com.android.hoststubgen.dumper.ApiDumper
-import com.android.hoststubgen.filters.AnnotationBasedFilter
-import com.android.hoststubgen.filters.ClassWidePolicyPropagatingFilter
-import com.android.hoststubgen.filters.ConstantFilter
-import com.android.hoststubgen.filters.DefaultHookInjectingFilter
 import com.android.hoststubgen.filters.FilterPolicy
-import com.android.hoststubgen.filters.FilterRemapper
-import com.android.hoststubgen.filters.ImplicitOutputFilter
-import com.android.hoststubgen.filters.KeepNativeFilter
-import com.android.hoststubgen.filters.OutputFilter
-import com.android.hoststubgen.filters.SanitizationFilter
-import com.android.hoststubgen.filters.TextFileFilterPolicyBuilder
 import com.android.hoststubgen.filters.printAsTextPolicy
-import com.android.hoststubgen.utils.ClassPredicate
-import com.android.hoststubgen.visitors.BaseAdapter
-import com.android.hoststubgen.visitors.PackageRedirectRemapper
 import java.io.BufferedInputStream
 import java.io.BufferedOutputStream
 import java.io.FileOutputStream
-import java.io.InputStream
-import java.io.OutputStream
 import java.io.PrintWriter
 import java.util.zip.ZipEntry
 import java.util.zip.ZipFile
 import java.util.zip.ZipOutputStream
-import org.objectweb.asm.ClassReader
-import org.objectweb.asm.ClassVisitor
-import org.objectweb.asm.ClassWriter
-import org.objectweb.asm.commons.ClassRemapper
-import org.objectweb.asm.commons.Remapper
-import org.objectweb.asm.util.CheckClassAdapter
 
 /**
  * Actual main class.
@@ -76,21 +55,15 @@
             }
         }
 
-        // Build the filters.
-        val filter = buildFilter(errors, allClasses, options)
-
-        val filterRemapper = FilterRemapper(filter)
+        // Build the class processor
+        val processor = HostStubGenClassProcessor(options, allClasses, errors, stats)
 
         // Transform the jar.
         convert(
             options.inJar.get,
             options.outJar.get,
-            filter,
+            processor,
             options.enableClassChecker.get,
-            allClasses,
-            errors,
-            stats,
-            filterRemapper,
             options.numShards.get,
             options.shard.get,
         )
@@ -106,109 +79,20 @@
                 PrintWriter(it).use { pw ->
                     // TODO, when dumping a jar that's not framework-minus-apex.jar, we need to feed
                     // framework-minus-apex.jar so that we can dump inherited methods from it.
-                    ApiDumper(pw, allClasses, null, filter).dump()
+                    ApiDumper(pw, allClasses, null, processor.filter).dump()
                 }
             }
         }
     }
 
     /**
-     * Build the filter, which decides what classes/methods/fields should be put in stub or impl
-     * jars, and "how". (e.g. with substitution?)
-     */
-    private fun buildFilter(
-        errors: HostStubGenErrors,
-        allClasses: ClassNodes,
-        options: HostStubGenOptions,
-    ): OutputFilter {
-        // We build a "chain" of multiple filters here.
-        //
-        // The filters are build in from "inside", meaning the first filter created here is
-        // the last filter used, so it has the least precedence.
-        //
-        // So, for example, the "remove" annotation, which is handled by AnnotationBasedFilter,
-        // can override a class-wide annotation, which is handled by
-        // ClassWidePolicyPropagatingFilter, and any annotations can be overridden by the
-        // text-file based filter, which is handled by parseTextFilterPolicyFile.
-
-        // The first filter is for the default policy from the command line options.
-        var filter: OutputFilter = ConstantFilter(options.defaultPolicy.get, "default-by-options")
-
-        // Next, we build a filter that preserves all native methods by default
-        filter = KeepNativeFilter(allClasses, filter)
-
-        // Next, we need a filter that resolves "class-wide" policies.
-        // This is used when a member (methods, fields, nested classes) don't get any polices
-        // from upper filters. e.g. when a method has no annotations, then this filter will apply
-        // the class-wide policy, if any. (if not, we'll fall back to the above filter.)
-        filter = ClassWidePolicyPropagatingFilter(allClasses, filter)
-
-        // Inject default hooks from options.
-        filter = DefaultHookInjectingFilter(
-            allClasses,
-            options.defaultClassLoadHook.get,
-            options.defaultMethodCallHook.get,
-            filter
-        )
-
-        val annotationAllowedPredicate = options.annotationAllowedClassesFile.get.let { file ->
-            if (file == null) {
-                ClassPredicate.newConstantPredicate(true) // Allow all classes
-            } else {
-                ClassPredicate.loadFromFile(file, false)
-            }
-        }
-
-        // Next, Java annotation based filter.
-        val annotFilter = AnnotationBasedFilter(
-            errors,
-            allClasses,
-            options.keepAnnotations,
-            options.keepClassAnnotations,
-            options.throwAnnotations,
-            options.removeAnnotations,
-            options.ignoreAnnotations,
-            options.substituteAnnotations,
-            options.redirectAnnotations,
-            options.redirectionClassAnnotations,
-            options.classLoadHookAnnotations,
-            options.partiallyAllowedAnnotations,
-            options.keepStaticInitializerAnnotations,
-            annotationAllowedPredicate,
-            filter
-        )
-        filter = annotFilter
-
-        // Next, "text based" filter, which allows to override polices without touching
-        // the target code.
-        if (options.policyOverrideFiles.isNotEmpty()) {
-            val builder = TextFileFilterPolicyBuilder(allClasses, filter)
-            options.policyOverrideFiles.forEach(builder::parse)
-            filter = builder.createOutputFilter()
-            annotFilter.annotationAllowedMembers = builder.annotationAllowedMembersFilter
-        }
-
-        // Apply the implicit filter.
-        filter = ImplicitOutputFilter(errors, allClasses, filter)
-
-        // Add a final sanitization step.
-        filter = SanitizationFilter(errors, allClasses, filter)
-
-        return filter
-    }
-
-    /**
      * Convert a JAR file into "stub" and "impl" JAR files.
      */
     private fun convert(
         inJar: String,
         outJar: String?,
-        filter: OutputFilter,
+        processor: HostStubGenClassProcessor,
         enableChecker: Boolean,
-        classes: ClassNodes,
-        errors: HostStubGenErrors,
-        stats: HostStubGenStats,
-        remapper: Remapper?,
         numShards: Int,
         shard: Int
     ) {
@@ -216,8 +100,6 @@
         log.i("ASM CheckClassAdapter is %s", if (enableChecker) "enabled" else "disabled")
 
         log.iTime("Transforming jar") {
-            val packageRedirector = PackageRedirectRemapper(options.packageRedirects)
-
             var itemIndex = 0
             var numItemsProcessed = 0
             var numItems = -1 // == Unknown
@@ -240,11 +122,7 @@
                             if (!inShard) {
                                 continue
                             }
-                            convertSingleEntry(
-                                inZip, entry, outStream, filter,
-                                packageRedirector, remapper, enableChecker,
-                                classes, errors, stats
-                            )
+                            convertSingleEntry(inZip, entry, outStream, processor)
                             numItemsProcessed++
                         }
                         log.i("Converted all entries.")
@@ -270,13 +148,7 @@
         inZip: ZipFile,
         entry: ZipEntry,
         outStream: ZipOutputStream?,
-        filter: OutputFilter,
-        packageRedirector: PackageRedirectRemapper,
-        remapper: Remapper?,
-        enableChecker: Boolean,
-        classes: ClassNodes,
-        errors: HostStubGenErrors,
-        stats: HostStubGenStats
+        processor: HostStubGenClassProcessor
     ) {
         log.d("Entry: %s", entry.name)
         log.withIndent {
@@ -289,10 +161,7 @@
 
             // If it's a class, convert it.
             if (name.endsWith(".class")) {
-                processSingleClass(
-                    inZip, entry, outStream, filter, packageRedirector,
-                    remapper, enableChecker, classes, errors, stats
-                )
+                processSingleClass(inZip, entry, outStream, processor)
                 return
             }
 
@@ -332,29 +201,23 @@
     }
 
     /**
-     * Convert a single class to "stub" and "impl".
+     * Convert a single class.
      */
     private fun processSingleClass(
         inZip: ZipFile,
         entry: ZipEntry,
         outStream: ZipOutputStream?,
-        filter: OutputFilter,
-        packageRedirector: PackageRedirectRemapper,
-        remapper: Remapper?,
-        enableChecker: Boolean,
-        classes: ClassNodes,
-        errors: HostStubGenErrors,
-        stats: HostStubGenStats
+        processor: HostStubGenClassProcessor
     ) {
         val classInternalName = entry.name.replaceFirst("\\.class$".toRegex(), "")
-        val classPolicy = filter.getPolicyForClass(classInternalName)
+        val classPolicy = processor.filter.getPolicyForClass(classInternalName)
         if (classPolicy.policy == FilterPolicy.Remove) {
             log.d("Removing class: %s %s", classInternalName, classPolicy)
             return
         }
         // If we're applying a remapper, we need to rename the file too.
         var newName = entry.name
-        remapper?.mapType(classInternalName)?.let { remappedName ->
+        processor.remapper.mapType(classInternalName)?.let { remappedName ->
             if (remappedName != classInternalName) {
                 log.d("Renaming class file: %s -> %s", classInternalName, remappedName)
                 newName = "$remappedName.class"
@@ -367,64 +230,11 @@
                 BufferedInputStream(inZip.getInputStream(entry)).use { bis ->
                     val newEntry = ZipEntry(newName)
                     outStream.putNextEntry(newEntry)
-                    convertClass(
-                        classInternalName, bis,
-                        outStream, filter, packageRedirector, remapper,
-                        enableChecker, classes, errors, stats
-                    )
+                    val classBytecode = bis.readAllBytes()
+                    outStream.write(processor.processClassBytecode(classBytecode))
                     outStream.closeEntry()
                 }
             }
         }
     }
-
-    /**
-     * Convert a single class to either "stub" or "impl".
-     */
-    private fun convertClass(
-        classInternalName: String,
-        input: InputStream,
-        out: OutputStream,
-        filter: OutputFilter,
-        packageRedirector: PackageRedirectRemapper,
-        remapper: Remapper?,
-        enableChecker: Boolean,
-        classes: ClassNodes,
-        errors: HostStubGenErrors,
-        stats: HostStubGenStats?
-    ) {
-        val cr = ClassReader(input)
-
-        // COMPUTE_FRAMES wouldn't be happy if code uses
-        val flags = ClassWriter.COMPUTE_MAXS // or ClassWriter.COMPUTE_FRAMES
-        val cw = ClassWriter(flags)
-
-        // Connect to the class writer
-        var outVisitor: ClassVisitor = cw
-        if (enableChecker) {
-            outVisitor = CheckClassAdapter(outVisitor)
-        }
-
-        // Remapping should happen at the end.
-        remapper?.let {
-            outVisitor = ClassRemapper(outVisitor, remapper)
-        }
-
-        val visitorOptions = BaseAdapter.Options(
-            errors = errors,
-            stats = stats,
-            enablePreTrace = options.enablePreTrace.get,
-            enablePostTrace = options.enablePostTrace.get,
-            deleteClassFinals = options.deleteFinals.get,
-            deleteMethodFinals = options.deleteFinals.get,
-        )
-        outVisitor = BaseAdapter.getVisitor(
-            classInternalName, classes, outVisitor, filter,
-            packageRedirector, visitorOptions
-        )
-
-        cr.accept(outVisitor, ClassReader.EXPAND_FRAMES)
-        val data = cw.toByteArray()
-        out.write(data)
-    }
 }
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt
index 8506466..4ba8c5c 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt
+++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenMain.kt
@@ -17,8 +17,6 @@
 
 package com.android.hoststubgen
 
-import java.io.PrintWriter
-
 /**
  * Entry point.
  */
@@ -26,10 +24,10 @@
     executableName = "HostStubGen"
     runMainWithBoilerplate {
         // Parse the command line arguments.
-        var clanupOnError = false
+        var cleanupOnError = false
         try {
-            val options = HostStubGenOptions.parseArgs(args)
-            clanupOnError = options.cleanUpOnError.get
+            val options = HostStubGenOptions().apply { parseArgs(args.asList()) }
+            cleanupOnError = options.cleanUpOnError.get
 
             log.v("$executableName started")
             log.v("Options: $options")
@@ -37,30 +35,10 @@
             // Run.
             HostStubGen(options).run()
         } catch (e: Throwable) {
-            if (clanupOnError) {
+            if (cleanupOnError) {
                 TODO("Remove output jars here")
             }
             throw e
         }
     }
 }
-
-inline fun runMainWithBoilerplate(realMain: () -> Unit) {
-    var success = false
-
-    try {
-        realMain()
-
-        success = true
-    } catch (e: Throwable) {
-        log.e("$executableName: Error: ${e.message}")
-        if (e !is UserErrorException) {
-            e.printStackTrace(PrintWriter(log.getWriter(LogLevel.Error)))
-        }
-    } finally {
-        log.i("$executableName finished")
-        log.flush()
-    }
-
-    System.exit(if (success) 0 else 1 )
-}
diff --git a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
index 1ab88d2..8bb454f 100644
--- a/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
+++ b/ravenwood/tools/hoststubgen/src/com/android/hoststubgen/HostStubGenOptions.kt
@@ -15,385 +15,102 @@
  */
 package com.android.hoststubgen
 
-import com.android.hoststubgen.filters.FilterPolicy
-import java.io.BufferedReader
-import java.io.FileReader
-
-/**
- * A single value that can only set once.
- */
-open class SetOnce<T>(private var value: T) {
-    class SetMoreThanOnceException : Exception()
-
-    private var set = false
-
-    fun set(v: T): T {
-        if (set) {
-            throw SetMoreThanOnceException()
-        }
-        if (v == null) {
-            throw NullPointerException("This shouldn't happen")
-        }
-        set = true
-        value = v
-        return v
-    }
-
-    val get: T
-        get() = this.value
-
-    val isSet: Boolean
-        get() = this.set
-
-    fun <R> ifSet(block: (T & Any) -> R): R? {
-        if (isSet) {
-            return block(value!!)
-        }
-        return null
-    }
-
-    override fun toString(): String {
-        return "$value"
-    }
-}
-
-class IntSetOnce(value: Int) : SetOnce<Int>(value) {
-    fun set(v: String): Int {
-        try {
-            return this.set(v.toInt())
-        } catch (e: NumberFormatException) {
-            throw ArgumentsException("Invalid integer $v")
-        }
-    }
-}
+import com.android.hoststubgen.utils.ArgIterator
+import com.android.hoststubgen.utils.IntSetOnce
+import com.android.hoststubgen.utils.SetOnce
 
 /**
  * Options that can be set from command line arguments.
  */
 class HostStubGenOptions(
-        /** Input jar file*/
-        var inJar: SetOnce<String> = SetOnce(""),
+    /** Input jar file*/
+    var inJar: SetOnce<String> = SetOnce(""),
 
-        /** Output jar file */
-        var outJar: SetOnce<String?> = SetOnce(null),
+    /** Output jar file */
+    var outJar: SetOnce<String?> = SetOnce(null),
 
-        var inputJarDumpFile: SetOnce<String?> = SetOnce(null),
+    var inputJarDumpFile: SetOnce<String?> = SetOnce(null),
 
-        var inputJarAsKeepAllFile: SetOnce<String?> = SetOnce(null),
+    var inputJarAsKeepAllFile: SetOnce<String?> = SetOnce(null),
 
-        var keepAnnotations: MutableSet<String> = mutableSetOf(),
-        var throwAnnotations: MutableSet<String> = mutableSetOf(),
-        var removeAnnotations: MutableSet<String> = mutableSetOf(),
-        var ignoreAnnotations: MutableSet<String> = mutableSetOf(),
-        var keepClassAnnotations: MutableSet<String> = mutableSetOf(),
-        var partiallyAllowedAnnotations: MutableSet<String> = mutableSetOf(),
-        var redirectAnnotations: MutableSet<String> = mutableSetOf(),
+    var cleanUpOnError: SetOnce<Boolean> = SetOnce(false),
 
-        var substituteAnnotations: MutableSet<String> = mutableSetOf(),
-        var redirectionClassAnnotations: MutableSet<String> = mutableSetOf(),
-        var classLoadHookAnnotations: MutableSet<String> = mutableSetOf(),
-        var keepStaticInitializerAnnotations: MutableSet<String> = mutableSetOf(),
+    var statsFile: SetOnce<String?> = SetOnce(null),
 
-        var packageRedirects: MutableList<Pair<String, String>> = mutableListOf(),
+    var apiListFile: SetOnce<String?> = SetOnce(null),
 
-        var annotationAllowedClassesFile: SetOnce<String?> = SetOnce(null),
+    var numShards: IntSetOnce = IntSetOnce(1),
+    var shard: IntSetOnce = IntSetOnce(0),
+) : HostStubGenClassProcessorOptions() {
 
-        var defaultClassLoadHook: SetOnce<String?> = SetOnce(null),
-        var defaultMethodCallHook: SetOnce<String?> = SetOnce(null),
-
-        var policyOverrideFiles: MutableList<String> = mutableListOf(),
-
-        var defaultPolicy: SetOnce<FilterPolicy> = SetOnce(FilterPolicy.Remove),
-
-        var cleanUpOnError: SetOnce<Boolean> = SetOnce(false),
-
-        var deleteFinals: SetOnce<Boolean> = SetOnce(false),
-
-        var enableClassChecker: SetOnce<Boolean> = SetOnce(false),
-        var enablePreTrace: SetOnce<Boolean> = SetOnce(false),
-        var enablePostTrace: SetOnce<Boolean> = SetOnce(false),
-
-        var statsFile: SetOnce<String?> = SetOnce(null),
-
-        var apiListFile: SetOnce<String?> = SetOnce(null),
-
-        var numShards: IntSetOnce = IntSetOnce(1),
-        var shard: IntSetOnce = IntSetOnce(0),
-) {
-    companion object {
-
-        private fun parsePackageRedirect(fromColonTo: String): Pair<String, String> {
-            val colon = fromColonTo.indexOf(':')
-            if ((colon < 1) || (colon + 1 >= fromColonTo.length)) {
-                throw ArgumentsException("--package-redirect must be a colon-separated string")
-            }
-            // TODO check for duplicates
-            return Pair(fromColonTo.substring(0, colon), fromColonTo.substring(colon + 1))
+    override fun checkArgs() {
+        if (!inJar.isSet) {
+            throw ArgumentsException("Required option missing: --in-jar")
+        }
+        if (!outJar.isSet) {
+            log.w("--out-jar is not set. $executableName will not generate jar files.")
+        }
+        if (numShards.isSet != shard.isSet) {
+            throw ArgumentsException("--num-shards and --shard-index must be used together")
         }
 
-        fun parseArgs(args: Array<String>): HostStubGenOptions {
-            val ret = HostStubGenOptions()
-
-            val ai = ArgIterator.withAtFiles(args)
-
-            var allAnnotations = mutableSetOf<String>()
-
-            fun ensureUniqueAnnotation(name: String): String {
-                if (!allAnnotations.add(name)) {
-                    throw DuplicateAnnotationException(ai.current)
-                }
-                return name
+        if (numShards.isSet) {
+            if (shard.get >= numShards.get) {
+                throw ArgumentsException("--shard-index must be smaller than --num-shards")
             }
-
-            while (true) {
-                val arg = ai.nextArgOptional() ?: break
-
-                // Define some shorthands...
-                fun nextArg(): String = ai.nextArgRequired(arg)
-                fun MutableSet<String>.addUniqueAnnotationArg(): String =
-                        nextArg().also { this += ensureUniqueAnnotation(it) }
-
-                if (log.maybeHandleCommandLineArg(arg) { nextArg() }) {
-                    continue
-                }
-                try {
-                    when (arg) {
-                        // TODO: Write help
-                        "-h", "--help" -> TODO("Help is not implemented yet")
-
-                        "--in-jar" -> ret.inJar.set(nextArg()).ensureFileExists()
-                        // We support both arguments because some AOSP dependencies
-                        // still use the old argument
-                        "--out-jar", "--out-impl-jar" -> ret.outJar.set(nextArg())
-
-                        "--policy-override-file" ->
-                            ret.policyOverrideFiles.add(nextArg().ensureFileExists())
-
-                        "--clean-up-on-error" -> ret.cleanUpOnError.set(true)
-                        "--no-clean-up-on-error" -> ret.cleanUpOnError.set(false)
-
-                        "--default-remove" -> ret.defaultPolicy.set(FilterPolicy.Remove)
-                        "--default-throw" -> ret.defaultPolicy.set(FilterPolicy.Throw)
-                        "--default-keep" -> ret.defaultPolicy.set(FilterPolicy.Keep)
-
-                        "--keep-annotation" ->
-                            ret.keepAnnotations.addUniqueAnnotationArg()
-
-                        "--keep-class-annotation" ->
-                            ret.keepClassAnnotations.addUniqueAnnotationArg()
-
-                        "--partially-allowed-annotation" ->
-                            ret.partiallyAllowedAnnotations.addUniqueAnnotationArg()
-
-                        "--throw-annotation" ->
-                            ret.throwAnnotations.addUniqueAnnotationArg()
-
-                        "--remove-annotation" ->
-                            ret.removeAnnotations.addUniqueAnnotationArg()
-
-                        "--ignore-annotation" ->
-                            ret.ignoreAnnotations.addUniqueAnnotationArg()
-
-                        "--substitute-annotation" ->
-                            ret.substituteAnnotations.addUniqueAnnotationArg()
-
-                        "--redirect-annotation" ->
-                            ret.redirectAnnotations.addUniqueAnnotationArg()
-
-                        "--redirection-class-annotation" ->
-                            ret.redirectionClassAnnotations.addUniqueAnnotationArg()
-
-                        "--class-load-hook-annotation" ->
-                            ret.classLoadHookAnnotations.addUniqueAnnotationArg()
-
-                        "--keep-static-initializer-annotation" ->
-                            ret.keepStaticInitializerAnnotations.addUniqueAnnotationArg()
-
-                        "--package-redirect" ->
-                            ret.packageRedirects += parsePackageRedirect(nextArg())
-
-                        "--annotation-allowed-classes-file" ->
-                            ret.annotationAllowedClassesFile.set(nextArg())
-
-                        "--default-class-load-hook" ->
-                            ret.defaultClassLoadHook.set(nextArg())
-
-                        "--default-method-call-hook" ->
-                            ret.defaultMethodCallHook.set(nextArg())
-
-                        "--gen-keep-all-file" ->
-                            ret.inputJarAsKeepAllFile.set(nextArg())
-
-                        "--delete-finals" -> ret.deleteFinals.set(true)
-
-                        // Following options are for debugging.
-                        "--enable-class-checker" -> ret.enableClassChecker.set(true)
-                        "--no-class-checker" -> ret.enableClassChecker.set(false)
-
-                        "--enable-pre-trace" -> ret.enablePreTrace.set(true)
-                        "--no-pre-trace" -> ret.enablePreTrace.set(false)
-
-                        "--enable-post-trace" -> ret.enablePostTrace.set(true)
-                        "--no-post-trace" -> ret.enablePostTrace.set(false)
-
-                        "--gen-input-dump-file" -> ret.inputJarDumpFile.set(nextArg())
-
-                        "--stats-file" -> ret.statsFile.set(nextArg())
-                        "--supported-api-list-file" -> ret.apiListFile.set(nextArg())
-
-                        "--num-shards" -> ret.numShards.set(nextArg()).also {
-                            if (it < 1) {
-                                throw ArgumentsException("$arg must be positive integer")
-                            }
-                        }
-                        "--shard-index" -> ret.shard.set(nextArg()).also {
-                            if (it < 0) {
-                                throw ArgumentsException("$arg must be positive integer or zero")
-                            }
-                        }
-
-                        else -> throw ArgumentsException("Unknown option: $arg")
-                    }
-                } catch (e: SetOnce.SetMoreThanOnceException) {
-                    throw ArgumentsException("Duplicate or conflicting argument found: $arg")
-                }
-            }
-
-            if (!ret.inJar.isSet) {
-                throw ArgumentsException("Required option missing: --in-jar")
-            }
-            if (!ret.outJar.isSet) {
-                log.w("--out-jar is not set. $executableName will not generate jar files.")
-            }
-            if (ret.numShards.isSet != ret.shard.isSet) {
-                throw ArgumentsException("--num-shards and --shard-index must be used together")
-            }
-
-            if (ret.numShards.isSet) {
-                if (ret.shard.get >= ret.numShards.get) {
-                    throw ArgumentsException("--shard-index must be smaller than --num-shards")
-                }
-            }
-
-            return ret
         }
     }
 
-    override fun toString(): String {
+    override fun parseOption(option: String, ai: ArgIterator): Boolean {
+        // Define some shorthands...
+        fun nextArg(): String = ai.nextArgRequired(option)
+
+        when (option) {
+            // TODO: Write help
+            "-h", "--help" -> TODO("Help is not implemented yet")
+
+            "--in-jar" -> inJar.set(nextArg()).ensureFileExists()
+            // We support both arguments because some AOSP dependencies
+            // still use the old argument
+            "--out-jar", "--out-impl-jar" -> outJar.set(nextArg())
+
+            "--clean-up-on-error" -> cleanUpOnError.set(true)
+            "--no-clean-up-on-error" -> cleanUpOnError.set(false)
+
+            "--gen-input-dump-file" -> inputJarDumpFile.set(nextArg())
+            "--gen-keep-all-file" -> inputJarAsKeepAllFile.set(nextArg())
+
+            "--stats-file" -> statsFile.set(nextArg())
+            "--supported-api-list-file" -> apiListFile.set(nextArg())
+
+            "--num-shards" -> numShards.set(nextArg()).also {
+                if (it < 1) {
+                    throw ArgumentsException("$option must be positive integer")
+                }
+            }
+            "--shard-index" -> shard.set(nextArg()).also {
+                if (it < 0) {
+                    throw ArgumentsException("$option must be positive integer or zero")
+                }
+            }
+
+            else -> return super.parseOption(option, ai)
+        }
+
+        return true
+    }
+
+    override fun dumpFields(): String {
         return """
-            HostStubGenOptions{
-              inJar='$inJar',
-              outJar='$outJar',
-              inputJarDumpFile=$inputJarDumpFile,
-              inputJarAsKeepAllFile=$inputJarAsKeepAllFile,
-              keepAnnotations=$keepAnnotations,
-              throwAnnotations=$throwAnnotations,
-              removeAnnotations=$removeAnnotations,
-              ignoreAnnotations=$ignoreAnnotations,
-              keepClassAnnotations=$keepClassAnnotations,
-              partiallyAllowedAnnotations=$partiallyAllowedAnnotations,
-              substituteAnnotations=$substituteAnnotations,
-              nativeSubstituteAnnotations=$redirectionClassAnnotations,
-              classLoadHookAnnotations=$classLoadHookAnnotations,
-              keepStaticInitializerAnnotations=$keepStaticInitializerAnnotations,
-              packageRedirects=$packageRedirects,
-              annotationAllowedClassesFile=$annotationAllowedClassesFile,
-              defaultClassLoadHook=$defaultClassLoadHook,
-              defaultMethodCallHook=$defaultMethodCallHook,
-              policyOverrideFiles=${policyOverrideFiles.toTypedArray().contentToString()},
-              defaultPolicy=$defaultPolicy,
-              deleteFinals=$deleteFinals,
-              cleanUpOnError=$cleanUpOnError,
-              enableClassChecker=$enableClassChecker,
-              enablePreTrace=$enablePreTrace,
-              enablePostTrace=$enablePostTrace,
-              statsFile=$statsFile,
-              apiListFile=$apiListFile,
-              numShards=$numShards,
-              shard=$shard,
-            }
-            """.trimIndent()
+            inJar=$inJar,
+            outJar=$outJar,
+            inputJarDumpFile=$inputJarDumpFile,
+            inputJarAsKeepAllFile=$inputJarAsKeepAllFile,
+            cleanUpOnError=$cleanUpOnError,
+            statsFile=$statsFile,
+            apiListFile=$apiListFile,
+            numShards=$numShards,
+            shard=$shard,
+        """.trimIndent() + '\n' + super.dumpFields()
     }
 }
-
-class ArgIterator(
-    private val args: List<String>,
-    private var currentIndex: Int = -1
-) {
-    val current: String
-        get() = args.get(currentIndex)
-
-    /**
-     * Get the next argument, or [null] if there's no more arguments.
-     */
-    fun nextArgOptional(): String? {
-        if ((currentIndex + 1) >= args.size) {
-            return null
-        }
-        return args.get(++currentIndex)
-    }
-
-    /**
-     * Get the next argument, or throw if
-     */
-    fun nextArgRequired(argName: String): String {
-        nextArgOptional().let {
-            if (it == null) {
-                throw ArgumentsException("Missing parameter for option $argName")
-            }
-            if (it.isEmpty()) {
-                throw ArgumentsException("Parameter can't be empty for option $argName")
-            }
-            return it
-        }
-    }
-
-    companion object {
-        fun withAtFiles(args: Array<String>): ArgIterator {
-            return ArgIterator(expandAtFiles(args))
-        }
-    }
-}
-
-/**
- * Scan the arguments, and if any of them starts with an `@`, then load from the file
- * and use its content as arguments.
- *
- * In order to pass an argument that starts with an '@', use '@@' instead.
- *
- * In this file, each line is treated as a single argument.
- *
- * The file can contain '#' as comments.
- */
-private fun expandAtFiles(args: Array<String>): List<String> {
-    val ret = mutableListOf<String>()
-
-    args.forEach { arg ->
-        if (arg.startsWith("@@")) {
-            ret += arg.substring(1)
-            return@forEach
-        } else if (!arg.startsWith('@')) {
-            ret += arg
-            return@forEach
-        }
-        // Read from the file, and add each line to the result.
-        val filename = arg.substring(1).ensureFileExists()
-
-        log.v("Expanding options file $filename")
-
-        BufferedReader(FileReader(filename)).use { reader ->
-            while (true) {
-                var line = reader.readLine()
-                if (line == null) {
-                    break // EOF
-                }
-
-                line = normalizeTextLine(line)
-                if (line.isNotEmpty()) {
-                    ret += line
-                }
-            }
-        }
-    }
-    return ret
-}
diff --git a/ravenwood/tools/ravenhelper/Android.bp b/ravenwood/tools/ravenhelper/Android.bp
index 3da6dd8..b279147 100644
--- a/ravenwood/tools/ravenhelper/Android.bp
+++ b/ravenwood/tools/ravenhelper/Android.bp
@@ -14,13 +14,7 @@
     static_libs: [
         "guava",
         "hoststubgen-lib",
-        "junit",
         "metalava-gradle-plugin-deps", // Get lint/PSI related classes from here.
-        "ow2-asm",
-        "ow2-asm-analysis",
-        "ow2-asm-commons",
-        "ow2-asm-tree",
-        "ow2-asm-util",
     ],
     visibility: ["//visibility:public"],
 }
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt
index 08bd95f..f7fd080 100644
--- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaOptions.kt
@@ -15,11 +15,11 @@
  */
 package com.android.platform.test.ravenwood.ravenhelper.policytoannot
 
-import com.android.hoststubgen.ArgIterator
 import com.android.hoststubgen.ArgumentsException
-import com.android.hoststubgen.SetOnce
 import com.android.hoststubgen.ensureFileExists
-import com.android.hoststubgen.log
+import com.android.hoststubgen.utils.ArgIterator
+import com.android.hoststubgen.utils.BaseOptions
+import com.android.hoststubgen.utils.SetOnce
 
 /**
  * Options for the "ravenhelper pta" subcommand.
@@ -39,68 +39,48 @@
 
     /** Dump the operations (for debugging) */
     var dumpOperations: SetOnce<Boolean> = SetOnce(false),
-) {
-    companion object {
-        fun parseArgs(args: List<String>): PtaOptions {
-            val ret = PtaOptions()
-            val ai = ArgIterator.withAtFiles(args.toTypedArray())
+) : BaseOptions() {
 
-            while (true) {
-                val arg = ai.nextArgOptional() ?: break
+    override fun parseOption(option: String, ai: ArgIterator): Boolean {
+        fun nextArg(): String = ai.nextArgRequired(option)
 
-                fun nextArg(): String = ai.nextArgRequired(arg)
+        when (option) {
+            // TODO: Write help
+            "-h", "--help" -> TODO("Help is not implemented yet")
 
-                if (log.maybeHandleCommandLineArg(arg) { nextArg() }) {
-                    continue
-                }
-                try {
-                    when (arg) {
-                        // TODO: Write help
-                        "-h", "--help" -> TODO("Help is not implemented yet")
+            "-p", "--policy-override-file" ->
+                policyOverrideFiles.add(nextArg().ensureFileExists())
 
-                        "-p", "--policy-override-file" ->
-                            ret.policyOverrideFiles.add(nextArg().ensureFileExists())
+            "-a", "--annotation-allowed-classes-file" ->
+                annotationAllowedClassesFile.set(nextArg().ensureFileExists())
 
-                        "-a", "--annotation-allowed-classes-file" ->
-                            ret.annotationAllowedClassesFile.set(nextArg().ensureFileExists())
+            "-s", "--src" -> sourceFilesOrDirectories.add(nextArg().ensureFileExists())
+            "--dump" -> dumpOperations.set(true)
+            "-o", "--output-script" -> outputScriptFile.set(nextArg())
 
-                        "-s", "--src" ->
-                            ret.sourceFilesOrDirectories.add(nextArg().ensureFileExists())
+            else -> return false
+        }
 
-                        "--dump" ->
-                            ret.dumpOperations.set(true)
+        return true
+    }
 
-                        "-o", "--output-script" ->
-                            ret.outputScriptFile.set(nextArg())
+    override fun checkArgs() {
+        if (policyOverrideFiles.size == 0) {
+            throw ArgumentsException("Must specify at least one policy file")
+        }
 
-                        else -> throw ArgumentsException("Unknown option: $arg")
-                    }
-                } catch (e: SetOnce.SetMoreThanOnceException) {
-                    throw ArgumentsException("Duplicate or conflicting argument found: $arg")
-                }
-            }
-
-            if (ret.policyOverrideFiles.size == 0) {
-                throw ArgumentsException("Must specify at least one policy file")
-            }
-
-            if (ret.sourceFilesOrDirectories.size == 0) {
-                throw ArgumentsException("Must specify at least one source path")
-            }
-
-            return ret
+        if (sourceFilesOrDirectories.size == 0) {
+            throw ArgumentsException("Must specify at least one source path")
         }
     }
 
-    override fun toString(): String {
+    override fun dumpFields(): String {
         return """
-            PtaOptions{
-              policyOverrideFiles=$policyOverrideFiles
-              annotationAllowedClassesFile=$annotationAllowedClassesFile
-              sourceFilesOrDirectories=$sourceFilesOrDirectories
-              outputScriptFile=$outputScriptFile
-              dumpOperations=$dumpOperations
-            }
-            """.trimIndent()
+            policyOverrideFiles=$policyOverrideFiles
+            annotationAllowedClassesFile=$annotationAllowedClassesFile
+            sourceFilesOrDirectories=$sourceFilesOrDirectories
+            outputScriptFile=$outputScriptFile
+            dumpOperations=$dumpOperations
+        """.trimIndent()
     }
-}
\ No newline at end of file
+}
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt
index a7f481a..fd6f732 100644
--- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/policytoannot/PtaProcessor.kt
@@ -39,7 +39,7 @@
  */
 class PtaProcessor : SubcommandHandler {
     override fun handle(args: List<String>) {
-        val options = PtaOptions.parseArgs(args)
+        val options = PtaOptions().apply { parseArgs(args) }
 
         log.v("Options: $options")
 
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt
index ee200bb..8b95843 100644
--- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MapOptions.kt
@@ -15,11 +15,11 @@
  */
 package com.android.platform.test.ravenwood.ravenhelper.sourcemap
 
-import com.android.hoststubgen.ArgIterator
 import com.android.hoststubgen.ArgumentsException
-import com.android.hoststubgen.SetOnce
 import com.android.hoststubgen.ensureFileExists
-import com.android.hoststubgen.log
+import com.android.hoststubgen.utils.ArgIterator
+import com.android.hoststubgen.utils.BaseOptions
+import com.android.hoststubgen.utils.SetOnce
 
 /**
  * Options for the "ravenhelper map" subcommand.
@@ -36,60 +36,36 @@
 
     /** Text to insert. */
     var text: SetOnce<String?> = SetOnce(null),
-) {
-    companion object {
-        fun parseArgs(args: List<String>): MapOptions {
-            val ret = MapOptions()
-            val ai = ArgIterator.withAtFiles(args.toTypedArray())
+) : BaseOptions() {
 
-            while (true) {
-                val arg = ai.nextArgOptional() ?: break
+    override fun parseOption(option: String, ai: ArgIterator): Boolean {
+        fun nextArg(): String = ai.nextArgRequired(option)
 
-                fun nextArg(): String = ai.nextArgRequired(arg)
+        when (option) {
+            // TODO: Write help
+            "-h", "--help" -> TODO("Help is not implemented yet")
+            "-s", "--src" -> sourceFilesOrDirectories.add(nextArg().ensureFileExists())
+            "-i", "--input" -> targetMethodFiles.add(nextArg().ensureFileExists())
+            "-o", "--output-script" -> outputScriptFile.set(nextArg())
+            "-t", "--text" -> text.set(nextArg())
+            else -> return false
+        }
 
-                if (log.maybeHandleCommandLineArg(arg) { nextArg() }) {
-                    continue
-                }
-                try {
-                    when (arg) {
-                        // TODO: Write help
-                        "-h", "--help" -> TODO("Help is not implemented yet")
+        return true
+    }
 
-                        "-s", "--src" ->
-                            ret.sourceFilesOrDirectories.add(nextArg().ensureFileExists())
-
-                        "-i", "--input" ->
-                            ret.targetMethodFiles.add(nextArg().ensureFileExists())
-
-                        "-o", "--output-script" ->
-                            ret.outputScriptFile.set(nextArg())
-
-                        "-t", "--text" ->
-                            ret.text.set(nextArg())
-
-                        else -> throw ArgumentsException("Unknown option: $arg")
-                    }
-                } catch (e: SetOnce.SetMoreThanOnceException) {
-                    throw ArgumentsException("Duplicate or conflicting argument found: $arg")
-                }
-            }
-
-            if (ret.sourceFilesOrDirectories.size == 0) {
-                throw ArgumentsException("Must specify at least one source path")
-            }
-
-            return ret
+    override fun checkArgs() {
+        if (sourceFilesOrDirectories.size == 0) {
+            throw ArgumentsException("Must specify at least one source path")
         }
     }
 
-    override fun toString(): String {
+    override fun dumpFields(): String {
         return """
-            PtaOptions{
-              sourceFilesOrDirectories=$sourceFilesOrDirectories
-              targetMethods=$targetMethodFiles
-              outputScriptFile=$outputScriptFile
-              text=$text
-            }
-            """.trimIndent()
+            sourceFilesOrDirectories=$sourceFilesOrDirectories
+            targetMethods=$targetMethodFiles
+            outputScriptFile=$outputScriptFile
+            text=$text
+        """.trimIndent()
     }
-}
\ No newline at end of file
+}
diff --git a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MarkMethodHandler.kt b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MarkMethodHandler.kt
index 8085253..f1c1398 100644
--- a/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MarkMethodHandler.kt
+++ b/ravenwood/tools/ravenhelper/src/com/android/platform/test/ravenwood/ravenhelper/sourcemap/MarkMethodHandler.kt
@@ -35,7 +35,7 @@
  */
 class MarkMethodHandler : SubcommandHandler {
     override fun handle(args: List<String>) {
-        val options = MapOptions.parseArgs(args)
+        val options = MapOptions().apply { parseArgs(args) }
 
         log.i("Options: $options")
 
diff --git a/ravenwood/tools/ravenizer/Android.bp b/ravenwood/tools/ravenizer/Android.bp
index a52a04b..957e206 100644
--- a/ravenwood/tools/ravenizer/Android.bp
+++ b/ravenwood/tools/ravenizer/Android.bp
@@ -13,12 +13,6 @@
     srcs: ["src/**/*.kt"],
     static_libs: [
         "hoststubgen-lib",
-        "ow2-asm",
-        "ow2-asm-analysis",
-        "ow2-asm-commons",
-        "ow2-asm-tree",
-        "ow2-asm-util",
-        "junit",
         "ravenwood-junit-for-ravenizer",
     ],
     visibility: ["//visibility:public"],
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerMain.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerMain.kt
index aee4530..7f4829e 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerMain.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerMain.kt
@@ -21,6 +21,21 @@
 import com.android.hoststubgen.executableName
 import com.android.hoststubgen.log
 import com.android.hoststubgen.runMainWithBoilerplate
+import java.nio.file.Paths
+import kotlin.io.path.exists
+
+/**
+ * If this file exits, we also read options from it. This is "unsafe" because it could break
+ * incremental builds, if it sets any flag that affects the output file.
+ * (however, for now, there's no such options.)
+ *
+ * For example, to enable verbose logging, do `echo '-v' > ~/.raveniezr-unsafe`
+ *
+ * (but even the content of this file changes, soong won't rerun the command, so you need to
+ * remove the output first and then do a build again.)
+ */
+private val RAVENIZER_DOTFILE = System.getenv("HOME") + "/.ravenizer-unsafe"
+
 
 /**
  * Entry point.
@@ -30,7 +45,15 @@
     log.setConsoleLogLevel(LogLevel.Info)
 
     runMainWithBoilerplate {
-        val options = RavenizerOptions.parseArgs(args)
+        var newArgs = args.asList()
+        if (Paths.get(RAVENIZER_DOTFILE).exists()) {
+            log.i("Reading options from $RAVENIZER_DOTFILE")
+            newArgs = args.toMutableList().apply {
+                add(0, "@$RAVENIZER_DOTFILE")
+            }
+        }
+
+        val options = RavenizerOptions().apply { parseArgs(newArgs) }
 
         log.i("$executableName started")
         log.v("Options: $options")
diff --git a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
index a0e5599..2c03654 100644
--- a/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
+++ b/ravenwood/tools/ravenizer/src/com/android/platform/test/ravenwood/ravenizer/RavenizerOptions.kt
@@ -15,25 +15,11 @@
  */
 package com.android.platform.test.ravenwood.ravenizer
 
-import com.android.hoststubgen.ArgIterator
 import com.android.hoststubgen.ArgumentsException
-import com.android.hoststubgen.SetOnce
 import com.android.hoststubgen.ensureFileExists
-import com.android.hoststubgen.log
-import java.nio.file.Paths
-import kotlin.io.path.exists
-
-/**
- * If this file exits, we also read options from it. This is "unsafe" because it could break
- * incremental builds, if it sets any flag that affects the output file.
- * (however, for now, there's no such options.)
- *
- * For example, to enable verbose logging, do `echo '-v' > ~/.raveniezr-unsafe`
- *
- * (but even the content of this file changes, soong won't rerun the command, so you need to
- * remove the output first and then do a build again.)
- */
-private val RAVENIZER_DOTFILE = System.getenv("HOME") + "/.raveniezr-unsafe"
+import com.android.hoststubgen.utils.ArgIterator
+import com.android.hoststubgen.utils.BaseOptions
+import com.android.hoststubgen.utils.SetOnce
 
 class RavenizerOptions(
     /** Input jar file*/
@@ -50,72 +36,49 @@
 
     /** Whether to remove mockito and dexmaker classes. */
     var stripMockito: SetOnce<Boolean> = SetOnce(false),
-) {
-    companion object {
+) : BaseOptions() {
 
-        fun parseArgs(origArgs: Array<String>): RavenizerOptions {
-            val args = origArgs.toMutableList()
-            if (Paths.get(RAVENIZER_DOTFILE).exists()) {
-                log.i("Reading options from $RAVENIZER_DOTFILE")
-                args.add(0, "@$RAVENIZER_DOTFILE")
-            }
+    override fun parseOption(option: String, ai: ArgIterator): Boolean {
+        fun nextArg(): String = ai.nextArgRequired(option)
 
-            val ret = RavenizerOptions()
-            val ai = ArgIterator.withAtFiles(args.toTypedArray())
+        when (option) {
+            // TODO: Write help
+            "-h", "--help" -> TODO("Help is not implemented yet")
 
-            while (true) {
-                val arg = ai.nextArgOptional()
-                if (arg == null) {
-                    break
-                }
+            "--in-jar" -> inJar.set(nextArg()).ensureFileExists()
+            "--out-jar" -> outJar.set(nextArg())
 
-                fun nextArg(): String = ai.nextArgRequired(arg)
+            "--enable-validation" -> enableValidation.set(true)
+            "--disable-validation" -> enableValidation.set(false)
 
-                if (log.maybeHandleCommandLineArg(arg) { nextArg() }) {
-                    continue
-                }
-                try {
-                    when (arg) {
-                        // TODO: Write help
-                        "-h", "--help" -> TODO("Help is not implemented yet")
+            "--fatal-validation" -> fatalValidation.set(true)
+            "--no-fatal-validation" -> fatalValidation.set(false)
 
-                        "--in-jar" -> ret.inJar.set(nextArg()).ensureFileExists()
-                        "--out-jar" -> ret.outJar.set(nextArg())
+            "--strip-mockito" -> stripMockito.set(true)
+            "--no-strip-mockito" -> stripMockito.set(false)
 
-                        "--enable-validation" -> ret.enableValidation.set(true)
-                        "--disable-validation" -> ret.enableValidation.set(false)
+            else -> return false
+        }
 
-                        "--fatal-validation" -> ret.fatalValidation.set(true)
-                        "--no-fatal-validation" -> ret.fatalValidation.set(false)
+        return true
+    }
 
-                        "--strip-mockito" -> ret.stripMockito.set(true)
-                        "--no-strip-mockito" -> ret.stripMockito.set(false)
-
-                        else -> throw ArgumentsException("Unknown option: $arg")
-                    }
-                } catch (e: SetOnce.SetMoreThanOnceException) {
-                    throw ArgumentsException("Duplicate or conflicting argument found: $arg")
-                }
-            }
-
-            if (!ret.inJar.isSet) {
-                throw ArgumentsException("Required option missing: --in-jar")
-            }
-            if (!ret.outJar.isSet) {
-                throw ArgumentsException("Required option missing: --out-jar")
-            }
-           return ret
+    override fun checkArgs() {
+        if (!inJar.isSet) {
+            throw ArgumentsException("Required option missing: --in-jar")
+        }
+        if (!outJar.isSet) {
+            throw ArgumentsException("Required option missing: --out-jar")
         }
     }
 
-    override fun toString(): String {
+    override fun dumpFields(): String {
         return """
-            RavenizerOptions{
-              inJar=$inJar,
-              outJar=$outJar,
-              enableValidation=$enableValidation,
-              fatalValidation=$fatalValidation,
-            }
-            """.trimIndent()
+            inJar=$inJar,
+            outJar=$outJar,
+            enableValidation=$enableValidation,
+            fatalValidation=$fatalValidation,
+            stripMockito=$stripMockito,
+        """.trimIndent()
     }
 }
diff --git a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
index 42834ce..c49151d 100644
--- a/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
+++ b/services/accessibility/java/com/android/server/accessibility/AccessibilityManagerService.java
@@ -287,7 +287,8 @@
 
     public static final int INVALID_SERVICE_ID = -1;
 
-    // Each service has an ID. Also provide one for magnification gesture handling
+    // Each service has an ID. Also provide one for magnification gesture handling.
+    // This ID is also used for mouse event handling.
     public static final int MAGNIFICATION_GESTURE_HANDLER_ID = 0;
 
     private static int sIdCounter = MAGNIFICATION_GESTURE_HANDLER_ID + 1;
diff --git a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java
index 57bbb4a..90ddc43 100644
--- a/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java
+++ b/services/accessibility/java/com/android/server/accessibility/autoclick/AutoclickTypePanel.java
@@ -86,13 +86,6 @@
     })
     public @interface Corner {}
 
-    private static final @Corner int[] CORNER_ROTATION_ORDER = {
-            CORNER_BOTTOM_RIGHT,
-            CORNER_BOTTOM_LEFT,
-            CORNER_TOP_LEFT,
-            CORNER_TOP_RIGHT
-    };
-
     // An interface exposed to {@link AutoclickController) to handle different actions on the panel,
     // including changing autoclick type, pausing/resuming autoclick.
     public interface ClickPanelControllerInterface {
@@ -136,10 +129,9 @@
 
     // Whether autoclick is paused.
     private boolean mPaused = false;
-    // Tracks the current corner position of the panel using an index into CORNER_ROTATION_ORDER
-    // array. This allows the panel to cycle through screen corners in a defined sequence when
-    // repositioned.
-    private int mCurrentCornerIndex = 0;
+
+    // The current corner position of the panel, default to bottom right.
+    private @Corner int mCurrentCorner = CORNER_BOTTOM_RIGHT;
 
     private final LinearLayout mLeftClickButton;
     private final LinearLayout mRightClickButton;
@@ -257,13 +249,13 @@
             params.gravity = Gravity.START | Gravity.TOP;
             // Set the current corner to be bottom-left to ensure that the subsequent reposition
             // action rotates the panel clockwise from bottom-left towards top-left.
-            mCurrentCornerIndex = 1;
+            mCurrentCorner = CORNER_BOTTOM_LEFT;
         } else {
             // Snap to right edge. Set params.gravity to make sure x, y offsets from correct anchor.
             params.gravity = Gravity.END | Gravity.TOP;
             // Set the current corner to be top-right to ensure that the subsequent reposition
             // action rotates the panel clockwise from top-right towards bottom-right.
-            mCurrentCornerIndex = 3;
+            mCurrentCorner = CORNER_TOP_RIGHT;
         }
 
         // Apply final position: set params.x to be edge margin, params.y to maintain vertical
@@ -415,10 +407,10 @@
 
     /** Moves the panel to the next corner in clockwise direction. */
     private void moveToNextCorner() {
-        @Corner int nextCornerIndex = (mCurrentCornerIndex + 1) % CORNER_ROTATION_ORDER.length;
-        mCurrentCornerIndex = nextCornerIndex;
+        @Corner int nextCorner = (mCurrentCorner + 1) % 4;
+        mCurrentCorner = nextCorner;
 
-        setPanelPositionForCorner(mParams, mCurrentCornerIndex);
+        setPanelPositionForCorner(mParams, mCurrentCorner);
         mWindowManager.updateViewLayout(mContentView, mParams);
     }
 
@@ -457,7 +449,7 @@
                 String.valueOf(mParams.gravity),
                 String.valueOf(mParams.x),
                 String.valueOf(mParams.y),
-                String.valueOf(mCurrentCornerIndex)
+                String.valueOf(mCurrentCorner)
         });
         Settings.Secure.putStringForUser(mContext.getContentResolver(),
                 ACCESSIBILITY_AUTOCLICK_PANEL_POSITION, positionString, mUserId);
@@ -473,7 +465,7 @@
                 ACCESSIBILITY_AUTOCLICK_PANEL_POSITION, mUserId);
         if (savedPosition == null) {
             setPanelPositionForCorner(mParams, CORNER_BOTTOM_RIGHT);
-            mCurrentCornerIndex = 0;
+            mCurrentCorner = CORNER_BOTTOM_RIGHT;
             return;
         }
 
@@ -481,7 +473,7 @@
         String[] parts = TextUtils.split(savedPosition, POSITION_DELIMITER);
         if (!isValidPositionParts(parts)) {
             setPanelPositionForCorner(mParams, CORNER_BOTTOM_RIGHT);
-            mCurrentCornerIndex = 0;
+            mCurrentCorner = CORNER_BOTTOM_RIGHT;
             return;
         }
 
@@ -489,7 +481,7 @@
         mParams.gravity = Integer.parseInt(parts[0]);
         mParams.x = Integer.parseInt(parts[1]);
         mParams.y = Integer.parseInt(parts[2]);
-        mCurrentCornerIndex = Integer.parseInt(parts[3]);
+        mCurrentCorner = Integer.parseInt(parts[3]);
     }
 
     private boolean isValidPositionParts(String[] parts) {
@@ -538,8 +530,8 @@
 
     @VisibleForTesting
     @Corner
-    int getCurrentCornerIndexForTesting() {
-        return mCurrentCornerIndex;
+    int getCurrentCornerForTesting() {
+        return mCurrentCorner;
     }
 
     @VisibleForTesting
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index fd230f6..fb32943 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -887,6 +887,9 @@
                     mSendHoverEnterAndMoveDelayed.cancel();
                     mSendHoverExitDelayed.cancel();
                 }
+                if (pointerIndex < 0) {
+                    return;
+                }
                 // If the user is touch exploring the second pointer may be
                 // performing a double tap to activate an item without need
                 // for the user to lift their exploring finger.
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
index 11b8ccb..004b3ff 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationController.java
@@ -121,6 +121,8 @@
     @NonNull private final Supplier<MagnificationThumbnail> mThumbnailSupplier;
     @NonNull private final Supplier<Boolean> mMagnificationConnectionStateSupplier;
 
+    private boolean mIsPointerMotionFilterInstalled = false;
+
     /**
      * This class implements {@link WindowManagerInternal.MagnificationCallbacks} and holds
      * magnification information per display.
@@ -830,9 +832,17 @@
                 return;
             }
 
-            final float nonNormOffsetX = mCurrentMagnificationSpec.offsetX - offsetX;
-            final float nonNormOffsetY = mCurrentMagnificationSpec.offsetY - offsetY;
-            if (updateCurrentSpecWithOffsetsLocked(nonNormOffsetX, nonNormOffsetY)) {
+            setOffset(mCurrentMagnificationSpec.offsetX - offsetX,
+                    mCurrentMagnificationSpec.offsetY - offsetY, id);
+        }
+
+        @GuardedBy("mLock")
+        void setOffset(float offsetX, float offsetY, int id) {
+            if (!mRegistered) {
+                return;
+            }
+
+            if (updateCurrentSpecWithOffsetsLocked(offsetX, offsetY)) {
                 onMagnificationChangedLocked(/* isScaleTransient= */ false);
             }
             if (id != INVALID_SERVICE_ID) {
@@ -1065,6 +1075,7 @@
             if (display.register()) {
                 mDisplays.put(displayId, display);
                 mScreenStateObserver.registerIfNecessary();
+                configurePointerMotionFilter(true);
             }
         }
     }
@@ -1613,6 +1624,28 @@
     }
 
     /**
+     * Sets the offset of the magnified region.
+     *
+     * @param displayId The logical display id.
+     * @param offsetX   the offset of the magnified region in the X coordinate, in current
+     *                  screen pixels.
+     * @param offsetY   the offset of the magnified region in the Y coordinate, in current
+     *                  screen pixels.
+     * @param id        the ID of the service requesting the change
+     */
+    @SuppressWarnings("GuardedBy")
+    // errorprone cannot recognize an inner class guarded by an outer class member.
+    public void setOffset(int displayId, float offsetX, float offsetY, int id) {
+        synchronized (mLock) {
+            final DisplayMagnification display = mDisplays.get(displayId);
+            if (display == null) {
+                return;
+            }
+            display.setOffset(offsetX, offsetY, id);
+        }
+    }
+
+    /**
      * Offsets the magnified region. Note that the offsetX and offsetY values actually move in the
      * opposite direction as the offsets passed in here.
      *
@@ -1885,6 +1918,7 @@
         }
         if (!hasRegister) {
             mScreenStateObserver.unregister();
+            configurePointerMotionFilter(false);
         }
     }
 
@@ -1900,6 +1934,22 @@
         }
     }
 
+    private void configurePointerMotionFilter(boolean enabled) {
+        if (!Flags.enableMagnificationFollowsMouseWithPointerMotionFilter()) {
+            return;
+        }
+        if (enabled == mIsPointerMotionFilterInstalled) {
+            return;
+        }
+        if (!enabled) {
+            mControllerCtx.getInputManager().registerAccessibilityPointerMotionFilter(null);
+        } else {
+            mControllerCtx.getInputManager().registerAccessibilityPointerMotionFilter(
+                    new FullScreenMagnificationPointerMotionEventFilter(this));
+        }
+        mIsPointerMotionFilterInstalled = enabled;
+    }
+
     private boolean traceEnabled() {
         return mControllerCtx.getTraceManager().isA11yTracingEnabledForTypes(
                 FLAGS_WINDOW_MANAGER_INTERNAL);
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index e0dd8b6..59b4a16 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -182,6 +182,7 @@
     private final int mMinimumVelocity;
     private final int mMaximumVelocity;
 
+    @Nullable
     private final MouseEventHandler mMouseEventHandler;
 
     public FullScreenMagnificationGestureHandler(
@@ -313,7 +314,9 @@
         mOverscrollEdgeSlop = context.getResources().getDimensionPixelSize(
                 R.dimen.accessibility_fullscreen_magnification_gesture_edge_slop);
         mIsWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
-        mMouseEventHandler = new MouseEventHandler(mFullScreenMagnificationController);
+        mMouseEventHandler =
+                Flags.enableMagnificationFollowsMouseWithPointerMotionFilter()
+                        ? null : new MouseEventHandler(mFullScreenMagnificationController);
 
         if (mDetectShortcutTrigger) {
             mScreenStateReceiver = new ScreenStateReceiver(context, this);
@@ -337,9 +340,11 @@
 
     @Override
     void handleMouseOrStylusEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
-        if (!mFullScreenMagnificationController.isActivated(mDisplayId)) {
+        if (mMouseEventHandler == null
+                || !mFullScreenMagnificationController.isActivated(mDisplayId)) {
             return;
         }
+
         // TODO(b/354696546): Allow mouse/stylus to activate whichever display they are
         // over, rather than only interacting with the current display.
 
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilter.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilter.java
new file mode 100644
index 0000000..f1ba83e
--- /dev/null
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilter.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.accessibility.magnification;
+
+import static com.android.server.accessibility.AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID;
+
+import android.annotation.NonNull;
+
+import com.android.server.input.InputManagerInternal;
+
+/**
+ * Handles pointer motion event for full screen magnification.
+ * Responsible for controlling magnification's cursor following feature.
+ */
+public class FullScreenMagnificationPointerMotionEventFilter implements
+        InputManagerInternal.AccessibilityPointerMotionFilter {
+
+    private final FullScreenMagnificationController mController;
+
+    public FullScreenMagnificationPointerMotionEventFilter(
+            FullScreenMagnificationController controller) {
+        mController = controller;
+    }
+
+    /**
+     * This call happens on the input hot path and it is extremely performance sensitive. It
+     * also must not call back into native code.
+     */
+    @Override
+    @NonNull
+    public float[] filterPointerMotionEvent(float dx, float dy, float currentX, float currentY,
+            int displayId) {
+        if (!mController.isActivated(displayId)) {
+            // unrelated display.
+            return new float[]{dx, dy};
+        }
+
+        // TODO(361817142): implement centered and edge following types.
+
+        // Continuous cursor following.
+        float scale = mController.getScale(displayId);
+        final float newCursorX = currentX + dx;
+        final float newCursorY = currentY + dy;
+        mController.setOffset(displayId,
+                newCursorX - newCursorX * scale, newCursorY - newCursorY * scale,
+                MAGNIFICATION_GESTURE_HANDLER_ID);
+
+        // In the continuous mode, the cursor speed in physical display is kept.
+        // Thus, we don't consume any motion delta.
+        return new float[]{dx, dy};
+    }
+}
diff --git a/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java b/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
index ce7dcd0..0310756 100644
--- a/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
+++ b/services/companion/java/com/android/server/companion/association/AssociationDiskStore.java
@@ -299,14 +299,24 @@
     public void writeLastRemovedAssociation(AssociationInfo association, String reason) {
         Slog.i(TAG, "Writing last removed association=" + association.getId() + " to disk...");
 
+        // Remove indirect identifier i.e. Mac Address
+        AssociationInfo.Builder builder = new AssociationInfo.Builder(association)
+                .setDeviceMacAddress(null);
+        // Set a placeholder display name if it's null because Mac Address and display name can't be
+        // both null.
+        if (association.getDisplayName() == null) {
+            builder.setDisplayName("");
+        }
+        AssociationInfo redactedAssociation = builder.build();
+
         final AtomicFile file = createStorageFileForUser(
-                association.getUserId(), FILE_NAME_LAST_REMOVED_ASSOCIATION);
+                redactedAssociation.getUserId(), FILE_NAME_LAST_REMOVED_ASSOCIATION);
         writeToFileSafely(file, out -> {
             out.write(String.valueOf(System.currentTimeMillis()).getBytes());
             out.write(' ');
             out.write(reason.getBytes());
             out.write(' ');
-            out.write(association.toString().getBytes());
+            out.write(redactedAssociation.toString().getBytes());
         });
     }
 
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 6c7c9b3..4c62c0d 100644
--- a/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
+++ b/services/companion/java/com/android/server/companion/securechannel/SecureChannel.java
@@ -73,6 +73,8 @@
     private int mVerificationResult = FLAG_FAILURE_UNKNOWN;
     private boolean mPskVerified;
 
+    private final Object mHandshakeLock = new Object();
+
 
     /**
      * Create a new secure channel object. This secure channel allows secure messages to be
@@ -342,20 +344,22 @@
     }
 
     private void initiateHandshake() throws IOException, BadHandleException , HandshakeException {
-        if (mConnectionContext != null) {
-            Slog.d(TAG, "Ukey2 handshake is already completed.");
-            return;
-        }
+        synchronized (mHandshakeLock) {
+            if (mConnectionContext != null) {
+                Slog.d(TAG, "Ukey2 handshake is already completed.");
+                return;
+            }
 
-        mRole = Role.INITIATOR;
-        mHandshakeContext = D2DHandshakeContext.forInitiator();
-        mClientInit = mHandshakeContext.getNextHandshakeMessage();
+            mRole = Role.INITIATOR;
+            mHandshakeContext = D2DHandshakeContext.forInitiator();
+            mClientInit = mHandshakeContext.getNextHandshakeMessage();
 
-        // Send Client Init
-        if (DEBUG) {
-            Slog.d(TAG, "Sending Ukey2 Client Init message");
+            // Send Client Init
+            if (DEBUG) {
+                Slog.d(TAG, "Sending Ukey2 Client Init message");
+            }
+            sendMessage(MessageType.HANDSHAKE_INIT, constructHandshakeInitMessage(mClientInit));
         }
-        sendMessage(MessageType.HANDSHAKE_INIT, constructHandshakeInitMessage(mClientInit));
     }
 
     // In an occasion where both participants try to initiate a handshake, resolve the conflict
@@ -414,8 +418,17 @@
         // Mark "in-progress" upon receiving the first message
         mInProgress = true;
 
+        // Complete a series of handshake exchange and processing
+        synchronized (mHandshakeLock) {
+            completeHandshake(handshakeInitMessage);
+        }
+    }
+
+    private void completeHandshake(byte[] initMessage) throws IOException, HandshakeException,
+            BadHandleException, CryptoException, AlertException {
+
         // Handle a potential collision where both devices tried to initiate a connection
-        byte[] handshakeMessage = handleHandshakeCollision(handshakeInitMessage);
+        byte[] handshakeMessage = handleHandshakeCollision(initMessage);
 
         // Proceed with the rest of Ukey2 handshake
         if (mHandshakeContext == null) { // Server-side logic
diff --git a/services/core/Android.bp b/services/core/Android.bp
index 2aaf6a9..14d9d3f 100644
--- a/services/core/Android.bp
+++ b/services/core/Android.bp
@@ -121,6 +121,13 @@
     out: ["com/android/server/location/contexthub/ContextHubStatsLog.java"],
 }
 
+genrule {
+  name: "statslog-mediarouter-java-gen",
+  tools: ["stats-log-api-gen"],
+  cmd: "$(location stats-log-api-gen) --java $(out) --module mediarouter --javaPackage com.android.server.media --javaClass MediaRouterStatsLog",
+  out: ["com/android/server/media/MediaRouterStatsLog.java"],
+}
+
 java_library_static {
     name: "services.core.unboosted",
     defaults: [
@@ -136,6 +143,7 @@
         ":android.hardware.tv.mediaquality-V1-java-source",
         ":statslog-art-java-gen",
         ":statslog-contexthub-java-gen",
+        ":statslog-mediarouter-java-gen",
         ":services.core-aidl-sources",
         ":services.core-sources",
         ":services.core.protologsrc",
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 296f7cf..f54027e 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -514,6 +514,7 @@
                 mCarModeEnabled = mDockState == Intent.EXTRA_DOCK_STATE_CAR;
                 registerVrStateListener();
                 // register listeners
+                // LINT.IfChange(fi_cb)
                 context.getContentResolver()
                         .registerContentObserver(Secure.getUriFor(Secure.UI_NIGHT_MODE),
                                 false, mDarkThemeObserver, 0);
@@ -523,6 +524,7 @@
                                     Secure.getUriFor(ACCESSIBILITY_FORCE_INVERT_COLOR_ENABLED),
                                     false, mForceInvertStateObserver, UserHandle.USER_ALL);
                 }
+                // LINT.ThenChange(/core/java/android/view/ViewRootImpl.java:fi_cb)
                 context.getContentResolver().registerContentObserver(
                         Secure.getUriFor(Secure.CONTRAST_LEVEL), false,
                         mContrastObserver, UserHandle.USER_ALL);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index 600b124..79fdcca 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -190,6 +190,7 @@
     }
 
     final Context mContext;
+    final PackageMonitor mPackageMonitor;
 
     private static final int[] INTERESTING_APP_OPS = new int[] {
         AppOpsManager.OP_GET_ACCOUNTS,
@@ -373,7 +374,7 @@
         }, UserHandle.ALL, userFilter, null, null);
 
         // Need to cancel account request notifications if the update/install can access the account
-        new PackageMonitor() {
+        mPackageMonitor = new PackageMonitor() {
             @Override
             public void onPackageAdded(String packageName, int uid) {
                 // Called on a handler, and running as the system
@@ -397,7 +398,8 @@
                     return;
                 }
             }
-        }.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
+        };
+        mPackageMonitor.register(mContext, mHandler.getLooper(), UserHandle.ALL, true);
 
         // Cancel account request notification if an app op was preventing the account access
         for (int i = 0; i < INTERESTING_APP_OPS.length; ++i) {
diff --git a/services/core/java/com/android/server/am/BroadcastController.java b/services/core/java/com/android/server/am/BroadcastController.java
index bec5db7..afd639d 100644
--- a/services/core/java/com/android/server/am/BroadcastController.java
+++ b/services/core/java/com/android/server/am/BroadcastController.java
@@ -1961,7 +1961,9 @@
 
     private void sendPackageBroadcastLocked(int cmd, String[] packages, int userId) {
         mService.mProcessList.sendPackageBroadcastLocked(cmd, packages, userId);
-    }private List<ResolveInfo> collectReceiverComponents(
+    }
+
+    private List<ResolveInfo> collectReceiverComponents(
             Intent intent, String resolvedType, int callingUid, int callingPid,
             int[] users, int[] broadcastAllowList) {
         // TODO: come back and remove this assumption to triage all broadcasts
diff --git a/services/core/java/com/android/server/am/BroadcastProcessedEventRecord.java b/services/core/java/com/android/server/am/BroadcastProcessedEventRecord.java
new file mode 100644
index 0000000..1bcedf6
--- /dev/null
+++ b/services/core/java/com/android/server/am/BroadcastProcessedEventRecord.java
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.am;
+
+import static com.android.internal.util.FrameworkStatsLog.BROADCAST_PROCESSED;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+
+import com.android.internal.util.FrameworkStatsLog;
+
+final class BroadcastProcessedEventRecord {
+
+    /**
+     * Minimum threshold for logging the broadcast processed event.
+     */
+    private static final int MIN_THRESHOLD_FOR_LOGGING_TIME_MILLIS = 10;
+
+    @Nullable
+    private String mIntentAction;
+
+    private int mSenderUid;
+
+    private int mReceiverUid;
+
+    private int mNumberOfReceivers;
+
+    @NonNull
+    private String mReceiverProcessName;
+
+    private long mTotalBroadcastFinishTimeMillis;
+
+    private long mMaxReceiverFinishTimeMillis = Long.MIN_VALUE;
+
+    @NonNull
+    private int[] mBroadcastTypes;
+
+    @NonNull
+    public BroadcastProcessedEventRecord setBroadcastTypes(@NonNull int[] broadcastTypes) {
+        this.mBroadcastTypes = broadcastTypes;
+        return this;
+    }
+
+    @NonNull
+    public BroadcastProcessedEventRecord setReceiverProcessName(
+            @NonNull String receiverProcessName) {
+        mReceiverProcessName = receiverProcessName;
+        return this;
+    }
+
+    @NonNull
+    public BroadcastProcessedEventRecord setIntentAction(@Nullable String intentAction) {
+        mIntentAction = intentAction;
+        return this;
+    }
+
+    @NonNull
+    public BroadcastProcessedEventRecord setSenderUid(int uid) {
+        mSenderUid = uid;
+        return this;
+    }
+
+    @NonNull
+    public BroadcastProcessedEventRecord setReceiverUid(int uid) {
+        mReceiverUid = uid;
+        return this;
+    }
+
+    public void addReceiverFinishTime(long timeMillis) {
+        mTotalBroadcastFinishTimeMillis += timeMillis;
+        mMaxReceiverFinishTimeMillis = Math.max(mMaxReceiverFinishTimeMillis, timeMillis);
+        mNumberOfReceivers++;
+    }
+
+    @Nullable
+    String getIntentActionForTest() {
+        return mIntentAction;
+    }
+
+    int getSenderUidForTest() {
+        return mSenderUid;
+    }
+
+    int getReceiverUidForTest() {
+        return mReceiverUid;
+    }
+
+    int getNumberOfReceiversForTest() {
+        return mNumberOfReceivers;
+    }
+
+    @NonNull
+    String getReceiverProcessNameForTest() {
+        return mReceiverProcessName;
+    }
+
+    long getTotalBroadcastFinishTimeMillisForTest() {
+        return mTotalBroadcastFinishTimeMillis;
+    }
+
+    long getMaxReceiverFinishTimeMillisForTest() {
+        return mMaxReceiverFinishTimeMillis;
+    }
+
+    @NonNull
+    int[] getBroadcastTypesForTest() {
+        return mBroadcastTypes;
+    }
+
+    public void logToStatsD() {
+        // We do not care about the processes where total time to process the
+        // broadcast is less than 10ms/ are quick to process the broadcast.
+        if (mTotalBroadcastFinishTimeMillis <= MIN_THRESHOLD_FOR_LOGGING_TIME_MILLIS) {
+            return;
+        }
+
+        FrameworkStatsLog.write(
+                BROADCAST_PROCESSED,
+                mIntentAction,
+                mSenderUid,
+                mReceiverUid,
+                mNumberOfReceivers,
+                mReceiverProcessName,
+                mTotalBroadcastFinishTimeMillis,
+                mMaxReceiverFinishTimeMillis,
+                mBroadcastTypes);
+    }
+}
diff --git a/services/core/java/com/android/server/am/BroadcastQueueImpl.java b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
index 78beb18..c76a0d0 100644
--- a/services/core/java/com/android/server/am/BroadcastQueueImpl.java
+++ b/services/core/java/com/android/server/am/BroadcastQueueImpl.java
@@ -2189,6 +2189,11 @@
             logBroadcastDeliveryEventReported(queue, app, r, index, receiver);
         }
 
+        if (!r.isAssumedDelivered(index) && r.wasDelivered(index)) {
+            r.updateBroadcastProcessedEventRecord(receiver,
+                    r.terminalTime[index] - r.scheduledTime[index]);
+        }
+
         final boolean recordFinished = (r.terminalCount == r.receivers.size());
         if (recordFinished) {
             notifyFinishBroadcast(r);
@@ -2254,6 +2259,7 @@
         mHistory.onBroadcastFinishedLocked(r);
 
         logBootCompletedBroadcastCompletionLatencyIfPossible(r);
+        r.logBroadcastProcessedEventRecord();
 
         if (r.intent.getComponent() == null && r.intent.getPackage() == null
                 && (r.intent.getFlags() & Intent.FLAG_RECEIVER_REGISTERED_ONLY) == 0) {
diff --git a/services/core/java/com/android/server/am/BroadcastRecord.java b/services/core/java/com/android/server/am/BroadcastRecord.java
index c1b0a76..45c7d59 100644
--- a/services/core/java/com/android/server/am/BroadcastRecord.java
+++ b/services/core/java/com/android/server/am/BroadcastRecord.java
@@ -167,6 +167,12 @@
     @Nullable
     private ArrayMap<BroadcastRecord, Boolean> mMatchingRecordsCache;
 
+    // Stores the {@link BroadcastProcessedEventRecord} for each process associated with this
+    // record.
+    @NonNull
+    private ArrayMap<String, BroadcastProcessedEventRecord> mBroadcastProcessedRecords =
+            new ArrayMap<>();
+
     private @Nullable String mCachedToString;
     private @Nullable String mCachedToShortString;
 
@@ -654,6 +660,17 @@
         }
     }
 
+    boolean wasDelivered(int index) {
+        final int deliveryState = getDeliveryState(index);
+        switch (deliveryState) {
+            case DELIVERY_DELIVERED:
+            case DELIVERY_TIMEOUT:
+                return true;
+            default:
+                return false;
+        }
+    }
+
     void copyEnqueueTimeFrom(@NonNull BroadcastRecord replacedBroadcast) {
         originalEnqueueClockTime = enqueueClockTime;
         enqueueTime = replacedBroadcast.enqueueTime;
@@ -1327,4 +1344,48 @@
         proto.write(BroadcastRecordProto.INTENT_ACTION, intent.getAction());
         proto.end(token);
     }
+
+    /**
+     * Uses the {@link BroadcastProcessedEventRecord} pojo to store the logging information related
+     * to {@param receiver} object.
+     */
+    public void updateBroadcastProcessedEventRecord(@NonNull Object receiver, long timeMillis) {
+        if (!Flags.logBroadcastProcessedEvent()) {
+            return;
+        }
+
+        final String receiverProcessName = getReceiverProcessName(receiver);
+        BroadcastProcessedEventRecord broadcastProcessedEventRecord =
+                mBroadcastProcessedRecords.get(receiverProcessName);
+        if (broadcastProcessedEventRecord == null) {
+            broadcastProcessedEventRecord = new BroadcastProcessedEventRecord()
+                    .setBroadcastTypes(calculateTypesForLogging())
+                    .setIntentAction(intent.getAction())
+                    .setReceiverProcessName(receiverProcessName)
+                    .setReceiverUid(getReceiverUid(receiver))
+                    .setSenderUid(callingUid);
+
+            mBroadcastProcessedRecords.put(receiverProcessName, broadcastProcessedEventRecord);
+        }
+
+        broadcastProcessedEventRecord.addReceiverFinishTime(timeMillis);
+    }
+
+    public void logBroadcastProcessedEventRecord() {
+        if (!Flags.logBroadcastProcessedEvent()) {
+            return;
+        }
+
+        int size = mBroadcastProcessedRecords.size();
+        for (int i = 0; i < size; i++) {
+            mBroadcastProcessedRecords.valueAt(i).logToStatsD();
+        }
+        mBroadcastProcessedRecords.clear();
+    }
+
+    @VisibleForTesting
+    @NonNull
+    ArrayMap<String, BroadcastProcessedEventRecord> getBroadcastProcessedRecordsForTest() {
+        return mBroadcastProcessedRecords;
+    }
 }
diff --git a/services/core/java/com/android/server/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 13d367a..336a35e 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -3433,8 +3433,12 @@
             // Process has user visible activities.
             return PROCESS_CAPABILITY_CPU_TIME;
         }
-        if (app.mServices.hasUndemotedShortForegroundService(nowUptime)) {
-            // It running a short fgs, just give it cpu time.
+        if (Flags.prototypeAggressiveFreezing()) {
+            if (app.mServices.hasUndemotedShortForegroundService(nowUptime)) {
+                // Grant cpu time for short FGS even when aggressively freezing.
+                return PROCESS_CAPABILITY_CPU_TIME;
+            }
+        } else if (app.mServices.hasForegroundServices()) {
             return PROCESS_CAPABILITY_CPU_TIME;
         }
         if (app.mReceivers.numberOfCurReceivers() > 0) {
diff --git a/services/core/java/com/android/server/am/PendingIntentRecord.java b/services/core/java/com/android/server/am/PendingIntentRecord.java
index 2c0366e..ac30be9 100644
--- a/services/core/java/com/android/server/am/PendingIntentRecord.java
+++ b/services/core/java/com/android/server/am/PendingIntentRecord.java
@@ -31,7 +31,6 @@
 
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_AM;
 import static com.android.server.am.ActivityManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.window.flags.Flags.balClearAllowlistDuration;
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
@@ -330,7 +329,7 @@
         mAllowBgActivityStartsForActivitySender.remove(token);
         mAllowBgActivityStartsForBroadcastSender.remove(token);
         mAllowBgActivityStartsForServiceSender.remove(token);
-        if (mAllowlistDuration != null && balClearAllowlistDuration()) {
+        if (mAllowlistDuration != null) {
             TempAllowListDuration duration = mAllowlistDuration.get(token);
             if (duration != null
                     && duration.type == TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED) {
diff --git a/services/core/java/com/android/server/am/ProcessRecord.java b/services/core/java/com/android/server/am/ProcessRecord.java
index 1503d88..eea667e 100644
--- a/services/core/java/com/android/server/am/ProcessRecord.java
+++ b/services/core/java/com/android/server/am/ProcessRecord.java
@@ -1443,17 +1443,32 @@
 
     void onProcessFrozen() {
         mProfile.onProcessFrozen();
-        if (mThread != null) mThread.onProcessPaused();
+        final ApplicationThreadDeferred t;
+        synchronized (mService) {
+            t = mThread;
+        }
+        // Release the lock before calling the notifier, in case that calls back into AM.
+        if (t != null) t.onProcessPaused();
     }
 
     void onProcessUnfrozen() {
-        if (mThread != null) mThread.onProcessUnpaused();
+        final ApplicationThreadDeferred t;
+        synchronized (mService) {
+            t = mThread;
+        }
+        // Release the lock before calling the notifier, in case that calls back into AM.
+        if (t != null) t.onProcessUnpaused();
         mProfile.onProcessUnfrozen();
         mServices.onProcessUnfrozen();
     }
 
     void onProcessFrozenCancelled() {
-        if (mThread != null) mThread.onProcessPausedCancelled();
+        final ApplicationThreadDeferred t;
+        synchronized (mService) {
+            t = mThread;
+        }
+        // Release the lock before calling the notifier, in case that calls back into AM.
+        if (t != null) t.onProcessPausedCancelled();
         mServices.onProcessFrozenCancelled();
     }
 
diff --git a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
index 0954c49..3a041fd 100644
--- a/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
+++ b/services/core/java/com/android/server/am/SettingsToPropertiesMapper.java
@@ -228,6 +228,7 @@
         "media_reliability",
         "media_solutions",
         "media_tv",
+        "microxr",
         "nearby",
         "nfc",
         "pdf_viewer",
diff --git a/services/core/java/com/android/server/am/broadcasts_flags.aconfig b/services/core/java/com/android/server/am/broadcasts_flags.aconfig
index 68e21a3..3867f77 100644
--- a/services/core/java/com/android/server/am/broadcasts_flags.aconfig
+++ b/services/core/java/com/android/server/am/broadcasts_flags.aconfig
@@ -26,4 +26,15 @@
     metadata {
         purpose: PURPOSE_BUGFIX
     }
-}
\ No newline at end of file
+}
+
+flag {
+    name: "log_broadcast_processed_event"
+    namespace: "backstage_power"
+    description: "Log the broadcast processed event to Statsd"
+    bug: "387576580"
+    is_fixed_read_only: true
+    metadata {
+        purpose: PURPOSE_BUGFIX
+    }
+}
diff --git a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
index ca9a25b..6f8c241 100644
--- a/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
+++ b/services/core/java/com/android/server/appop/AppOpsUidStateTrackerImpl.java
@@ -341,17 +341,15 @@
     }
 
     private void commitUidPendingState(int uid) {
-        int pendingUidState = mPendingUidStates.get(uid,
-                mUidStates.get(uid, MIN_PRIORITY_UID_STATE));
-        int pendingCapability = mPendingCapability.get(uid,
-                mCapability.get(uid, PROCESS_CAPABILITY_NONE));
-        boolean pendingAppWidgetVisible = mPendingAppWidgetVisible.get(uid,
-                mAppWidgetVisible.get(uid, false));
 
         int uidState = mUidStates.get(uid, MIN_PRIORITY_UID_STATE);
         int capability = mCapability.get(uid, PROCESS_CAPABILITY_NONE);
         boolean appWidgetVisible = mAppWidgetVisible.get(uid, false);
 
+        int pendingUidState = mPendingUidStates.get(uid, uidState);
+        int pendingCapability = mPendingCapability.get(uid, capability);
+        boolean pendingAppWidgetVisible = mPendingAppWidgetVisible.get(uid, appWidgetVisible);
+
         boolean foregroundChange = uidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
                 != pendingUidState <= UID_STATE_MAX_LAST_NON_RESTRICTED
                 || capability != pendingCapability
diff --git a/services/core/java/com/android/server/audio/AudioDeviceBroker.java b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
index ef80d59..8ef79a91 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceBroker.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceBroker.java
@@ -16,6 +16,22 @@
 package com.android.server.audio;
 
 import static android.media.audio.Flags.scoManagedByAudio;
+import static android.media.AudioSystem.DEVICE_IN_ALL_SCO_SET;
+import static android.media.AudioSystem.DEVICE_IN_BLE_HEADSET;
+import static android.media.AudioSystem.DEVICE_IN_BLUETOOTH_SCO_HEADSET;
+import static android.media.AudioSystem.DEVICE_IN_USB_HEADSET;
+import static android.media.AudioSystem.DEVICE_IN_WIRED_HEADSET;
+import static android.media.AudioSystem.DEVICE_OUT_ALL_SCO_SET;
+import static android.media.AudioSystem.DEVICE_OUT_BLE_HEADSET;
+import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO;
+import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_CARKIT;
+import static android.media.AudioSystem.DEVICE_OUT_BLUETOOTH_SCO_HEADSET;
+import static android.media.AudioSystem.DEVICE_OUT_BUS;
+import static android.media.AudioSystem.DEVICE_OUT_EARPIECE;
+import static android.media.AudioSystem.DEVICE_OUT_SPEAKER;
+import static android.media.AudioSystem.DEVICE_OUT_USB_HEADSET;
+import static android.media.AudioSystem.DEVICE_OUT_WIRED_HEADSET;
+import static android.media.AudioSystem.isBluetoothScoOutDevice;
 
 import static com.android.media.audio.Flags.equalScoLeaVcIndexRange;
 import static com.android.media.audio.Flags.optimizeBtDeviceSwitch;
@@ -78,9 +94,11 @@
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.HashSet;
 import java.util.LinkedList;
 import java.util.List;
+import java.util.Map;
 import java.util.NoSuchElementException;
 import java.util.Objects;
 import java.util.Set;
@@ -514,7 +532,7 @@
     @GuardedBy("mDeviceStateLock")
     private CommunicationRouteClient topCommunicationRouteClient() {
         for (CommunicationRouteClient crc : mCommunicationRouteClients) {
-            if (crc.getUid() == mAudioModeOwner.mUid) {
+            if (crc.getUid() == mAudioModeOwner.mUid && !crc.isDisabled()) {
                 return crc;
             }
         }
@@ -574,36 +592,6 @@
         return false;
     }
 
-    /*package */
-    void postCheckCommunicationDeviceRemoval(@NonNull AudioDeviceAttributes device) {
-        if (!isValidCommunicationDeviceType(
-                AudioDeviceInfo.convertInternalDeviceToDeviceType(device.getInternalType()))) {
-            return;
-        }
-        sendLMsgNoDelay(MSG_L_CHECK_COMMUNICATION_DEVICE_REMOVAL, SENDMSG_QUEUE, device);
-    }
-
-    @GuardedBy("mDeviceStateLock")
-    void onCheckCommunicationDeviceRemoval(@NonNull AudioDeviceAttributes device) {
-        if (AudioService.DEBUG_COMM_RTE) {
-            Log.v(TAG, "onCheckCommunicationDeviceRemoval device: " + device.toString());
-        }
-        for (CommunicationRouteClient crc : mCommunicationRouteClients) {
-            if (device.equals(crc.getDevice())) {
-                if (AudioService.DEBUG_COMM_RTE) {
-                    Log.v(TAG, "onCheckCommunicationDeviceRemoval removing client: "
-                            + crc.toString());
-                }
-                // Cancelling the route for this client will remove it from the stack and update
-                // the communication route.
-                CommunicationDeviceInfo deviceInfo = new CommunicationDeviceInfo(
-                        crc.getBinder(), crc.getAttributionSource(), device, false,
-                        BtHelper.SCO_MODE_UNDEFINED, "onCheckCommunicationDeviceRemoval",
-                        crc.isPrivileged());
-                postSetCommunicationDeviceForClient(deviceInfo);
-            }
-        }
-    }
 
     // check playback or record activity after 6 seconds for UIDs
     private static final int CHECK_CLIENT_STATE_DELAY_MS = 6000;
@@ -1693,8 +1681,18 @@
                                 boolean connect, @Nullable BluetoothDevice btDevice,
                                 boolean deviceSwitch) {
         synchronized (mDeviceStateLock) {
-            return mDeviceInventory.handleDeviceConnection(
+            boolean status =  mDeviceInventory.handleDeviceConnection(
                     attributes, connect, false /*for test*/, btDevice, deviceSwitch);
+            if (isValidCommunicationDeviceType(attributes.getType())
+                    || mDuplexCommunicationDevices.containsValue(attributes.getInternalType())) {
+                checkCommunicationRouteClientsDevices();
+                if (connect || !deviceSwitch) {
+                    onUpdateCommunicationRouteClient(
+                            bluetoothScoRequestOwnerAttributionSource(),
+                            "handleDeviceConnection");
+                }
+            }
+            return status;
         }
     }
 
@@ -1953,15 +1951,17 @@
                                                 || btInfo.mIsLeOutput)
                                             ? mAudioService.getBluetoothContextualVolumeStream()
                                             : AudioSystem.STREAM_DEFAULT);
-                                if ((btInfo.mProfile == BluetoothProfile.LE_AUDIO
+                                if (btInfo.mProfile == BluetoothProfile.LE_AUDIO
                                         || btInfo.mProfile == BluetoothProfile.HEARING_AID
                                         || (mScoManagedByAudio
-                                            && btInfo.mProfile == BluetoothProfile.HEADSET))
-                                        && (btInfo.mState == BluetoothProfile.STATE_CONNECTED
-                                            || !btInfo.mIsDeviceSwitch)) {
-                                    onUpdateCommunicationRouteClient(
+                                            && btInfo.mProfile == BluetoothProfile.HEADSET)) {
+                                    checkCommunicationRouteClientsDevices();
+                                    if (btInfo.mState == BluetoothProfile.STATE_CONNECTED
+                                            || !btInfo.mIsDeviceSwitch) {
+                                        onUpdateCommunicationRouteClient(
                                             bluetoothScoRequestOwnerAttributionSource(),
                                             "setBluetoothActiveDevice");
+                                    }
                                 }
                             }
                         }
@@ -2123,13 +2123,6 @@
                     final BluetoothDevice btDevice = (BluetoothDevice) msg.obj;
                     BtHelper.onNotifyPreferredAudioProfileApplied(btDevice);
                 } break;
-                case MSG_L_CHECK_COMMUNICATION_DEVICE_REMOVAL: {
-                    synchronized (mSetModeLock) {
-                        synchronized (mDeviceStateLock) {
-                            onCheckCommunicationDeviceRemoval((AudioDeviceAttributes) msg.obj);
-                        }
-                    }
-                } break;
                 case MSG_PERSIST_AUDIO_DEVICE_SETTINGS:
                     onPersistAudioDeviceSettings();
                     break;
@@ -2227,7 +2220,6 @@
     private static final int MSG_IIL_BTLEAUDIO_TIMEOUT = 49;
 
     private static final int MSG_L_NOTIFY_PREFERRED_AUDIOPROFILE_APPLIED = 52;
-    private static final int MSG_L_CHECK_COMMUNICATION_DEVICE_REMOVAL = 53;
 
     private static final int MSG_PERSIST_AUDIO_DEVICE_SETTINGS = 54;
 
@@ -2431,18 +2423,21 @@
         private final IBinder mCb;
         @NonNull private final AttributionSource mAttributionSource;
         private final boolean mIsPrivileged;
-        private AudioDeviceAttributes mDevice;
+        @NonNull private AudioDeviceAttributes mDevice;
         private boolean mPlaybackActive;
         private boolean mRecordingActive;
 
+        private boolean mDisabled;
+
         CommunicationRouteClient(IBinder cb, @NonNull AttributionSource attributionSource,
-                AudioDeviceAttributes device, boolean isPrivileged) {
+                @NonNull AudioDeviceAttributes device, boolean isPrivileged) {
             mCb = cb;
             mAttributionSource = attributionSource;
             mDevice = device;
             mIsPrivileged = isPrivileged;
             mPlaybackActive = mAudioService.isPlaybackActiveForUid(attributionSource.getUid());
             mRecordingActive = mAudioService.isRecordingActiveForUid(attributionSource.getUid());
+            mDisabled = false;
         }
 
         public boolean registerDeathRecipient() {
@@ -2485,7 +2480,10 @@
             return mIsPrivileged;
         }
 
-        AudioDeviceAttributes getDevice() {
+        void setDevice(@NonNull AudioDeviceAttributes device) {
+            mDevice = device;
+        }
+        @NonNull AudioDeviceAttributes getDevice() {
             return mDevice;
         }
 
@@ -2498,7 +2496,14 @@
         }
 
         public boolean isActive() {
-            return mIsPrivileged || mRecordingActive || mPlaybackActive;
+            return !mDisabled && (mIsPrivileged || mRecordingActive || mPlaybackActive);
+        }
+
+        public void setDisabled(boolean disabled) {
+            mDisabled = disabled;
+        }
+        public boolean isDisabled() {
+            return mDisabled;
         }
 
         @Override
@@ -2507,7 +2512,8 @@
                     + " mDevice: " + mDevice.toString()
                     + " mIsPrivileged: " + mIsPrivileged
                     + " mPlaybackActive: " + mPlaybackActive
-                    + " mRecordingActive: " + mRecordingActive + "]";
+                    + " mRecordingActive: " + mRecordingActive
+                    + " mDisabled: " + mDisabled + "]";
         }
     }
 
@@ -2593,6 +2599,76 @@
         onUpdatePhoneStrategyDevice(preferredCommunicationDevice);
     }
 
+    // Pairs of input and output devices for duplex communication devices (headsets)
+    private final HashMap<Integer, Integer> mDuplexCommunicationDevices = new HashMap<>(
+            Map.of(DEVICE_OUT_BLE_HEADSET, DEVICE_IN_BLE_HEADSET,
+                DEVICE_OUT_WIRED_HEADSET, DEVICE_IN_WIRED_HEADSET,
+                DEVICE_OUT_USB_HEADSET, DEVICE_IN_USB_HEADSET,
+                DEVICE_OUT_BLUETOOTH_SCO, DEVICE_IN_BLUETOOTH_SCO_HEADSET,
+                DEVICE_OUT_BLUETOOTH_SCO_HEADSET, DEVICE_IN_BLUETOOTH_SCO_HEADSET,
+                DEVICE_OUT_BLUETOOTH_SCO_CARKIT, DEVICE_IN_BLUETOOTH_SCO_HEADSET
+            ));
+    /**
+     * Scan communication route clients and disable them if their selected device is not connected
+     * or re-enable them if a device of the same type as their connected device is connected
+     */
+    // @GuardedBy("mSetModeLock")
+    @GuardedBy("mDeviceStateLock")
+    private void checkCommunicationRouteClientsDevices() {
+        for (CommunicationRouteClient crc : mCommunicationRouteClients) {
+            int deviceType = crc.getDevice().getInternalType();
+            // Skip non detachable devices
+            if (deviceType == DEVICE_OUT_EARPIECE || deviceType == DEVICE_OUT_SPEAKER
+                    || deviceType == DEVICE_OUT_BUS) {
+                continue;
+            }
+
+            // outDeviceSet is the expected connected output device types for the requested device
+            Set<Integer> outDeviceSet = null;
+            // inDeviceSet is the expected input device for outDeviceSet. Null for non
+            // duplex devices
+            Set<Integer> inDeviceSet = null;
+            // Special case for SCO because several device types are equivalent
+            if (isBluetoothScoOutDevice(deviceType)) {
+                outDeviceSet = DEVICE_OUT_ALL_SCO_SET;
+                inDeviceSet = DEVICE_IN_ALL_SCO_SET;
+            } else {
+                outDeviceSet = new HashSet<>();
+                outDeviceSet.add(deviceType);
+                if (mDuplexCommunicationDevices.containsKey(deviceType)) {
+                    inDeviceSet = new HashSet<>();
+                    inDeviceSet.add(mDuplexCommunicationDevices.get(deviceType));
+                }
+            }
+
+            AudioDeviceAttributes outAda =
+                    mDeviceInventory.getFirstConnectedDeviceAttributesOfTypes(outDeviceSet);
+            AudioDeviceAttributes inAda = (inDeviceSet == null) ? null
+                    : mDeviceInventory.getFirstConnectedDeviceAttributesOfTypes(inDeviceSet);
+
+            // A device is fully connected if the output device is connect and if not duplex
+            // or an input device with the same address is connected
+            boolean fullyConnected = outAda != null && (inDeviceSet == null
+                    || (inAda != null && inAda.getAddress().equals(outAda.getAddress())));
+
+            if (fullyConnected) {
+                crc.setDevice(outAda);
+                if (crc.isDisabled()) {
+                    crc.setDisabled(false);
+                    if (AudioService.DEBUG_COMM_RTE) {
+                        Log.v(TAG,
+                                "checkCommunicationRouteClientsDevices, enabling client: " + crc);
+                    }
+                }
+            } else if (!crc.isDisabled()) {
+                crc.setDisabled(true);
+                if (AudioService.DEBUG_COMM_RTE) {
+                    Log.v(TAG, "checkCommunicationRouteClientsDevices, disabling client: " + crc);
+                }
+            }
+        }
+    }
+
     /**
      * Select new communication device from communication route client at the top of the stack
      * and restore communication route including restarting SCO audio if needed.
@@ -2601,6 +2677,7 @@
     @GuardedBy("mDeviceStateLock")
     private void onUpdateCommunicationRouteClient(
             @Nullable AttributionSource previousBtScoRequesterAS, String eventSource) {
+
         CommunicationRouteClient crc = topCommunicationRouteClient();
         if (AudioService.DEBUG_COMM_RTE) {
             Log.v(TAG, "onUpdateCommunicationRouteClient, crc: " + crc
diff --git a/services/core/java/com/android/server/audio/AudioDeviceInventory.java b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
index ae91934..829d9ea 100644
--- a/services/core/java/com/android/server/audio/AudioDeviceInventory.java
+++ b/services/core/java/com/android/server/audio/AudioDeviceInventory.java
@@ -1867,7 +1867,6 @@
                         deviceSwitch);
                 // always remove even if disconnection failed
                 mConnectedDevices.remove(deviceKey);
-                mDeviceBroker.postCheckCommunicationDeviceRemoval(attributes);
                 status = true;
             }
             if (status) {
@@ -2413,7 +2412,7 @@
         } else {
             AudioService.sDeviceLogger.enqueue((new EventLogger.StringEvent(
                     "A2DP device addr=" + Utils.anonymizeBluetoothAddress(address)
-                            + " made unavailable, deviceSwitch" + deviceSwitch))
+                            + " made unavailable, deviceSwitch: " + deviceSwitch))
                     .printSlog(EventLogger.Event.ALOGI, TAG));
         }
         mApmConnectedDevices.remove(AudioSystem.DEVICE_OUT_BLUETOOTH_A2DP);
@@ -2423,7 +2422,6 @@
         mmi.record();
         updateBluetoothPreferredModes_l(null /*connectedDevice*/);
         purgeDevicesRoles_l();
-        mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
     }
 
     @GuardedBy("mDevicesLock")
@@ -2479,7 +2477,6 @@
         // always remove regardless of the result
         mConnectedDevices.remove(
                 DeviceInfo.makeDeviceListKey(AudioSystem.DEVICE_IN_BLUETOOTH_A2DP, address));
-        mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
     }
 
     @GuardedBy("mDevicesLock")
@@ -2541,7 +2538,6 @@
                 .set(MediaMetrics.Property.DEVICE,
                         AudioSystem.getDeviceName(DEVICE_OUT_HEARING_AID))
                 .record();
-        mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
     }
 
     @GuardedBy("mDevicesLock")
@@ -2572,6 +2568,15 @@
     }
 
     /**
+     * Returns a DeviceInfo for the first connected device matching one of the supplied types
+     */
+    AudioDeviceAttributes getFirstConnectedDeviceAttributesOfTypes(Set<Integer> internalTypes) {
+        DeviceInfo di = getFirstConnectedDeviceOfTypes(internalTypes);
+        return di == null ? null : new AudioDeviceAttributes(
+                di.mDeviceType, di.mDeviceAddress, di.mDeviceName);
+    }
+
+    /**
      * Returns a list of connected devices matching one of the supplied types
      */
     private List<DeviceInfo> getConnectedDevicesOfTypes(Set<Integer> internalTypes) {
@@ -2689,13 +2694,16 @@
 
             if (res != AudioSystem.AUDIO_STATUS_OK) {
                 AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
-                        "APM failed to make unavailable LE Audio device addr=" + address
-                                + " error=" + res).printSlog(EventLogger.Event.ALOGE, TAG));
+                        "APM failed to make unavailable LE Audio "
+                        + (AudioSystem.isInputDevice(device) ? "source" : "sink")
+                        + " device addr=" + address
+                        + " error=" + res).printSlog(EventLogger.Event.ALOGE, TAG));
                 // not taking further action: proceeding as if disconnection from APM worked
             } else {
                 AudioService.sDeviceLogger.enqueue(new EventLogger.StringEvent(
-                        "LE Audio device addr=" + Utils.anonymizeBluetoothAddress(address)
-                            + " made unavailable, deviceSwitch" + deviceSwitch)
+                        "LE Audio " + (AudioSystem.isInputDevice(device) ? "source" : "sink")
+                            + "device addr=" + Utils.anonymizeBluetoothAddress(address)
+                            + " made unavailable, deviceSwitch: " + deviceSwitch)
                         .printSlog(EventLogger.Event.ALOGI, TAG));
             }
             mConnectedDevices.remove(DeviceInfo.makeDeviceListKey(device, address));
@@ -2704,9 +2712,6 @@
         setCurrentAudioRouteNameIfPossible(null, false /*fromA2dp*/);
         updateBluetoothPreferredModes_l(null /*connectedDevice*/);
         purgeDevicesRoles_l();
-        if (ada != null) {
-            mDeviceBroker.postCheckCommunicationDeviceRemoval(ada);
-        }
     }
 
     @GuardedBy("mDevicesLock")
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0f1228f..ada1cd7 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -7806,7 +7806,8 @@
                 return AudioSystem.STREAM_RING;
             }
         default:
-            if (isInCommunication()) {
+            if (isInCommunication()
+                    || mAudioSystem.isStreamActive(AudioManager.STREAM_VOICE_CALL, 0)) {
                 if (!replaceStreamBtSco()
                         && mBtCommDeviceActive.get() == BT_COMM_DEVICE_ACTIVE_SCO) {
                     if (DEBUG_VOL) Log.v(TAG, "getActiveStreamType: Forcing STREAM_BLUETOOTH_SCO");
diff --git a/services/core/java/com/android/server/clipboard/OWNERS b/services/core/java/com/android/server/clipboard/OWNERS
index 0d5dbf9..4ca4b80 100644
--- a/services/core/java/com/android/server/clipboard/OWNERS
+++ b/services/core/java/com/android/server/clipboard/OWNERS
@@ -1,3 +1,3 @@
-per-file EmulatorClipboardMonitor.java = bohu@google.com,lfy@google.com,rkir@google.com
+per-file EmulatorClipboardMonitor.java = bohu@google.com,rkir@google.com
 
 olilan@google.com
diff --git a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
index 8637d2d..47b1c544 100644
--- a/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
+++ b/services/core/java/com/android/server/compat/overrides/AppCompatOverridesService.java
@@ -103,12 +103,6 @@
         }
     }
 
-    @Override
-    public void finalize() {
-        unregisterDeviceConfigListeners();
-        unregisterPackageReceiver();
-    }
-
     @VisibleForTesting
     void registerDeviceConfigListeners() {
         for (DeviceConfigListener listener : mDeviceConfigListeners) {
@@ -116,21 +110,11 @@
         }
     }
 
-    private void unregisterDeviceConfigListeners() {
-        for (DeviceConfigListener listener : mDeviceConfigListeners) {
-            listener.unregister();
-        }
-    }
-
     @VisibleForTesting
     void registerPackageReceiver() {
         mPackageReceiver.register();
     }
 
-    private void unregisterPackageReceiver() {
-        mPackageReceiver.unregister();
-    }
-
     /**
      * Same as {@link #applyOverrides(Properties, Set, Map)} except all properties of the given
      * {@code namespace} are fetched via {@link DeviceConfig#getProperties}.
@@ -374,10 +358,6 @@
                     this);
         }
 
-        private void unregister() {
-            DeviceConfig.removeOnPropertiesChangedListener(this);
-        }
-
         @Override
         public void onPropertiesChanged(Properties properties) {
             boolean removeOverridesFlagChanged = properties.getKeyset().contains(
@@ -426,10 +406,6 @@
                     null, /* scheduler= */ null);
         }
 
-        private void unregister() {
-            mContext.unregisterReceiver(this);
-        }
-
         @Override
         public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
             Uri data = intent.getData();
diff --git a/services/core/java/com/android/server/content/SyncManager.java b/services/core/java/com/android/server/content/SyncManager.java
index 969a684..2d387ea 100644
--- a/services/core/java/com/android/server/content/SyncManager.java
+++ b/services/core/java/com/android/server/content/SyncManager.java
@@ -261,6 +261,7 @@
     private final SyncLogger mLogger;
 
     private final AppCloningDeviceConfigHelper mAppCloningDeviceConfigHelper;
+    private final PackageMonitorImpl mPackageMonitor;
 
     private boolean isJobIdInUseLockedH(int jobId, List<JobInfo> pendingJobs) {
         for (int i = 0, size = pendingJobs.size(); i < size; i++) {
@@ -725,8 +726,8 @@
                 mUserIntentReceiver, UserHandle.ALL, intentFilter, null, null);
 
 
-        final PackageMonitor packageMonitor = new PackageMonitorImpl();
-        packageMonitor.register(mContext, null /* thread */, UserHandle.ALL,
+        mPackageMonitor = new PackageMonitorImpl();
+        mPackageMonitor.register(mContext, null /* thread */, UserHandle.ALL,
                 false /* externalStorage */);
 
         intentFilter = new IntentFilter(Intent.ACTION_TIME_CHANGED);
diff --git a/services/core/java/com/android/server/display/DisplayAdapter.java b/services/core/java/com/android/server/display/DisplayAdapter.java
index 69bc66f..155f82a 100644
--- a/services/core/java/com/android/server/display/DisplayAdapter.java
+++ b/services/core/java/com/android/server/display/DisplayAdapter.java
@@ -19,6 +19,7 @@
 import android.content.Context;
 import android.os.Handler;
 import android.view.Display;
+import android.view.SurfaceControl;
 
 import com.android.server.display.feature.DisplayManagerFlags;
 
@@ -138,6 +139,21 @@
                 vsyncRate, /* isSynthetic= */ false, alternativeRefreshRates, supportedHdrTypes);
     }
 
+    static int getPowerModeForState(int state) {
+        switch (state) {
+            case Display.STATE_OFF:
+                return SurfaceControl.POWER_MODE_OFF;
+            case Display.STATE_DOZE:
+                return SurfaceControl.POWER_MODE_DOZE;
+            case Display.STATE_DOZE_SUSPEND:
+                return SurfaceControl.POWER_MODE_DOZE_SUSPEND;
+            case Display.STATE_ON_SUSPEND:
+                return SurfaceControl.POWER_MODE_ON_SUSPEND;
+            default:
+                return SurfaceControl.POWER_MODE_NORMAL;
+        }
+    }
+
     public interface Listener {
         void onDisplayDeviceEvent(DisplayDevice device, int event);
         void onTraversalRequested();
diff --git a/services/core/java/com/android/server/display/DisplayManagerService.java b/services/core/java/com/android/server/display/DisplayManagerService.java
index 258c955..7016c11 100644
--- a/services/core/java/com/android/server/display/DisplayManagerService.java
+++ b/services/core/java/com/android/server/display/DisplayManagerService.java
@@ -2442,7 +2442,10 @@
             applyDisplayChangedLocked(display);
         }
 
-        if (mDisplayTopologyCoordinator != null) {
+        // The default display should always be added to the topology. Other displays will be added
+        // upon calling onDisplayBelongToTopologyChanged().
+        if (mDisplayTopologyCoordinator != null
+                && display.getDisplayIdLocked() == Display.DEFAULT_DISPLAY) {
             mDisplayTopologyCoordinator.onDisplayAdded(display.getDisplayInfoLocked());
         }
     }
@@ -2618,8 +2621,7 @@
         // Blank or unblank the display immediately to match the state requested
         // by the display power controller (if known).
         DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
-        if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0
-                || android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) {
+        if ((info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
             final LogicalDisplay display = mLogicalDisplayMapper.getDisplayLocked(device);
             if (display == null) {
                 return null;
@@ -5580,9 +5582,7 @@
                     final DisplayDevice displayDevice = mLogicalDisplayMapper.getDisplayLocked(
                             id).getPrimaryDisplayDeviceLocked();
                     final int flags = displayDevice.getDisplayDeviceInfoLocked().flags;
-                    if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0
-                            || android.companion.virtualdevice.flags.Flags
-                                    .correctVirtualDisplayPowerState()) {
+                    if ((flags & DisplayDeviceInfo.FLAG_NEVER_BLANK) == 0) {
                         final DisplayPowerController displayPowerController =
                                 mDisplayPowerControllers.get(id);
                         if (displayPowerController != null) {
@@ -6040,6 +6040,18 @@
         }
 
         @Override
+        public void onDisplayBelongToTopologyChanged(int displayId, boolean inTopology) {
+            if (mDisplayTopologyCoordinator == null) {
+                return;
+            }
+            if (inTopology) {
+                mDisplayTopologyCoordinator.onDisplayAdded(getDisplayInfo(displayId));
+            } else {
+                mDisplayTopologyCoordinator.onDisplayRemoved(displayId);
+            }
+        }
+
+        @Override
         public void reloadTopologies(final int userId) {
             // Reload topologies only if the userId matches the current user id.
             if (userId == mCurrentUserId) {
diff --git a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
index 2618cf4..997fff5 100644
--- a/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
+++ b/services/core/java/com/android/server/display/DisplayTopologyCoordinator.java
@@ -267,11 +267,6 @@
                     + "type is EXTERNAL or OVERLAY and !mIsExtendedDisplayEnabled");
             return false;
         }
-        if (info.displayGroupId != Display.DEFAULT_DISPLAY_GROUP) {
-            Slog.d(TAG, "Display " + info.displayId + " not allowed in topology because "
-                    + "it is not in the default display group");
-            return false;
-        }
         return true;
     }
 
diff --git a/services/core/java/com/android/server/display/LocalDisplayAdapter.java b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
index 551202c..7b714ad 100644
--- a/services/core/java/com/android/server/display/LocalDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/LocalDisplayAdapter.java
@@ -208,21 +208,6 @@
         }
     }
 
-    static int getPowerModeForState(int state) {
-        switch (state) {
-            case Display.STATE_OFF:
-                return SurfaceControl.POWER_MODE_OFF;
-            case Display.STATE_DOZE:
-                return SurfaceControl.POWER_MODE_DOZE;
-            case Display.STATE_DOZE_SUSPEND:
-                return SurfaceControl.POWER_MODE_DOZE_SUSPEND;
-            case Display.STATE_ON_SUSPEND:
-                return SurfaceControl.POWER_MODE_ON_SUSPEND;
-            default:
-                return SurfaceControl.POWER_MODE_NORMAL;
-        }
-    }
-
     private final class LocalDisplayDevice extends DisplayDevice {
         private final long mPhysicalDisplayId;
         private final SparseArray<DisplayModeRecord> mSupportedModes = new SparseArray<>();
diff --git a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
index e7939bb..ac03a93 100644
--- a/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
+++ b/services/core/java/com/android/server/display/VirtualDisplayAdapter.java
@@ -113,6 +113,11 @@
             public void destroyDisplay(IBinder displayToken) {
                 DisplayControl.destroyVirtualDisplay(displayToken);
             }
+
+            @Override
+            public void setDisplayPowerMode(IBinder displayToken, int mode) {
+                SurfaceControl.setDisplayPowerMode(displayToken, mode);
+            }
         }, featureFlags);
     }
 
@@ -340,6 +345,7 @@
         private Display.Mode mMode;
         private int mDisplayIdToMirror;
         private boolean mIsWindowManagerMirroring;
+        private final boolean mNeverBlank;
         private final DisplayCutout mDisplayCutout;
         private final float mDefaultBrightness;
         private final float mDimBrightness;
@@ -371,7 +377,11 @@
             mCallback = callback;
             mProjection = projection;
             mMediaProjectionCallback = mediaProjectionCallback;
-            if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) {
+            // Private non-mirror displays are never blank and always on.
+            mNeverBlank = (flags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0
+                    && (flags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0;
+            if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()
+                    && !mNeverBlank) {
                 // The display's power state depends on the power state of the state of its
                 // display / power group, which we don't know here. Initializing to UNKNOWN allows
                 // the first call to requestDisplayStateLocked() to set the correct state.
@@ -471,7 +481,15 @@
         @Override
         public Runnable requestDisplayStateLocked(int state, float brightnessState,
                 float sdrBrightnessState, DisplayOffloadSessionImpl displayOffloadSession) {
+            Runnable runnable = null;
             if (state != mDisplayState) {
+                Slog.d(TAG, "Changing state of virtual display " + mName + " from "
+                        + Display.stateToString(mDisplayState) + " to "
+                        + Display.stateToString(state));
+                if (state != Display.STATE_ON && state != Display.STATE_OFF) {
+                    Slog.wtf(TAG, "Unexpected display state for Virtual Display: "
+                            + Display.stateToString(state));
+                }
                 mDisplayState = state;
                 mInfo = null;
                 sendDisplayDeviceEventLocked(this, DISPLAY_DEVICE_EVENT_CHANGED);
@@ -480,6 +498,15 @@
                 } else {
                     mCallback.dispatchDisplayResumed();
                 }
+
+                if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) {
+                    final IBinder token = getDisplayTokenLocked();
+                    runnable = () -> {
+                        final int mode = getPowerModeForState(state);
+                        Slog.d(TAG, "Requesting power mode for display " + mName + " to " + mode);
+                        mSurfaceControlDisplayFactory.setDisplayPowerMode(token, mode);
+                    };
+                }
             }
             if (android.companion.virtualdevice.flags.Flags.deviceAwareDisplayPower()
                     && mBrightnessListener != null
@@ -488,7 +515,7 @@
                 mCurrentBrightness = brightnessState;
                 mCallback.dispatchRequestedBrightnessChanged(mCurrentBrightness);
             }
-            return null;
+            return runnable;
         }
 
         @Override
@@ -572,23 +599,14 @@
                 mInfo.yDpi = mDensityDpi;
                 mInfo.presentationDeadlineNanos = 1000000000L / (int) getRefreshRate(); // 1 frame
                 mInfo.flags = 0;
-                if (android.companion.virtualdevice.flags.Flags.correctVirtualDisplayPowerState()) {
-                    if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
-                        mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
-                    }
-                    if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0) {
-                        mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
-                    }
-                } else {
-                    if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
-                        mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE
-                                | DisplayDeviceInfo.FLAG_NEVER_BLANK;
-                    }
-                    if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) != 0) {
-                        mInfo.flags &= ~DisplayDeviceInfo.FLAG_NEVER_BLANK;
-                    } else {
-                        mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
-                    }
+                if ((mFlags & VIRTUAL_DISPLAY_FLAG_PUBLIC) == 0) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_PRIVATE;
+                }
+                if ((mFlags & VIRTUAL_DISPLAY_FLAG_AUTO_MIRROR) == 0) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_CONTENT_ONLY;
+                }
+                if (mNeverBlank) {
+                    mInfo.flags |= DisplayDeviceInfo.FLAG_NEVER_BLANK;
                 }
                 if ((mFlags & VIRTUAL_DISPLAY_FLAG_OWN_DISPLAY_GROUP) != 0) {
                     mInfo.flags |= DisplayDeviceInfo.FLAG_OWN_DISPLAY_GROUP;
@@ -782,5 +800,13 @@
          * @param displayToken The display token for the display to be destroyed.
          */
         void destroyDisplay(IBinder displayToken);
+
+        /**
+         * Set the display power mode in SurfaceFlinger.
+         *
+         * @param displayToken The display token for the display.
+         * @param mode the SurfaceControl power mode, e.g. {@link SurfaceControl#POWER_MODE_OFF}.
+         */
+        void setDisplayPowerMode(IBinder displayToken, int mode);
     }
 }
diff --git a/services/core/java/com/android/server/display/brightness/BrightnessReason.java b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
index a4804e1..d4b9a6c 100644
--- a/services/core/java/com/android/server/display/brightness/BrightnessReason.java
+++ b/services/core/java/com/android/server/display/brightness/BrightnessReason.java
@@ -49,11 +49,9 @@
     public static final int MODIFIER_HDR = 0x4;
     public static final int MODIFIER_THROTTLED = 0x8;
     public static final int MODIFIER_MIN_LUX = 0x10;
-    public static final int MODIFIER_MIN_USER_SET_LOWER_BOUND = 0x20;
-    public static final int MODIFIER_STYLUS_UNDER_USE = 0x40;
+    public static final int MODIFIER_STYLUS_UNDER_USE = 0x20;
     public static final int MODIFIER_MASK = MODIFIER_DIMMED | MODIFIER_LOW_POWER | MODIFIER_HDR
-            | MODIFIER_THROTTLED | MODIFIER_MIN_LUX | MODIFIER_MIN_USER_SET_LOWER_BOUND
-            | MODIFIER_STYLUS_UNDER_USE;
+            | MODIFIER_THROTTLED | MODIFIER_MIN_LUX | MODIFIER_STYLUS_UNDER_USE;
 
     // ADJUSTMENT_*
     // These things can happen at any point, even if the main brightness reason doesn't
@@ -157,9 +155,6 @@
         if ((mModifier & MODIFIER_MIN_LUX) != 0) {
             sb.append(" lux_lower_bound");
         }
-        if ((mModifier & MODIFIER_MIN_USER_SET_LOWER_BOUND) != 0) {
-            sb.append(" user_min_pref");
-        }
         if ((mModifier & MODIFIER_STYLUS_UNDER_USE) != 0) {
             sb.append(" stylus_under_use");
         }
diff --git a/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java b/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java
index c3596c3..72cb31d 100644
--- a/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java
+++ b/services/core/java/com/android/server/display/brightness/clamper/BrightnessLowLuxModifier.java
@@ -19,12 +19,8 @@
 
 import android.content.ContentResolver;
 import android.content.Context;
-import android.database.ContentObserver;
 import android.hardware.display.DisplayManagerInternal;
-import android.net.Uri;
 import android.os.Handler;
-import android.os.UserHandle;
-import android.provider.Settings;
 import android.util.Slog;
 
 import com.android.internal.annotations.VisibleForTesting;
@@ -49,7 +45,6 @@
     private static final String TAG = "BrightnessLowLuxModifier";
     private static final boolean DEBUG = DebugUtils.isDebuggable(TAG);
     private static final float MIN_NITS_DEFAULT = 0.2f;
-    private final SettingsObserver mSettingsObserver;
     private final ContentResolver mContentResolver;
     private final Handler mHandler;
     private final BrightnessClamperController.ClamperChangeListener mChangeListener;
@@ -69,7 +64,6 @@
         mChangeListener = listener;
         mHandler = handler;
         mContentResolver = context.getContentResolver();
-        mSettingsObserver = new SettingsObserver(mHandler);
         mDisplayDeviceConfig = displayDeviceConfig;
         mHandler.post(() -> {
             start();
@@ -82,12 +76,7 @@
      */
     @VisibleForTesting
     public void recalculateLowerBound() {
-        float settingNitsLowerBound = Settings.Secure.getFloatForUser(
-                mContentResolver, Settings.Secure.EVEN_DIMMER_MIN_NITS,
-                /* def= */ MIN_NITS_DEFAULT, UserHandle.USER_CURRENT);
-
-        boolean isActive = isSettingEnabled()
-                && mAmbientLux != BrightnessMappingStrategy.INVALID_LUX;
+        boolean isActive = mAmbientLux != BrightnessMappingStrategy.INVALID_LUX;
 
         final int reason;
         float minNitsAllowed = -1f; // undefined, if setting is off.
@@ -95,12 +84,9 @@
 
         if (isActive) {
             float luxBasedNitsLowerBound = mDisplayDeviceConfig.getMinNitsFromLux(mAmbientLux);
-            minNitsAllowed = Math.max(settingNitsLowerBound,
-                    luxBasedNitsLowerBound);
+            minNitsAllowed = Math.max(MIN_NITS_DEFAULT, luxBasedNitsLowerBound);
             minBrightnessAllowed = getBrightnessFromNits(minNitsAllowed);
-            reason = settingNitsLowerBound > luxBasedNitsLowerBound
-                    ? BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND
-                    : BrightnessReason.MODIFIER_MIN_LUX;
+            reason = BrightnessReason.MODIFIER_MIN_LUX;
         } else {
             minBrightnessAllowed = mDisplayDeviceConfig.getEvenDimmerTransitionPoint();
             reason = 0;
@@ -169,7 +155,6 @@
     @Override
     public void apply(DisplayManagerInternal.DisplayPowerRequest request,
             DisplayBrightnessState.Builder stateBuilder) {
-
         stateBuilder.setMinBrightness(mBrightnessLowerBound);
         float boundedBrightness = Math.max(mBrightnessLowerBound, stateBuilder.getBrightness());
         stateBuilder.setBrightness(boundedBrightness);
@@ -181,12 +166,11 @@
 
     @Override
     public void stop() {
-        mContentResolver.unregisterContentObserver(mSettingsObserver);
     }
 
     @Override
     public boolean shouldListenToLightSensor() {
-        return isSettingEnabled();
+        return true;
     }
 
     @Override
@@ -204,37 +188,8 @@
         pw.println("  mMinNitsAllowed=" + mMinNitsAllowed);
     }
 
-    /**
-     * Defaults to true, on devices where setting is unset.
-     *
-     * @return if setting indicates feature is enabled
-     */
-    private boolean isSettingEnabled() {
-        return Settings.Secure.getFloatForUser(mContentResolver,
-                Settings.Secure.EVEN_DIMMER_ACTIVATED,
-                /* def= */ 1.0f, UserHandle.USER_CURRENT) == 1.0f;
-    }
-
     private float getBrightnessFromNits(float nits) {
         return mDisplayDeviceConfig.getBrightnessFromBacklight(
                 mDisplayDeviceConfig.getBacklightFromNits(nits));
     }
-
-    private final class SettingsObserver extends ContentObserver {
-
-        SettingsObserver(Handler handler) {
-            super(handler);
-            mContentResolver.registerContentObserver(
-                    Settings.Secure.getUriFor(Settings.Secure.EVEN_DIMMER_MIN_NITS),
-                    false, this, UserHandle.USER_ALL);
-            mContentResolver.registerContentObserver(
-                    Settings.Secure.getUriFor(Settings.Secure.EVEN_DIMMER_ACTIVATED),
-                    false, this, UserHandle.USER_ALL);
-        }
-
-        @Override
-        public void onChange(boolean selfChange, Uri uri) {
-            recalculateLowerBound();
-        }
-    }
 }
diff --git a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
index 3cb21c3..97f9a7c 100644
--- a/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
+++ b/services/core/java/com/android/server/hdmi/HdmiCecLocalDeviceTv.java
@@ -793,7 +793,7 @@
                     @Override
                     public void onDeviceDiscoveryDone(List<HdmiDeviceInfo> deviceInfos) {
                         for (HdmiDeviceInfo info : deviceInfos) {
-                            if (!isInputReady(info.getDeviceId())) {
+                            if (!isInputReady(info.getId())) {
                                 mService.getHdmiCecNetwork().removeCecDevice(
                                         HdmiCecLocalDeviceTv.this, info.getLogicalAddress());
                             }
diff --git a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
index 6e5e0fd5..af06586 100644
--- a/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
+++ b/services/core/java/com/android/server/infra/AbstractMasterSystemService.java
@@ -193,6 +193,8 @@
     @Nullable
     private UserManagerInternal mUm;
 
+    private final MyPackageMonitor mPackageMonitor;
+
     /**
      * Default constructor.
      *
@@ -289,6 +291,7 @@
                 }
             });
         }
+        mPackageMonitor = new MyPackageMonitor(/* supportsPackageRestartQuery */ true);
         startTrackingPackageChanges();
     }
 
@@ -986,260 +989,264 @@
         }
     }
 
-    private void startTrackingPackageChanges() {
-        final PackageMonitor monitor = new PackageMonitor(true) {
+    private class MyPackageMonitor extends PackageMonitor {
+        MyPackageMonitor(boolean supportsPackageRestartQuery) {
+            super(supportsPackageRestartQuery);
+        }
 
-            @Override
-            public void onPackageUpdateStarted(@NonNull String packageName, int uid) {
-                if (verbose) Slog.v(mTag, "onPackageUpdateStarted(): " + packageName);
+        @Override
+        public void onPackageUpdateStarted(@NonNull String packageName, int uid) {
+            if (verbose) Slog.v(mTag, "onPackageUpdateStarted(): " + packageName);
+            synchronized (mLock) {
                 final String activePackageName = getActiveServicePackageNameLocked();
                 if (!packageName.equals(activePackageName)) return;
 
                 final int userId = getChangingUserId();
-                synchronized (mLock) {
-                    if (mUpdatingPackageNames == null) {
-                        mUpdatingPackageNames = new SparseArray<String>(mServicesCacheList.size());
-                    }
-                    mUpdatingPackageNames.put(userId, packageName);
-                    onServicePackageUpdatingLocked(userId);
-                    if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_NO_REFRESH) != 0) {
-                        if (debug) {
-                            Slog.d(mTag, "Holding service for user " + userId + " while package "
-                                    + activePackageName + " is being updated");
-                        }
-                    } else {
-                        if (debug) {
-                            Slog.d(mTag, "Removing service for user " + userId
-                                    + " because package " + activePackageName
-                                    + " is being updated");
-                        }
-                        removeCachedServiceListLocked(userId);
 
-                        if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_REFRESH_EAGER)
-                                != 0) {
-                            if (debug) {
-                                Slog.d(mTag, "Eagerly recreating service for user "
-                                        + userId);
-                            }
-                            getServiceForUserLocked(userId);
-                        }
-                    }
+                if (mUpdatingPackageNames == null) {
+                    mUpdatingPackageNames = new SparseArray<String>(mServicesCacheList.size());
                 }
-            }
-
-            @Override
-            public void onPackageUpdateFinished(@NonNull String packageName, int uid) {
-                if (verbose) Slog.v(mTag, "onPackageUpdateFinished(): " + packageName);
-                final int userId = getChangingUserId();
-                synchronized (mLock) {
-                    final String activePackageName = mUpdatingPackageNames == null ? null
-                            : mUpdatingPackageNames.get(userId);
-                    if (packageName.equals(activePackageName)) {
-                        if (mUpdatingPackageNames != null) {
-                            mUpdatingPackageNames.remove(userId);
-                            if (mUpdatingPackageNames.size() == 0) {
-                                mUpdatingPackageNames = null;
-                            }
-                        }
-                        onServicePackageUpdatedLocked(userId);
-                    } else {
-                        handlePackageUpdateLocked(packageName);
-                    }
-                }
-            }
-
-            @Override
-            public void onPackageRemoved(String packageName, int uid) {
-                if (mServiceNameResolver != null
-                        && mServiceNameResolver.isConfiguredInMultipleMode()) {
-                    final int userId = getChangingUserId();
-                    synchronized (mLock) {
-                        handlePackageRemovedMultiModeLocked(packageName, userId);
-                    }
-                    return;
-                }
-
-                synchronized (mLock) {
-                    final int userId = getChangingUserId();
-                    final S service = peekServiceForUserLocked(userId);
-                    if (service != null) {
-                        final ComponentName componentName = service.getServiceComponentName();
-                        if (componentName != null) {
-                            if (packageName.equals(componentName.getPackageName())) {
-                                handleActiveServiceRemoved(userId);
-                            }
-                        }
-                    }
-                }
-            }
-
-            @Override
-            public boolean onHandleForceStop(Intent intent, String[] packages,
-                    int uid, boolean doit) {
-                synchronized (mLock) {
-                    final String activePackageName = getActiveServicePackageNameLocked();
-                    for (String pkg : packages) {
-                        if (pkg.equals(activePackageName)) {
-                            if (!doit) {
-                                return true;
-                            }
-                            final String action = intent.getAction();
-                            final int userId = getChangingUserId();
-                            if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
-                                handleActiveServiceRestartedLocked(activePackageName, userId);
-                            } else {
-                                removeCachedServiceListLocked(userId);
-                            }
-                        } else {
-                            handlePackageUpdateLocked(pkg);
-                        }
-                    }
-                }
-                return false;
-            }
-
-            @Override
-            public void onPackageDataCleared(String packageName, int uid) {
-                if (verbose) Slog.v(mTag, "onPackageDataCleared(): " + packageName);
-                final int userId = getChangingUserId();
-
-                if (mServiceNameResolver != null
-                        && mServiceNameResolver.isConfiguredInMultipleMode()) {
-                    synchronized (mLock) {
-                        onServicePackageDataClearedMultiModeLocked(packageName, userId);
-                    }
-                    return;
-                }
-
-                synchronized (mLock) {
-                    final S service = peekServiceForUserLocked(userId);
-                    if (service != null) {
-                        final ComponentName componentName = service.getServiceComponentName();
-                        if (componentName != null) {
-                            if (packageName.equals(componentName.getPackageName())) {
-                                onServicePackageDataClearedLocked(userId);
-                            }
-                        }
-                    }
-                }
-            }
-
-            private void handleActiveServiceRemoved(@UserIdInt int userId) {
-                synchronized (mLock) {
-                    removeCachedServiceListLocked(userId);
-                }
-                final String serviceSettingsProperty = getServiceSettingsProperty();
-                if (serviceSettingsProperty != null) {
-                    Settings.Secure.putStringForUser(getContext().getContentResolver(),
-                            serviceSettingsProperty, null, userId);
-                }
-            }
-
-            @GuardedBy("mLock")
-            private void handleActiveServiceRestartedLocked(String activePackageName,
-                    @UserIdInt int userId) {
-                if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_NO_REFRESH) != 0) {
+                mUpdatingPackageNames.put(userId, packageName);
+                onServicePackageUpdatingLocked(userId);
+                if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_NO_REFRESH) != 0) {
                     if (debug) {
                         Slog.d(mTag, "Holding service for user " + userId + " while package "
-                                + activePackageName + " is being restarted");
+                                + activePackageName + " is being updated");
                     }
                 } else {
                     if (debug) {
                         Slog.d(mTag, "Removing service for user " + userId
                                 + " because package " + activePackageName
-                                + " is being restarted");
+                                + " is being updated");
                     }
                     removeCachedServiceListLocked(userId);
 
-                    if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_REFRESH_EAGER) != 0) {
+                    if ((mServicePackagePolicyFlags & PACKAGE_UPDATE_POLICY_REFRESH_EAGER)
+                            != 0) {
                         if (debug) {
-                            Slog.d(mTag, "Eagerly recreating service for user " + userId);
+                            Slog.d(mTag, "Eagerly recreating service for user "
+                                    + userId);
                         }
-                        updateCachedServiceLocked(userId);
+                        getServiceForUserLocked(userId);
                     }
                 }
-                onServicePackageRestartedLocked(userId);
             }
+        }
 
-            @Override
-            public void onPackageModified(String packageName) {
+        @Override
+        public void onPackageUpdateFinished(@NonNull String packageName, int uid) {
+            if (verbose) Slog.v(mTag, "onPackageUpdateFinished(): " + packageName);
+            final int userId = getChangingUserId();
+            synchronized (mLock) {
+                final String activePackageName = mUpdatingPackageNames == null ? null
+                        : mUpdatingPackageNames.get(userId);
+                if (packageName.equals(activePackageName)) {
+                    if (mUpdatingPackageNames != null) {
+                        mUpdatingPackageNames.remove(userId);
+                        if (mUpdatingPackageNames.size() == 0) {
+                            mUpdatingPackageNames = null;
+                        }
+                    }
+                    onServicePackageUpdatedLocked(userId);
+                } else {
+                    handlePackageUpdateLocked(packageName);
+                }
+            }
+        }
+
+        @Override
+        public void onPackageRemoved(String packageName, int uid) {
+            if (mServiceNameResolver != null
+                    && mServiceNameResolver.isConfiguredInMultipleMode()) {
+                final int userId = getChangingUserId();
                 synchronized (mLock) {
-                    if (verbose) Slog.v(mTag, "onPackageModified(): " + packageName);
-
-                    if (mServiceNameResolver == null) {
-                        return;
-                    }
-
-                    final int userId = getChangingUserId();
-                    final String[] serviceNames = mServiceNameResolver.getDefaultServiceNameList(
-                            userId);
-                    if (serviceNames != null) {
-                        if (Flags.packageUpdateFixEnabled()) {
-                            if (mServiceNameResolver.isConfiguredInMultipleMode()) {
-                                // Remove any service that is in the cache but is no longer valid
-                                // after this modification for this particular package
-                                removeInvalidCachedServicesLocked(serviceNames, packageName,
-                                        userId);
-                            }
-                        }
-
-                        // Update services that are still valid
-                        for (int i = 0; i < serviceNames.length; i++) {
-                            peekAndUpdateCachedServiceLocked(packageName, userId,
-                                    serviceNames[i]);
-                        }
-                    }
+                    handlePackageRemovedMultiModeLocked(packageName, userId);
                 }
+                return;
             }
 
-            @GuardedBy("mLock")
-            private void peekAndUpdateCachedServiceLocked(String packageName, int userId,
-                    String serviceName) {
-                if (serviceName == null) {
-                    return;
-                }
-
-                final ComponentName serviceComponentName =
-                        ComponentName.unflattenFromString(serviceName);
-                if (serviceComponentName == null
-                        || !serviceComponentName.getPackageName().equals(packageName)) {
-                    return;
-                }
-
-                // The default service package has changed, update the cached if the service
-                // exists but no active component.
+            synchronized (mLock) {
+                final int userId = getChangingUserId();
                 final S service = peekServiceForUserLocked(userId);
                 if (service != null) {
                     final ComponentName componentName = service.getServiceComponentName();
-                    if (componentName == null) {
-                        if (verbose) Slog.v(mTag, "update cached");
-                        updateCachedServiceLocked(userId);
+                    if (componentName != null) {
+                        if (packageName.equals(componentName.getPackageName())) {
+                            handleActiveServiceRemoved(userId);
+                        }
                     }
                 }
             }
+        }
 
-            @GuardedBy("mLock")
-            private String getActiveServicePackageNameLocked() {
-                final int userId = getChangingUserId();
+        @Override
+        public boolean onHandleForceStop(Intent intent, String[] packages,
+                int uid, boolean doit) {
+            synchronized (mLock) {
+                final String activePackageName = getActiveServicePackageNameLocked();
+                for (String pkg : packages) {
+                    if (pkg.equals(activePackageName)) {
+                        if (!doit) {
+                            return true;
+                        }
+                        final String action = intent.getAction();
+                        final int userId = getChangingUserId();
+                        if (Intent.ACTION_PACKAGE_RESTARTED.equals(action)) {
+                            handleActiveServiceRestartedLocked(activePackageName, userId);
+                        } else {
+                            removeCachedServiceListLocked(userId);
+                        }
+                    } else {
+                        handlePackageUpdateLocked(pkg);
+                    }
+                }
+            }
+            return false;
+        }
+
+        @Override
+        public void onPackageDataCleared(String packageName, int uid) {
+            if (verbose) Slog.v(mTag, "onPackageDataCleared(): " + packageName);
+            final int userId = getChangingUserId();
+
+            if (mServiceNameResolver != null
+                    && mServiceNameResolver.isConfiguredInMultipleMode()) {
+                synchronized (mLock) {
+                    onServicePackageDataClearedMultiModeLocked(packageName, userId);
+                }
+                return;
+            }
+
+            synchronized (mLock) {
                 final S service = peekServiceForUserLocked(userId);
-                if (service == null) {
-                    return null;
+                if (service != null) {
+                    final ComponentName componentName = service.getServiceComponentName();
+                    if (componentName != null) {
+                        if (packageName.equals(componentName.getPackageName())) {
+                            onServicePackageDataClearedLocked(userId);
+                        }
+                    }
                 }
-                final ComponentName serviceComponent = service.getServiceComponentName();
-                if (serviceComponent == null) {
-                    return null;
+            }
+        }
+
+        private void handleActiveServiceRemoved(@UserIdInt int userId) {
+            synchronized (mLock) {
+                removeCachedServiceListLocked(userId);
+            }
+            final String serviceSettingsProperty = getServiceSettingsProperty();
+            if (serviceSettingsProperty != null) {
+                Settings.Secure.putStringForUser(getContext().getContentResolver(),
+                        serviceSettingsProperty, null, userId);
+            }
+        }
+
+        @GuardedBy("mLock")
+        private void handleActiveServiceRestartedLocked(String activePackageName,
+                @UserIdInt int userId) {
+            if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_NO_REFRESH) != 0) {
+                if (debug) {
+                    Slog.d(mTag, "Holding service for user " + userId + " while package "
+                            + activePackageName + " is being restarted");
                 }
-                return serviceComponent.getPackageName();
+            } else {
+                if (debug) {
+                    Slog.d(mTag, "Removing service for user " + userId
+                            + " because package " + activePackageName
+                            + " is being restarted");
+                }
+                removeCachedServiceListLocked(userId);
+
+                if ((mServicePackagePolicyFlags & PACKAGE_RESTART_POLICY_REFRESH_EAGER) != 0) {
+                    if (debug) {
+                        Slog.d(mTag, "Eagerly recreating service for user " + userId);
+                    }
+                    updateCachedServiceLocked(userId);
+                }
+            }
+            onServicePackageRestartedLocked(userId);
+        }
+
+        @Override
+        public void onPackageModified(String packageName) {
+            synchronized (mLock) {
+                if (verbose) Slog.v(mTag, "onPackageModified(): " + packageName);
+
+                if (mServiceNameResolver == null) {
+                    return;
+                }
+
+                final int userId = getChangingUserId();
+                final String[] serviceNames = mServiceNameResolver.getDefaultServiceNameList(
+                        userId);
+                if (serviceNames != null) {
+                    if (Flags.packageUpdateFixEnabled()) {
+                        if (mServiceNameResolver.isConfiguredInMultipleMode()) {
+                            // Remove any service that is in the cache but is no longer valid
+                            // after this modification for this particular package
+                            removeInvalidCachedServicesLocked(serviceNames, packageName,
+                                    userId);
+                        }
+                    }
+
+                    // Update services that are still valid
+                    for (int i = 0; i < serviceNames.length; i++) {
+                        peekAndUpdateCachedServiceLocked(packageName, userId,
+                                serviceNames[i]);
+                    }
+                }
+            }
+        }
+
+        @GuardedBy("mLock")
+        private void peekAndUpdateCachedServiceLocked(String packageName, int userId,
+                String serviceName) {
+            if (serviceName == null) {
+                return;
             }
 
-            @GuardedBy("mLock")
-            private void handlePackageUpdateLocked(String packageName) {
-                visitServicesLocked((s) -> s.handlePackageUpdateLocked(packageName));
+            final ComponentName serviceComponentName =
+                    ComponentName.unflattenFromString(serviceName);
+            if (serviceComponentName == null
+                    || !serviceComponentName.getPackageName().equals(packageName)) {
+                return;
             }
-        };
 
+            // The default service package has changed, update the cached if the service
+            // exists but no active component.
+            final S service = peekServiceForUserLocked(userId);
+            if (service != null) {
+                final ComponentName componentName = service.getServiceComponentName();
+                if (componentName == null) {
+                    if (verbose) Slog.v(mTag, "update cached");
+                    updateCachedServiceLocked(userId);
+                }
+            }
+        }
+
+        @GuardedBy("mLock")
+        private String getActiveServicePackageNameLocked() {
+            final int userId = getChangingUserId();
+            final S service = peekServiceForUserLocked(userId);
+            if (service == null) {
+                return null;
+            }
+            final ComponentName serviceComponent = service.getServiceComponentName();
+            if (serviceComponent == null) {
+                return null;
+            }
+            return serviceComponent.getPackageName();
+        }
+
+        @GuardedBy("mLock")
+        private void handlePackageUpdateLocked(String packageName) {
+            visitServicesLocked((s) -> s.handlePackageUpdateLocked(packageName));
+        }
+    }
+
+    private void startTrackingPackageChanges() {
         // package changes
-        monitor.register(getContext(), null, UserHandle.ALL, true);
+        mPackageMonitor.register(getContext(), null, UserHandle.ALL, true);
     }
 
     @GuardedBy("mLock")
diff --git a/services/core/java/com/android/server/input/InputGestureManager.java b/services/core/java/com/android/server/input/InputGestureManager.java
index 7f85384..67e1ccc 100644
--- a/services/core/java/com/android/server/input/InputGestureManager.java
+++ b/services/core/java/com/android/server/input/InputGestureManager.java
@@ -138,11 +138,6 @@
                         KeyGestureEvent.KEY_GESTURE_TYPE_TAKE_SCREENSHOT
                 ),
                 createKeyGesture(
-                        KeyEvent.KEYCODE_DEL,
-                        KeyEvent.META_META_ON,
-                        KeyGestureEvent.KEY_GESTURE_TYPE_BACK
-                ),
-                createKeyGesture(
                         KeyEvent.KEYCODE_ESCAPE,
                         KeyEvent.META_META_ON,
                         KeyGestureEvent.KEY_GESTURE_TYPE_BACK
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index af726bd..68ad8f7 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -2902,12 +2902,7 @@
         final long ident = Binder.clearCallingIdentity();
         try {
             if (windowPerceptible != null && !windowPerceptible) {
-                if ((vis & InputMethodService.IME_VISIBLE) != 0) {
-                    vis &= ~InputMethodService.IME_VISIBLE;
-                    vis |= InputMethodService.IME_VISIBLE_IMPERCEPTIBLE;
-                }
-            } else {
-                vis &= ~InputMethodService.IME_VISIBLE_IMPERCEPTIBLE;
+                vis &= ~InputMethodService.IME_VISIBLE;
             }
             final var curId = bindingController.getCurId();
             // TODO(b/305849394): Make mMenuController multi-user aware.
diff --git a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
index f40d0dd..2d937bd 100644
--- a/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
+++ b/services/core/java/com/android/server/location/contexthub/ContextHubEndpointBroker.java
@@ -16,6 +16,8 @@
 
 package com.android.server.location.contexthub;
 
+import static com.android.server.location.contexthub.ContextHubTransactionManager.RELIABLE_MESSAGE_DUPLICATE_DETECTION_TIMEOUT;
+
 import android.annotation.NonNull;
 import android.app.AppOpsManager;
 import android.content.Context;
@@ -44,6 +46,9 @@
 
 import java.util.Collection;
 import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Map;
 import java.util.Optional;
 import java.util.Set;
 import java.util.function.Consumer;
@@ -100,7 +105,7 @@
 
     private final Object mOpenSessionLock = new Object();
 
-    static class SessionInfo {
+    static class Session {
         enum SessionState {
             /* The session is pending acceptance from the remote endpoint. */
             PENDING,
@@ -119,7 +124,15 @@
          */
         private final Set<Integer> mPendingSequenceNumbers = new HashSet<>();
 
-        SessionInfo(HubEndpointInfo remoteEndpointInfo, boolean remoteInitiated) {
+        /**
+         * Stores the history of received messages that are timestamped. We use a LinkedHashMap to
+         * guarantee insertion ordering for easier manipulation of removing expired entries.
+         *
+         * <p>The key is the sequence number, and the value is the timestamp in milliseconds.
+         */
+        private final LinkedHashMap<Integer, Long> mRxMessageHistoryMap = new LinkedHashMap<>();
+
+        Session(HubEndpointInfo remoteEndpointInfo, boolean remoteInitiated) {
             mRemoteEndpointInfo = remoteEndpointInfo;
             mRemoteInitiated = remoteInitiated;
         }
@@ -157,11 +170,43 @@
                 consumer.accept(sequenceNumber);
             }
         }
+
+        public boolean isInMessageHistory(HubMessage message) {
+            // Clean up the history
+            Iterator<Map.Entry<Integer, Long>> iterator =
+                    mRxMessageHistoryMap.entrySet().iterator();
+            long nowMillis = System.currentTimeMillis();
+            while (iterator.hasNext()) {
+                Map.Entry<Integer, Long> nextEntry = iterator.next();
+                long expiryMillis = RELIABLE_MESSAGE_DUPLICATE_DETECTION_TIMEOUT.toMillis();
+                if (nowMillis >= nextEntry.getValue() + expiryMillis) {
+                    iterator.remove();
+                }
+                break;
+            }
+
+            return mRxMessageHistoryMap.containsKey(message.getMessageSequenceNumber());
+        }
+
+        public void addMessageToHistory(HubMessage message) {
+            if (mRxMessageHistoryMap.containsKey(message.getMessageSequenceNumber())) {
+                long value = mRxMessageHistoryMap.get(message.getMessageSequenceNumber());
+                Log.w(
+                        TAG,
+                        "Message already exists in history (inserted @ "
+                                + value
+                                + " ms): "
+                                + message);
+                return;
+            }
+            mRxMessageHistoryMap.put(
+                    message.getMessageSequenceNumber(), System.currentTimeMillis());
+        }
     }
 
     /** A map between a session ID which maps to its current state. */
     @GuardedBy("mOpenSessionLock")
-    private final SparseArray<SessionInfo> mSessionInfoMap = new SparseArray<>();
+    private final SparseArray<Session> mSessionMap = new SparseArray<>();
 
     /** The package name of the app that created the endpoint */
     private final String mPackageName;
@@ -232,7 +277,7 @@
 
         synchronized (mOpenSessionLock) {
             try {
-                mSessionInfoMap.put(sessionId, new SessionInfo(destination, false));
+                mSessionMap.put(sessionId, new Session(destination, false));
                 mHubInterface.openEndpointSession(
                         sessionId, halEndpointInfo.id, mHalEndpointInfo.id, serviceDescriptor);
             } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) {
@@ -263,8 +308,8 @@
         super.unregister_enforcePermission();
         synchronized (mOpenSessionLock) {
             // Iterate in reverse since cleanupSessionResources will remove the entry
-            for (int i = mSessionInfoMap.size() - 1; i >= 0; i--) {
-                int id = mSessionInfoMap.keyAt(i);
+            for (int i = mSessionMap.size() - 1; i >= 0; i--) {
+                int id = mSessionMap.keyAt(i);
                 halCloseEndpointSessionNoThrow(id, Reason.ENDPOINT_GONE);
                 cleanupSessionResources(id);
             }
@@ -290,14 +335,14 @@
     public void openSessionRequestComplete(int sessionId) {
         super.openSessionRequestComplete_enforcePermission();
         synchronized (mOpenSessionLock) {
-            SessionInfo info = mSessionInfoMap.get(sessionId);
+            Session info = mSessionMap.get(sessionId);
             if (info == null) {
                 throw new IllegalArgumentException(
                         "openSessionRequestComplete for invalid session id=" + sessionId);
             }
             try {
                 mHubInterface.endpointSessionOpenComplete(sessionId);
-                info.setSessionState(SessionInfo.SessionState.ACTIVE);
+                info.setSessionState(Session.SessionState.ACTIVE);
             } catch (RemoteException | IllegalArgumentException | UnsupportedOperationException e) {
                 Log.e(TAG, "Exception while calling endpointSessionOpenComplete", e);
             }
@@ -310,7 +355,7 @@
             int sessionId, HubMessage message, IContextHubTransactionCallback callback) {
         super.sendMessage_enforcePermission();
         synchronized (mOpenSessionLock) {
-            SessionInfo info = mSessionInfoMap.get(sessionId);
+            Session info = mSessionMap.get(sessionId);
             if (info == null) {
                 throw new IllegalArgumentException(
                         "sendMessage for invalid session id=" + sessionId);
@@ -393,9 +438,9 @@
         } else {
             synchronized (mOpenSessionLock) {
                 // Iterate in reverse since cleanupSessionResources will remove the entry
-                for (int i = mSessionInfoMap.size() - 1; i >= 0; i--) {
-                    int id = mSessionInfoMap.keyAt(i);
-                    HubEndpointInfo target = mSessionInfoMap.get(id).getRemoteEndpointInfo();
+                for (int i = mSessionMap.size() - 1; i >= 0; i--) {
+                    int id = mSessionMap.keyAt(i);
+                    HubEndpointInfo target = mSessionMap.get(id).getRemoteEndpointInfo();
                     if (!hasEndpointPermissions(target)) {
                         halCloseEndpointSessionNoThrow(id, Reason.PERMISSION_DENIED);
                         onCloseEndpointSession(id, Reason.PERMISSION_DENIED);
@@ -415,13 +460,13 @@
             sb.append("wakelock: ").append(mWakeLock);
         }
         synchronized (mOpenSessionLock) {
-            if (mSessionInfoMap.size() != 0) {
+            if (mSessionMap.size() != 0) {
                 sb.append(System.lineSeparator());
                 sb.append(" sessions: ");
                 sb.append(System.lineSeparator());
             }
-            for (int i = 0; i < mSessionInfoMap.size(); i++) {
-                int id = mSessionInfoMap.keyAt(i);
+            for (int i = 0; i < mSessionMap.size(); i++) {
+                int id = mSessionMap.keyAt(i);
                 int count = i + 1;
                 sb.append(
                         "  "
@@ -429,7 +474,7 @@
                                 + ". id="
                                 + id
                                 + ", remote:"
-                                + mSessionInfoMap.get(id).getRemoteEndpointInfo());
+                                + mSessionMap.get(id).getRemoteEndpointInfo());
                 sb.append(System.lineSeparator());
             }
         }
@@ -485,23 +530,23 @@
                 Log.w(TAG, "Unknown session ID in onEndpointSessionOpenComplete: id=" + sessionId);
                 return;
             }
-            mSessionInfoMap.get(sessionId).setSessionState(SessionInfo.SessionState.ACTIVE);
+            mSessionMap.get(sessionId).setSessionState(Session.SessionState.ACTIVE);
         }
 
         invokeCallback((consumer) -> consumer.onSessionOpenComplete(sessionId));
     }
 
     /* package */ void onMessageReceived(int sessionId, HubMessage message) {
-        byte code = onMessageReceivedInternal(sessionId, message);
-        if (code != ErrorCode.OK && message.isResponseRequired()) {
-            sendMessageDeliveryStatus(sessionId, message.getMessageSequenceNumber(), code);
+        byte errorCode = onMessageReceivedInternal(sessionId, message);
+        if (errorCode != ErrorCode.OK && message.isResponseRequired()) {
+            sendMessageDeliveryStatus(sessionId, message.getMessageSequenceNumber(), errorCode);
         }
     }
 
     /* package */ void onMessageDeliveryStatusReceived(
             int sessionId, int sequenceNumber, byte errorCode) {
         synchronized (mOpenSessionLock) {
-            SessionInfo info = mSessionInfoMap.get(sessionId);
+            Session info = mSessionMap.get(sessionId);
             if (info == null || !info.isActive()) {
                 Log.w(TAG, "Received delivery status for invalid session: id=" + sessionId);
                 return;
@@ -517,7 +562,7 @@
 
     /* package */ boolean hasSessionId(int sessionId) {
         synchronized (mOpenSessionLock) {
-            return mSessionInfoMap.contains(sessionId);
+            return mSessionMap.contains(sessionId);
         }
     }
 
@@ -531,8 +576,8 @@
             }
         }
         synchronized (mOpenSessionLock) {
-            for (int i = mSessionInfoMap.size() - 1; i >= 0; i--) {
-                int id = mSessionInfoMap.keyAt(i);
+            for (int i = mSessionMap.size() - 1; i >= 0; i--) {
+                int id = mSessionMap.keyAt(i);
                 onCloseEndpointSession(id, Reason.HUB_RESET);
             }
         }
@@ -555,7 +600,7 @@
                 Log.e(TAG, "Existing session in onEndpointSessionOpenRequest: id=" + sessionId);
                 return Optional.of(Reason.UNSPECIFIED);
             }
-            mSessionInfoMap.put(sessionId, new SessionInfo(initiator, true));
+            mSessionMap.put(sessionId, new Session(initiator, true));
         }
 
         boolean success =
@@ -567,7 +612,6 @@
     }
 
     private byte onMessageReceivedInternal(int sessionId, HubMessage message) {
-        HubEndpointInfo remote;
         synchronized (mOpenSessionLock) {
             if (!isSessionActive(sessionId)) {
                 Log.e(
@@ -578,29 +622,36 @@
                                 + message);
                 return ErrorCode.PERMANENT_ERROR;
             }
-            remote = mSessionInfoMap.get(sessionId).getRemoteEndpointInfo();
-        }
+            HubEndpointInfo remote = mSessionMap.get(sessionId).getRemoteEndpointInfo();
+            if (mSessionMap.get(sessionId).isInMessageHistory(message)) {
+                Log.e(TAG, "Dropping duplicate message: " + message);
+                return ErrorCode.TRANSIENT_ERROR;
+            }
 
-        try {
-            Binder.withCleanCallingIdentity(
-                    () -> {
-                        if (!notePermissions(remote)) {
-                            throw new RuntimeException(
-                                    "Dropping message from "
-                                            + remote
-                                            + ". "
-                                            + mPackageName
-                                            + " doesn't have permission");
-                        }
-                    });
-        } catch (RuntimeException e) {
-            Log.e(TAG, e.getMessage());
-            return ErrorCode.PERMISSION_DENIED;
-        }
+            try {
+                Binder.withCleanCallingIdentity(
+                        () -> {
+                            if (!notePermissions(remote)) {
+                                throw new RuntimeException(
+                                        "Dropping message from "
+                                                + remote
+                                                + ". "
+                                                + mPackageName
+                                                + " doesn't have permission");
+                            }
+                        });
+            } catch (RuntimeException e) {
+                Log.e(TAG, e.getMessage());
+                return ErrorCode.PERMISSION_DENIED;
+            }
 
-        boolean success =
-                invokeCallback((consumer) -> consumer.onMessageReceived(sessionId, message));
-        return success ? ErrorCode.OK : ErrorCode.TRANSIENT_ERROR;
+            boolean success =
+                    invokeCallback((consumer) -> consumer.onMessageReceived(sessionId, message));
+            if (success) {
+                mSessionMap.get(sessionId).addMessageToHistory(message);
+            }
+            return success ? ErrorCode.OK : ErrorCode.TRANSIENT_ERROR;
+        }
     }
 
     /**
@@ -634,7 +685,7 @@
      */
     private boolean cleanupSessionResources(int sessionId) {
         synchronized (mOpenSessionLock) {
-            SessionInfo info = mSessionInfoMap.get(sessionId);
+            Session info = mSessionMap.get(sessionId);
             if (info != null) {
                 if (!info.isRemoteInitiated()) {
                     mEndpointManager.returnSessionId(sessionId);
@@ -644,7 +695,7 @@
                             mTransactionManager.onMessageDeliveryResponse(
                                     sequenceNumber, /* success= */ false);
                         });
-                mSessionInfoMap.remove(sessionId);
+                mSessionMap.remove(sessionId);
             }
             return info != null;
         }
@@ -656,7 +707,7 @@
      */
     private boolean isSessionActive(int sessionId) {
         synchronized (mOpenSessionLock) {
-            return hasSessionId(sessionId) && mSessionInfoMap.get(sessionId).isActive();
+            return hasSessionId(sessionId) && mSessionMap.get(sessionId).isActive();
         }
     }
 
diff --git a/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
index ebf7e6b..e540616 100644
--- a/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
+++ b/services/core/java/com/android/server/locksettings/recoverablekeystore/OWNERS
@@ -1,3 +1,2 @@
 aseemk@google.com
-bozhu@google.com
 dementyev@google.com
diff --git a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
index 23e9ac5..96e4539 100644
--- a/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
+++ b/services/core/java/com/android/server/media/MediaRoute2ProviderServiceProxy.java
@@ -983,6 +983,14 @@
             Objects.requireNonNull(providerInfo, "providerInfo must not be null");
 
             for (MediaRoute2Info route : providerInfo.getRoutes()) {
+                if (Flags.enableMirroringInMediaRouter2()
+                        && route.supportsRemoteRouting()
+                        && route.supportsSystemMediaRouting()
+                        && route.getDeduplicationIds().isEmpty()) {
+                    // This code is not accessible if the app is using the public API.
+                    throw new SecurityException("Route is missing deduplication id: " + route);
+                }
+
                 if (route.isSystemRoute()) {
                     throw new SecurityException(
                             "Only the system is allowed to publish system routes. "
diff --git a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
index debac94..f137de1 100644
--- a/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
+++ b/services/core/java/com/android/server/media/MediaRouter2ServiceImpl.java
@@ -25,8 +25,20 @@
 import static android.media.MediaRouter2.SCANNING_STATE_WHILE_INTERACTIVE;
 import static android.media.MediaRouter2Utils.getOriginalId;
 import static android.media.MediaRouter2Utils.getProviderId;
-
 import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_DESELECT_ROUTE;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_RELEASE_SESSION;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SELECT_ROUTE;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_TRANSFER_TO_ROUTE;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_ROUTE_ID;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_SESSION_ID;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_MANAGER_RECORD_NOT_FOUND;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_PERMISSION_DENIED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED;
 
 import android.Manifest;
 import android.annotation.NonNull;
@@ -64,14 +76,12 @@
 import android.util.Log;
 import android.util.Slog;
 import android.util.SparseArray;
-
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.function.pooled.PooledLambda;
 import com.android.media.flags.Flags;
 import com.android.server.LocalServices;
 import com.android.server.pm.UserManagerInternal;
 import com.android.server.statusbar.StatusBarManagerInternal;
-
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -130,9 +140,14 @@
     private final ArrayMap<IBinder, RouterRecord> mAllRouterRecords = new ArrayMap<>();
     @GuardedBy("mLock")
     private final ArrayMap<IBinder, ManagerRecord> mAllManagerRecords = new ArrayMap<>();
+
     @GuardedBy("mLock")
     private int mCurrentActiveUserId = -1;
 
+    @GuardedBy("mLock")
+    private static final MediaRouterMetricLogger mMediaRouterMetricLogger =
+            new MediaRouterMetricLogger();
+
     private final ActivityManager.OnUidImportanceListener mOnUidImportanceListener =
             (uid, importance) -> {
                 synchronized (mLock) {
@@ -350,8 +365,8 @@
         }
     }
 
-    public void setDiscoveryRequestWithRouter2(@NonNull IMediaRouter2 router,
-            @NonNull RouteDiscoveryPreference preference) {
+    public void setDiscoveryRequestWithRouter2(
+            @NonNull IMediaRouter2 router, @NonNull RouteDiscoveryPreference preference) {
         Objects.requireNonNull(router, "router must not be null");
         Objects.requireNonNull(preference, "preference must not be null");
 
@@ -409,8 +424,8 @@
         }
     }
 
-    public void setRouteVolumeWithRouter2(@NonNull IMediaRouter2 router,
-            @NonNull MediaRoute2Info route, int volume) {
+    public void setRouteVolumeWithRouter2(
+            @NonNull IMediaRouter2 router, @NonNull MediaRoute2Info route, int volume) {
         Objects.requireNonNull(router, "router must not be null");
         Objects.requireNonNull(route, "route must not be null");
 
@@ -439,12 +454,7 @@
         try {
             synchronized (mLock) {
                 requestCreateSessionWithRouter2Locked(
-                        requestId,
-                        managerRequestId,
-                        router,
-                        oldSession,
-                        route,
-                        sessionHints);
+                        requestId, managerRequestId, router, oldSession, route, sessionHints);
             }
         } finally {
             Binder.restoreCallingIdentity(token);
@@ -1326,6 +1336,9 @@
         final RouterRecord routerRecord = mAllRouterRecords.get(binder);
 
         if (routerRecord == null) {
+            mMediaRouterMetricLogger.logOperationFailure(
+                    MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION,
+                    MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND);
             return;
         }
 
@@ -1344,15 +1357,22 @@
         if (managerRequestId != MediaRoute2ProviderService.REQUEST_ID_NONE) {
             ManagerRecord manager = userHandler.findManagerWithId(toRequesterId(managerRequestId));
             if (manager == null || manager.mLastSessionCreationRequest == null) {
-                Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
-                        + "Ignoring unknown request.");
+                Slog.w(TAG, "requestCreateSessionWithRouter2Locked: Ignoring unknown request.");
+                mMediaRouterMetricLogger.logOperationFailure(
+                        MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_MANAGER_RECORD_NOT_FOUND);
                 routerRecord.notifySessionCreationFailed(requestId);
                 return;
             }
-            if (!TextUtils.equals(manager.mLastSessionCreationRequest.mOldSession.getId(),
-                    oldSession.getId())) {
-                Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
-                        + "Ignoring unmatched routing session.");
+            if (!TextUtils.equals(
+                    manager.mLastSessionCreationRequest.mOldSession.getId(), oldSession.getId())) {
+                Slog.w(
+                        TAG,
+                        "requestCreateSessionWithRouter2Locked: "
+                                + "Ignoring unmatched routing session.");
+                mMediaRouterMetricLogger.logOperationFailure(
+                        MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_SESSION_ID);
                 routerRecord.notifySessionCreationFailed(requestId);
                 return;
             }
@@ -1364,8 +1384,13 @@
                         && route.isSystemRoute()) {
                     route = manager.mLastSessionCreationRequest.mRoute;
                 } else {
-                    Slog.w(TAG, "requestCreateSessionWithRouter2Locked: "
-                            + "Ignoring unmatched route.");
+                    Slog.w(
+                            TAG,
+                            "requestCreateSessionWithRouter2Locked: "
+                                    + "Ignoring unmatched route.");
+                    mMediaRouterMetricLogger.logOperationFailure(
+                            MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION,
+                            MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_ROUTE_ID);
                     routerRecord.notifySessionCreationFailed(requestId);
                     return;
                 }
@@ -1376,14 +1401,19 @@
             if (route.isSystemRoute()
                     && !routerRecord.hasSystemRoutingPermission()
                     && !TextUtils.equals(route.getId(), defaultRouteId)) {
-                Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to"
-                        + route);
+                Slog.w(TAG, "MODIFY_AUDIO_ROUTING permission is required to transfer to" + route);
+                mMediaRouterMetricLogger.logOperationFailure(
+                        MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_PERMISSION_DENIED);
                 routerRecord.notifySessionCreationFailed(requestId);
                 return;
             }
         }
 
         long uniqueRequestId = toUniqueRequestId(routerRecord.mRouterId, requestId);
+        mMediaRouterMetricLogger.addRequestInfo(
+                uniqueRequestId,
+                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION);
         userHandler.sendMessage(
                 obtainMessage(
                         UserHandler::requestCreateSessionWithRouter2OnHandler,
@@ -1403,6 +1433,9 @@
         final RouterRecord routerRecord = mAllRouterRecords.get(binder);
 
         if (routerRecord == null) {
+            mMediaRouterMetricLogger.logOperationFailure(
+                    MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SELECT_ROUTE,
+                    MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND);
             return;
         }
 
@@ -1411,6 +1444,9 @@
                 TextUtils.formatSimple(
                         "selectRouteWithRouter2 | router: %s(id: %d), route: %s",
                         routerRecord.mPackageName, routerRecord.mRouterId, route.getId()));
+        mMediaRouterMetricLogger.logOperationTriggered(
+                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SELECT_ROUTE,
+                MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
 
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::selectRouteOnHandler,
@@ -1425,6 +1461,9 @@
         final RouterRecord routerRecord = mAllRouterRecords.get(binder);
 
         if (routerRecord == null) {
+            mMediaRouterMetricLogger.logOperationFailure(
+                    MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_DESELECT_ROUTE,
+                    MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND);
             return;
         }
 
@@ -1433,6 +1472,9 @@
                 TextUtils.formatSimple(
                         "deselectRouteWithRouter2 | router: %s(id: %d), route: %s",
                         routerRecord.mPackageName, routerRecord.mRouterId, route.getId()));
+        mMediaRouterMetricLogger.logOperationTriggered(
+                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_DESELECT_ROUTE,
+                MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
 
         routerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::deselectRouteOnHandler,
@@ -1450,6 +1492,9 @@
         final RouterRecord routerRecord = mAllRouterRecords.get(binder);
 
         if (routerRecord == null) {
+            mMediaRouterMetricLogger.logOperationFailure(
+                    MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_TRANSFER_TO_ROUTE,
+                    MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND);
             return;
         }
 
@@ -1458,6 +1503,9 @@
                 TextUtils.formatSimple(
                         "transferToRouteWithRouter2 | router: %s(id: %d), route: %s",
                         routerRecord.mPackageName, routerRecord.mRouterId, route.getId()));
+        mMediaRouterMetricLogger.logOperationTriggered(
+                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_TRANSFER_TO_ROUTE,
+                MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
 
         UserHandler userHandler = routerRecord.mUserRecord.mHandler;
         String defaultRouteId = userHandler.getSystemProvider().getDefaultRoute().getId();
@@ -1516,6 +1564,9 @@
         final RouterRecord routerRecord = mAllRouterRecords.get(binder);
 
         if (routerRecord == null) {
+            mMediaRouterMetricLogger.logOperationFailure(
+                    MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_RELEASE_SESSION,
+                    MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND);
             return;
         }
 
@@ -1794,6 +1845,9 @@
                 .findRouterWithSessionLocked(uniqueSessionId);
 
         long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
+        mMediaRouterMetricLogger.addRequestInfo(
+                uniqueRequestId, MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_SELECT_ROUTE);
+
         managerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::selectRouteOnHandler,
                         managerRecord.mUserRecord.mHandler,
@@ -1820,6 +1874,10 @@
                 .findRouterWithSessionLocked(uniqueSessionId);
 
         long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
+        mMediaRouterMetricLogger.addRequestInfo(
+                uniqueRequestId,
+                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_DESELECT_ROUTE);
+
         managerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(UserHandler::deselectRouteOnHandler,
                         managerRecord.mUserRecord.mHandler,
@@ -1851,6 +1909,10 @@
                 .findRouterWithSessionLocked(uniqueSessionId);
 
         long uniqueRequestId = toUniqueRequestId(managerRecord.mManagerId, requestId);
+        mMediaRouterMetricLogger.addRequestInfo(
+                uniqueRequestId,
+                MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_TRANSFER_TO_ROUTE);
+
         managerRecord.mUserRecord.mHandler.sendMessage(
                 obtainMessage(
                         UserHandler::transferToRouteOnHandler,
@@ -2792,7 +2854,8 @@
 
             if (!addedRoutes.isEmpty()) {
                 // If routes were added, newInfo cannot be null.
-                Slog.i(TAG,
+                Slog.i(
+                        TAG,
                         toLoggingMessage(
                                 /* source= */ "addProviderRoutes",
                                 newInfo.getUniqueId(),
@@ -2954,7 +3017,7 @@
         private void selectRouteOnHandler(long uniqueRequestId, @Nullable RouterRecord routerRecord,
                 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
             if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
-                    "selecting")) {
+                    "selecting", uniqueRequestId)) {
                 return;
             }
 
@@ -2963,8 +3026,12 @@
             if (provider == null) {
                 return;
             }
-            provider.selectRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
-                    route.getOriginalId());
+            provider.selectRoute(
+                    uniqueRequestId, getOriginalId(uniqueSessionId), route.getOriginalId());
+
+            // Log the success result.
+            mMediaRouterMetricLogger.logRequestResult(
+                    uniqueRequestId, MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS);
         }
 
         // routerRecord can be null if the session is system's or RCN.
@@ -2972,7 +3039,7 @@
                 @Nullable RouterRecord routerRecord,
                 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route) {
             if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
-                    "deselecting")) {
+                    "deselecting", uniqueRequestId)) {
                 return;
             }
 
@@ -2982,8 +3049,12 @@
                 return;
             }
 
-            provider.deselectRoute(uniqueRequestId, getOriginalId(uniqueSessionId),
-                    route.getOriginalId());
+            provider.deselectRoute(
+                    uniqueRequestId, getOriginalId(uniqueSessionId), route.getOriginalId());
+
+            // Log the success result.
+            mMediaRouterMetricLogger.logRequestResult(
+                    uniqueRequestId, MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS);
         }
 
         // routerRecord can be null if the session is system's or RCN.
@@ -2996,7 +3067,7 @@
                 @NonNull MediaRoute2Info route,
                 @RoutingSessionInfo.TransferReason int transferReason) {
             if (!checkArgumentsForSessionControl(routerRecord, uniqueSessionId, route,
-                    "transferring to")) {
+                    "transferring to", uniqueRequestId)) {
                 return;
             }
 
@@ -3016,18 +3087,25 @@
                     getOriginalId(uniqueSessionId),
                     route.getOriginalId(),
                     transferReason);
+
+            // Log the success result.
+            mMediaRouterMetricLogger.logRequestResult(
+                    uniqueRequestId, MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS);
         }
 
         // routerRecord is null if and only if the session is created without the request, which
         // includes the system's session and RCN cases.
         private boolean checkArgumentsForSessionControl(@Nullable RouterRecord routerRecord,
                 @NonNull String uniqueSessionId, @NonNull MediaRoute2Info route,
-                @NonNull String description) {
+                @NonNull String description, long uniqueRequestId) {
             final String providerId = route.getProviderId();
             final MediaRoute2Provider provider = findProvider(providerId);
             if (provider == null) {
                 Slog.w(TAG, "Ignoring " + description + " route since no provider found for "
                         + "given route=" + route);
+                mMediaRouterMetricLogger.logRequestResult(
+                        uniqueRequestId,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND);
                 return false;
             }
 
@@ -3050,6 +3128,9 @@
                                 + getPackageNameFromNullableRecord(matchingRecord)
                                 + " route="
                                 + route);
+                mMediaRouterMetricLogger.logRequestResult(
+                        uniqueRequestId,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTER_RECORD_NOT_FOUND);
                 return false;
             }
 
@@ -3057,6 +3138,9 @@
             if (sessionId == null) {
                 Slog.w(TAG, "Failed to get original session id from unique session id. "
                         + "uniqueSessionId=" + uniqueSessionId);
+                mMediaRouterMetricLogger.logRequestResult(
+                        uniqueRequestId,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_SESSION_ID);
                 return false;
             }
 
@@ -3168,6 +3252,10 @@
             }
             matchingRequest.mRouterRecord.notifySessionCreated(
                     toOriginalRequestId(uniqueRequestId), sessionInfo);
+
+            // Log the success result.
+            mMediaRouterMetricLogger.logRequestResult(
+                    uniqueRequestId, MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS);
         }
 
         /**
@@ -3255,10 +3343,14 @@
 
             // Currently, only manager records can get notified of failures.
             // TODO(b/282936553): Notify regular routers of request failures.
+
+            // Log the request result.
+            mMediaRouterMetricLogger.logRequestResult(
+                    uniqueRequestId, MediaRouterMetricLogger.convertResultFromReason(reason));
         }
 
-        private boolean handleSessionCreationRequestFailed(@NonNull MediaRoute2Provider provider,
-                long uniqueRequestId, int reason) {
+        private boolean handleSessionCreationRequestFailed(
+                @NonNull MediaRoute2Provider provider, long uniqueRequestId, int reason) {
             // Check whether the failure is about creating a session
             SessionCreationRequest matchingRequest = null;
             for (SessionCreationRequest request : mSessionCreationRequests) {
@@ -3385,8 +3477,8 @@
             }
         }
 
-        private void notifySessionCreatedToManagers(long managerRequestId,
-                @NonNull RoutingSessionInfo session) {
+        private void notifySessionCreatedToManagers(
+                long managerRequestId, @NonNull RoutingSessionInfo session) {
             int requesterId = toRequesterId(managerRequestId);
             int originalRequestId = toOriginalRequestId(managerRequestId);
 
diff --git a/services/core/java/com/android/server/media/MediaRouterMetricLogger.java b/services/core/java/com/android/server/media/MediaRouterMetricLogger.java
new file mode 100644
index 0000000..56d2a1b
--- /dev/null
+++ b/services/core/java/com/android/server/media/MediaRouterMetricLogger.java
@@ -0,0 +1,219 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_FAILED_TO_REROUTE_SYSTEM_MEDIA;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_NETWORK_ERROR;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_REJECTED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTE_NOT_AVAILABLE;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNIMPLEMENTED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNKNOWN_ERROR;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED;
+
+import android.annotation.NonNull;
+import android.media.MediaRoute2ProviderService;
+import android.util.Log;
+import android.util.Slog;
+import com.android.internal.annotations.VisibleForTesting;
+import java.io.PrintWriter;
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * Logs metrics for MediaRouter2.
+ *
+ * @hide
+ */
+final class MediaRouterMetricLogger {
+    private static final String TAG = "MediaRouterMetricLogger";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final int REQUEST_INFO_CACHE_CAPACITY = 100;
+
+    /** LRU cache to store request info. */
+    private final RequestInfoCache mRequestInfoCache;
+
+    /** Constructor for {@link MediaRouterMetricLogger}. */
+    public MediaRouterMetricLogger() {
+        mRequestInfoCache = new RequestInfoCache(REQUEST_INFO_CACHE_CAPACITY);
+    }
+
+    /**
+     * Adds a new request info to the cache.
+     *
+     * @param uniqueRequestId The unique request id.
+     * @param eventType The event type.
+     */
+    public void addRequestInfo(long uniqueRequestId, int eventType) {
+        RequestInfo requestInfo = new RequestInfo(uniqueRequestId, eventType);
+        mRequestInfoCache.put(requestInfo.mUniqueRequestId, requestInfo);
+    }
+
+    /**
+     * Removes a request info from the cache.
+     *
+     * @param uniqueRequestId The unique request id.
+     */
+    public void removeRequestInfo(long uniqueRequestId) {
+        mRequestInfoCache.remove(uniqueRequestId);
+    }
+
+    /**
+     * Logs an operation failure.
+     *
+     * @param eventType The event type.
+     * @param result The result of the operation.
+     */
+    public void logOperationFailure(int eventType, int result) {
+        logMediaRouterEvent(eventType, result);
+    }
+
+    /**
+     * Logs an operation triggered.
+     *
+     * @param eventType The event type.
+     */
+    public void logOperationTriggered(int eventType, int result) {
+        logMediaRouterEvent(eventType, result);
+    }
+
+    /**
+     * Logs the result of a request.
+     *
+     * @param uniqueRequestId The unique request id.
+     * @param result The result of the request.
+     */
+    public void logRequestResult(long uniqueRequestId, int result) {
+        RequestInfo requestInfo = mRequestInfoCache.get(uniqueRequestId);
+        if (requestInfo == null) {
+            Slog.w(
+                    TAG,
+                    "logRequestResult: No RequestInfo found for uniqueRequestId="
+                            + uniqueRequestId);
+            return;
+        }
+
+        int eventType = requestInfo.mEventType;
+        logMediaRouterEvent(eventType, result);
+
+        removeRequestInfo(uniqueRequestId);
+    }
+
+    /**
+     * Converts a reason code from {@link MediaRoute2ProviderService} to a result code for logging.
+     *
+     * @param reason The reason code from {@link MediaRoute2ProviderService}.
+     * @return The result code for logging.
+     */
+    public static int convertResultFromReason(int reason) {
+        switch (reason) {
+            case MediaRoute2ProviderService.REASON_UNKNOWN_ERROR:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNKNOWN_ERROR;
+            case MediaRoute2ProviderService.REASON_REJECTED:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_REJECTED;
+            case MediaRoute2ProviderService.REASON_NETWORK_ERROR:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_NETWORK_ERROR;
+            case MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTE_NOT_AVAILABLE;
+            case MediaRoute2ProviderService.REASON_INVALID_COMMAND:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND;
+            case MediaRoute2ProviderService.REASON_UNIMPLEMENTED:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNIMPLEMENTED;
+            case MediaRoute2ProviderService.REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_FAILED_TO_REROUTE_SYSTEM_MEDIA;
+            default:
+                return MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED;
+        }
+    }
+
+    /**
+     * Gets the size of the request info cache.
+     *
+     * @return The size of the request info cache.
+     */
+    @VisibleForTesting
+    public int getRequestCacheSize() {
+        return mRequestInfoCache.size();
+    }
+
+    private void logMediaRouterEvent(int eventType, int result) {
+        MediaRouterStatsLog.write(
+                MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED, eventType, result);
+
+        if (DEBUG) {
+            Slog.d(TAG, "logMediaRouterEvent: " + eventType + " " + result);
+        }
+    }
+
+    /** A cache for storing request info that evicts entries when it reaches its capacity. */
+    class RequestInfoCache extends LinkedHashMap<Long, RequestInfo> {
+
+        public final int capacity;
+
+        /**
+         * Constructor for {@link RequestInfoCache}.
+         *
+         * @param capacity The maximum capacity of the cache.
+         */
+        public RequestInfoCache(int capacity) {
+            super(capacity, 1.0f, true);
+            this.capacity = capacity;
+        }
+
+        @Override
+        protected boolean removeEldestEntry(Map.Entry<Long, RequestInfo> eldest) {
+            boolean shouldRemove = size() > capacity;
+            if (shouldRemove) {
+                Slog.d(TAG, "Evicted request info: " + eldest.getValue());
+                logOperationTriggered(
+                        eldest.getValue().mEventType,
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
+            }
+            return shouldRemove;
+        }
+    }
+
+    /** Class to store request info. */
+    static class RequestInfo {
+        public final long mUniqueRequestId;
+        public final int mEventType;
+
+        /**
+         * Constructor for {@link RequestInfo}.
+         *
+         * @param uniqueRequestId The unique request id.
+         * @param eventType The event type.
+         */
+        RequestInfo(long uniqueRequestId, int eventType) {
+            mUniqueRequestId = uniqueRequestId;
+            mEventType = eventType;
+        }
+
+        /**
+         * Dumps the request info.
+         *
+         * @param pw The print writer.
+         * @param prefix The prefix for the output.
+         */
+        public void dump(@NonNull PrintWriter pw, @NonNull String prefix) {
+            pw.println(prefix + "RequestInfo");
+            String indent = prefix + "  ";
+            pw.println(indent + "mUniqueRequestId=" + mUniqueRequestId);
+            pw.println(indent + "mEventType=" + mEventType);
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index b51e556..bfe0d32 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -2809,7 +2809,6 @@
                 mNotificationChannelLogger,
                 mAppOps,
                 mUserProfiles,
-                mUgmInternal,
                 mShowReviewPermissionsNotification,
                 Clock.systemUTC());
         mRankingHelper = new RankingHelper(getContext(), mRankingHandler, mPreferencesHelper,
@@ -7210,7 +7209,13 @@
             final Uri originalSoundUri =
                     (originalChannel != null) ? originalChannel.getSound() : null;
             if (soundUri != null && !Objects.equals(originalSoundUri, soundUri)) {
-                PermissionHelper.grantUriPermission(mUgmInternal, soundUri, sourceUid);
+                Binder.withCleanCallingIdentity(() -> {
+                    mUgmInternal.checkGrantUriPermission(sourceUid, null,
+                            ContentProvider.getUriWithoutUserId(soundUri),
+                            Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                            ContentProvider.getUserIdFromUri(soundUri,
+                            UserHandle.getUserId(sourceUid)));
+                });
             }
         }
 
diff --git a/services/core/java/com/android/server/notification/NotificationRecord.java b/services/core/java/com/android/server/notification/NotificationRecord.java
index 5a58f45..cec5a93 100644
--- a/services/core/java/com/android/server/notification/NotificationRecord.java
+++ b/services/core/java/com/android/server/notification/NotificationRecord.java
@@ -37,7 +37,10 @@
 import android.app.Notification;
 import android.app.NotificationChannel;
 import android.app.Person;
+import android.content.ContentProvider;
+import android.content.ContentResolver;
 import android.content.Context;
+import android.content.Intent;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.ShortcutInfo;
@@ -46,6 +49,7 @@
 import android.media.AudioSystem;
 import android.metrics.LogMaker;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -813,7 +817,13 @@
                 }
                 if ((android.app.Flags.nmSummarizationUi() || android.app.Flags.nmSummarization())
                         && signals.containsKey(KEY_SUMMARIZATION)) {
-                    mSummarization = signals.getString(KEY_SUMMARIZATION);
+                    CharSequence summary = signals.getCharSequence(KEY_SUMMARIZATION,
+                            signals.getString(KEY_SUMMARIZATION));
+                    if (summary != null) {
+                        mSummarization = summary.toString();
+                    } else {
+                        mSummarization = null;
+                    }
                     EventLogTags.writeNotificationAdjusted(getKey(),
                             KEY_SUMMARIZATION, Boolean.toString(mSummarization != null));
                 }
@@ -1532,15 +1542,21 @@
      * {@link #mGrantableUris}. Otherwise, this will either log or throw
      * {@link SecurityException} depending on target SDK of enqueuing app.
      */
-    private void visitGrantableUri(Uri uri, boolean userOverriddenUri,
-            boolean isSound) {
+    private void visitGrantableUri(Uri uri, boolean userOverriddenUri, boolean isSound) {
+        if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
+
         if (mGrantableUris != null && mGrantableUris.contains(uri)) {
             return; // already verified this URI
         }
 
         final int sourceUid = getSbn().getUid();
+        final long ident = Binder.clearCallingIdentity();
         try {
-            PermissionHelper.grantUriPermission(mUgmInternal, uri, sourceUid);
+            // This will throw a SecurityException if the caller can't grant.
+            mUgmInternal.checkGrantUriPermission(sourceUid, null,
+                    ContentProvider.getUriWithoutUserId(uri),
+                    Intent.FLAG_GRANT_READ_URI_PERMISSION,
+                    ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
 
             if (mGrantableUris == null) {
                 mGrantableUris = new ArraySet<>();
@@ -1560,6 +1576,8 @@
                     }
                 }
             }
+        } finally {
+            Binder.restoreCallingIdentity(ident);
         }
     }
 
diff --git a/services/core/java/com/android/server/notification/PermissionHelper.java b/services/core/java/com/android/server/notification/PermissionHelper.java
index 1464d48..b6f4889 100644
--- a/services/core/java/com/android/server/notification/PermissionHelper.java
+++ b/services/core/java/com/android/server/notification/PermissionHelper.java
@@ -25,25 +25,19 @@
 import android.annotation.NonNull;
 import android.annotation.UserIdInt;
 import android.companion.virtual.VirtualDeviceManager;
-import android.content.ContentProvider;
-import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
 import android.content.pm.IPackageManager;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.ParceledListSlice;
-import android.net.Uri;
 import android.os.Binder;
 import android.os.RemoteException;
-import android.os.UserHandle;
 import android.permission.IPermissionManager;
 import android.util.ArrayMap;
 import android.util.Pair;
 import android.util.Slog;
 
 import com.android.internal.util.ArrayUtils;
-import com.android.server.uri.UriGrantsManagerInternal;
 
 import java.util.Collections;
 import java.util.HashSet;
@@ -64,7 +58,7 @@
     private final IPermissionManager mPermManager;
 
     public PermissionHelper(Context context, IPackageManager packageManager,
-                IPermissionManager permManager) {
+            IPermissionManager permManager) {
         mContext = context;
         mPackageManager = packageManager;
         mPermManager = permManager;
@@ -304,19 +298,6 @@
         return false;
     }
 
-    static void grantUriPermission(final UriGrantsManagerInternal ugmInternal, Uri uri,
-            int sourceUid) {
-        if (uri == null || !ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) return;
-
-        Binder.withCleanCallingIdentity(() -> {
-            // This will throw a SecurityException if the caller can't grant.
-            ugmInternal.checkGrantUriPermission(sourceUid, null,
-                    ContentProvider.getUriWithoutUserId(uri),
-                    Intent.FLAG_GRANT_READ_URI_PERMISSION,
-                    ContentProvider.getUserIdFromUri(uri, UserHandle.getUserId(sourceUid)));
-        });
-    }
-
     public static class PackagePermission {
         public final String packageName;
         public final @UserIdInt int userId;
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 46ff798..b26b457 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -100,7 +100,6 @@
 import com.android.modules.utils.TypedXmlPullParser;
 import com.android.modules.utils.TypedXmlSerializer;
 import com.android.server.notification.PermissionHelper.PackagePermission;
-import com.android.server.uri.UriGrantsManagerInternal;
 
 import org.json.JSONArray;
 import org.json.JSONException;
@@ -228,7 +227,6 @@
     private final NotificationChannelLogger mNotificationChannelLogger;
     private final AppOpsManager mAppOps;
     private final ManagedServices.UserProfiles mUserProfiles;
-    private final UriGrantsManagerInternal mUgmInternal;
 
     private SparseBooleanArray mBadgingEnabled;
     private SparseBooleanArray mBubblesEnabled;
@@ -247,7 +245,6 @@
             ZenModeHelper zenHelper, PermissionHelper permHelper, PermissionManager permManager,
             NotificationChannelLogger notificationChannelLogger,
             AppOpsManager appOpsManager, ManagedServices.UserProfiles userProfiles,
-            UriGrantsManagerInternal ugmInternal,
             boolean showReviewPermissionsNotification, Clock clock) {
         mContext = context;
         mZenModeHelper = zenHelper;
@@ -258,7 +255,6 @@
         mNotificationChannelLogger = notificationChannelLogger;
         mAppOps = appOpsManager;
         mUserProfiles = userProfiles;
-        mUgmInternal = ugmInternal;
         mShowReviewPermissionsNotification = showReviewPermissionsNotification;
         mIsMediaNotificationFilteringEnabled = context.getResources()
                 .getBoolean(R.bool.config_quickSettingsShowMediaPlayer);
@@ -1195,11 +1191,6 @@
                 }
                 clearLockedFieldsLocked(channel);
 
-                // Verify that the app has permission to read the sound Uri
-                // Only check for new channels, as regular apps can only set sound
-                // before creating. See: {@link NotificationChannel#setSound}
-                PermissionHelper.grantUriPermission(mUgmInternal, channel.getSound(), uid);
-
                 channel.setImportanceLockedByCriticalDeviceFunction(
                         r.defaultAppLockedImportance || r.fixedImportance);
 
diff --git a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
index 60d028b..f379761 100644
--- a/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
+++ b/services/core/java/com/android/server/pm/BackgroundInstallControlService.java
@@ -392,7 +392,7 @@
 
     private boolean installedByAdb(String initiatingPackageName) {
         // GTS tests needs to adopt shell identity to install apps.
-        if(!SystemProperties.get("gts.transparency.bg-install-apps").isEmpty()) {
+        if(!SystemProperties.get("debug.gts.transparency.bg-install-apps").isEmpty()) {
             Slog.d(TAG, "handlePackageAdd: is GTS tests, skipping ADB check");
         } else if(PackageManagerServiceUtils.isInstalledByAdb(initiatingPackageName)) {
             Slog.d(TAG, "handlePackageAdd: is installed by ADB, skipping");
diff --git a/services/core/java/com/android/server/pm/PackageInstallerSession.java b/services/core/java/com/android/server/pm/PackageInstallerSession.java
index 635ef06..af788ea 100644
--- a/services/core/java/com/android/server/pm/PackageInstallerSession.java
+++ b/services/core/java/com/android/server/pm/PackageInstallerSession.java
@@ -21,6 +21,7 @@
 import static android.app.admin.DevicePolicyResources.Strings.Core.PACKAGE_UPDATED_BY_DO;
 import static android.content.pm.DataLoaderType.INCREMENTAL;
 import static android.content.pm.DataLoaderType.STREAMING;
+import static android.content.pm.Flags.cloudCompilationVerification;
 import static android.content.pm.PackageInstaller.LOCATION_DATA_APP;
 import static android.content.pm.PackageInstaller.UNARCHIVAL_OK;
 import static android.content.pm.PackageInstaller.UNARCHIVAL_STATUS_UNSET;
@@ -3687,6 +3688,10 @@
             CollectionUtils.addAll(stagedSplitTypes, apk.getSplitTypes());
         }
 
+        if (cloudCompilationVerification()) {
+            verifySdmSignatures(artManagedFilePaths, mSigningDetails);
+        }
+
         if (removeSplitList.size() > 0) {
             if (pkgInfo == null) {
                 throw new PackageManagerException(INSTALL_FAILED_INVALID_APK,
@@ -4028,6 +4033,14 @@
             File targetArtManagedFile = new File(
                     ArtManagedInstallFileHelper.getTargetPathForApk(path, targetFile.getPath()));
             stageFileLocked(artManagedFile, targetArtManagedFile);
+            if (!artManagedFile.equals(targetArtManagedFile)) {
+                // The file has been renamed. Update the list to reflect the change.
+                for (int i = 0; i < artManagedFilePaths.size(); ++i) {
+                    if (artManagedFilePaths.get(i).equals(path)) {
+                        artManagedFilePaths.set(i, targetArtManagedFile.getAbsolutePath());
+                    }
+                }
+            }
         }
     }
 
@@ -4309,6 +4322,37 @@
     }
 
     /**
+     * Verifies the signatures of SDM files.
+     *
+     * SDM is a file format that contains the cloud compilation artifacts. As a requirement, the SDM
+     * file should be signed with the same key as the APK.
+     *
+     * TODO(b/377474232): Move this logic to ART Service.
+     */
+    private static void verifySdmSignatures(List<String> artManagedFilePaths,
+            SigningDetails expectedSigningDetails) throws PackageManagerException {
+        ParseTypeImpl input = ParseTypeImpl.forDefaultParsing();
+        for (String path : artManagedFilePaths) {
+            if (!path.endsWith(".sdm")) {
+                continue;
+            }
+            // SDM is a format introduced in Android 16, so we don't need to support older
+            // signature schemes.
+            int minSignatureScheme = SigningDetails.SignatureSchemeVersion.SIGNING_BLOCK_V3;
+            ParseResult<SigningDetails> verified =
+                    ApkSignatureVerifier.verify(input, path, minSignatureScheme);
+            if (verified.isError()) {
+                throw new PackageManagerException(
+                        INSTALL_FAILED_INVALID_APK, "Failed to verify SDM signatures");
+            }
+            if (!expectedSigningDetails.signaturesMatchExactly(verified.getResult())) {
+                throw new PackageManagerException(
+                        INSTALL_FAILED_INVALID_APK, "SDM signatures are inconsistent with APK");
+            }
+        }
+    }
+
+    /**
      * @return the uid of the owner this session
      */
     public int getInstallerUid() {
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index d351305..66e9e77 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -1792,7 +1792,7 @@
     void injectPostToHandlerDebounced(@NonNull final Object token, @NonNull final Runnable r) {
         Objects.requireNonNull(token);
         Objects.requireNonNull(r);
-        synchronized (mServiceLock) {
+        synchronized (mHandler) {
             mHandler.removeCallbacksAndMessages(token);
             mHandler.postDelayed(r, token, CALLBACK_DELAY);
         }
diff --git a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
index 6ab3059..098f113 100644
--- a/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/permission/DefaultPermissionGrantPolicy.java
@@ -897,7 +897,7 @@
                     SearchManager.INTENT_ACTION_GLOBAL_SEARCH, userId);
             grantPermissionsToSystemPackage(pm, voiceSearchPackage,
                     userId, PHONE_PERMISSIONS, CALENDAR_PERMISSIONS, NEARBY_DEVICES_PERMISSIONS,
-                    COARSE_BACKGROUND_LOCATION_PERMISSIONS);
+                    COARSE_BACKGROUND_LOCATION_PERMISSIONS, CONTACTS_PERMISSIONS);
             revokeRuntimePermissions(pm, voiceSearchPackage,
                 FINE_LOCATION_PERMISSIONS, false, userId);
         }
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index f27194a..46dc758 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -3801,7 +3801,7 @@
                         return true;
                     }
                 }
-                // fall through
+                break;
             case KeyEvent.KEYCODE_ESCAPE:
                 if (firstDown && event.isMetaPressed()) {
                     notifyKeyGestureCompleted(event,
@@ -6706,12 +6706,6 @@
         return mKeyguardDelegate.isInputRestricted();
     }
 
-    /** {@inheritDoc} */
-    @Override
-    public boolean isKeyguardUnoccluding() {
-        return keyguardOn() && !mWindowManagerFuncs.isAppTransitionStateIdle();
-    }
-
     @Override
     public void dismissKeyguardLw(IKeyguardDismissCallback callback, CharSequence message) {
         if (mKeyguardDelegate != null && mKeyguardDelegate.isShowing()) {
diff --git a/services/core/java/com/android/server/policy/WindowManagerPolicy.java b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
index cc31bb1..d7de22e 100644
--- a/services/core/java/com/android/server/policy/WindowManagerPolicy.java
+++ b/services/core/java/com/android/server/policy/WindowManagerPolicy.java
@@ -337,12 +337,6 @@
         void moveDisplayToTopIfAllowed(int displayId);
 
         /**
-         * Return whether the app transition state is idle.
-         * @return {@code true} if app transition state is idle on the default display.
-         */
-        boolean isAppTransitionStateIdle();
-
-        /**
          * Enables the screen if all conditions are met.
          */
         void enableScreenIfNeeded();
@@ -989,14 +983,6 @@
     public boolean isKeyguardOccluded();
 
     /**
-     * Return whether the keyguard is unoccluding.
-     * @return {@code true} if the keyguard is unoccluding.
-     */
-    default boolean isKeyguardUnoccluding() {
-        return false;
-    }
-
-    /**
      * @return true if in keyguard is on.
      */
     boolean isKeyguardShowing();
diff --git a/services/core/java/com/android/server/security/advancedprotection/OWNERS b/services/core/java/com/android/server/security/advancedprotection/OWNERS
index 9bf5e58..8336ee8 100644
--- a/services/core/java/com/android/server/security/advancedprotection/OWNERS
+++ b/services/core/java/com/android/server/security/advancedprotection/OWNERS
@@ -1 +1,2 @@
 file:platform/frameworks/base:main:/core/java/android/security/advancedprotection/OWNERS
+per-file features/UsbDataAdvancedProtectionHook.java = georgechan@google.com, maunik@google.com
diff --git a/services/core/java/com/android/server/updates/CertPinInstallReceiver.java b/services/core/java/com/android/server/updates/CertPinInstallReceiver.java
index 250e99b..c8e7a8d 100644
--- a/services/core/java/com/android/server/updates/CertPinInstallReceiver.java
+++ b/services/core/java/com/android/server/updates/CertPinInstallReceiver.java
@@ -19,7 +19,10 @@
 import android.content.Context;
 import android.content.Intent;
 
+import java.io.File;
+
 public class CertPinInstallReceiver extends ConfigUpdateInstallReceiver {
+    private static final String KEYCHAIN_DIR = "/data/misc/keychain/";
 
     public CertPinInstallReceiver() {
         super("/data/misc/keychain/", "pins", "metadata/", "version");
@@ -27,7 +30,22 @@
 
     @Override
     public void onReceive(final Context context, final Intent intent) {
-        if (!com.android.server.flags.Flags.certpininstallerRemoval()) {
+        if (Intent.ACTION_BOOT_COMPLETED.equals(intent.getAction())) {
+            if (com.android.server.flags.Flags.certpininstallerRemoval()) {
+                File pins = new File(KEYCHAIN_DIR + "pins");
+                if (pins.exists()) {
+                    pins.delete();
+                }
+                File version = new File(KEYCHAIN_DIR + "metadata/version");
+                if (version.exists()) {
+                    version.delete();
+                }
+                File metadata = new File(KEYCHAIN_DIR + "metadata");
+                if (metadata.exists()) {
+                    metadata.delete();
+                }
+            }
+        } else if (!com.android.server.flags.Flags.certpininstallerRemoval()) {
             super.onReceive(context, intent);
         }
     }
diff --git a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
index 621a128..94e8ca5 100644
--- a/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
+++ b/services/core/java/com/android/server/vibrator/VendorVibrationSession.java
@@ -51,7 +51,9 @@
 final class VendorVibrationSession extends IVibrationSession.Stub
         implements VibrationSession, CancellationSignal.OnCancelListener, IBinder.DeathRecipient {
     private static final String TAG = "VendorVibrationSession";
-    private static final boolean DEBUG = false;
+    // To enable these logs, run:
+    // 'adb shell setprop persist.log.tag.VendorVibrationSession DEBUG && adb reboot'
+    private static final boolean DEBUG = VibratorDebugUtils.isDebuggable(TAG);
 
     /** Calls into VibratorManager functionality needed for playing an {@link ExternalVibration}. */
     interface VibratorManagerHooks {
diff --git a/services/core/java/com/android/server/vibrator/VibrationThread.java b/services/core/java/com/android/server/vibrator/VibrationThread.java
index cb9988f..ab30cdc 100644
--- a/services/core/java/com/android/server/vibrator/VibrationThread.java
+++ b/services/core/java/com/android/server/vibrator/VibrationThread.java
@@ -36,7 +36,9 @@
 /** Plays a {@link HalVibration} in dedicated thread. */
 final class VibrationThread extends Thread {
     static final String TAG = "VibrationThread";
-    static final boolean DEBUG = false;
+    // To enable these logs, run:
+    // 'adb shell setprop persist.log.tag.VibrationThread DEBUG && adb reboot'
+    static final boolean DEBUG = VibratorDebugUtils.isDebuggable(TAG);
 
     /** Calls into VibratorManager functionality needed for playing a {@link HalVibration}. */
     interface VibratorManagerHooks {
diff --git a/services/core/java/com/android/server/vibrator/VibratorDebugUtils.java b/services/core/java/com/android/server/vibrator/VibratorDebugUtils.java
new file mode 100644
index 0000000..9f37e76
--- /dev/null
+++ b/services/core/java/com/android/server/vibrator/VibratorDebugUtils.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.vibrator;
+
+import android.util.Log;
+
+class VibratorDebugUtils {
+
+    /**
+     * Checks if debugging is enabled for the specified tag or globally.
+     *
+     * <p>To enable debugging:<br>
+     * {@code adb shell setprop persist.log.tag.Vibrator_All DEBUG}<br>
+     * To disable debugging:<br>
+     * {@code adb shell setprop persist.log.tag.Vibrator_All \"\" }
+     *
+     * @param tag The tag to check for debugging. Use the tag name from the calling class.
+     * @return True if debugging is enabled for the tag or globally (Vibrator_All), false otherwise.
+     */
+    public static boolean isDebuggable(String tag) {
+        return Log.isLoggable(tag, Log.DEBUG) || Log.isLoggable("Vibrator_All", Log.DEBUG);
+    }
+}
diff --git a/services/core/java/com/android/server/vibrator/VibratorManagerService.java b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
index ce91e63..b953097 100644
--- a/services/core/java/com/android/server/vibrator/VibratorManagerService.java
+++ b/services/core/java/com/android/server/vibrator/VibratorManagerService.java
@@ -108,7 +108,9 @@
     private static final String EXTERNAL_VIBRATOR_SERVICE = "external_vibrator_service";
     private static final String VIBRATOR_CONTROL_SERVICE =
             "android.frameworks.vibrator.IVibratorControlService/default";
-    private static final boolean DEBUG = false;
+    // To enable these logs, run:
+    // 'adb shell setprop persist.log.tag.VibratorManagerService DEBUG && adb reboot'
+    private static final boolean DEBUG = VibratorDebugUtils.isDebuggable(TAG);
     private static final VibrationAttributes DEFAULT_ATTRIBUTES =
             new VibrationAttributes.Builder().build();
     private static final int ATTRIBUTES_ALL_BYPASS_FLAGS =
diff --git a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
index d620e98..bac7326 100644
--- a/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
+++ b/services/core/java/com/android/server/wallpaper/WallpaperManagerService.java
@@ -1173,12 +1173,19 @@
                     return;
                 }
 
-                final ComponentName wpService = mWallpaper.getComponent();
                 // The broadcast of package update could be delayed after service disconnected. Try
                 // to re-bind the service for 10 seconds.
                 mWallpaper.mBindSource = BindSource.CONNECTION_TRY_TO_REBIND;
-                if (bindWallpaperComponentLocked(
-                        wpService, true, false, mWallpaper, null)) {
+                boolean success;
+                if (liveWallpaperContentHandling()) {
+                    success = bindWallpaperDescriptionLocked(
+                            mWallpaper.getDescription(), /* force= */ true,
+                            /* fromUser= */ false, mWallpaper, /* reply= */ null);
+                } else {
+                    success = bindWallpaperComponentLocked(mWallpaper.getComponent(), /* force= */
+                            true, /* fromUser= */false, mWallpaper, /* reply= */ null);
+                }
+                if (success) {
                     mWallpaper.connection.scheduleTimeoutLocked();
                 } else if (SystemClock.uptimeMillis() - mWallpaper.lastDiedTime
                         < WALLPAPER_RECONNECT_TIMEOUT_MS) {
@@ -1189,7 +1196,7 @@
                     // Timeout
                     Slog.w(TAG, "Reverting to built-in wallpaper!");
                     clearWallpaperLocked(mWallpaper.mWhich, mWallpaper.userId, false, null);
-                    final String flattened = wpService.flattenToString();
+                    final String flattened = mWallpaper.getComponent().flattenToString();
                     EventLog.writeEvent(EventLogTags.WP_WALLPAPER_CRASHED,
                             flattened.substring(0, Math.min(flattened.length(),
                                     MAX_WALLPAPER_COMPONENT_LOG_LENGTH)));
diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java
index 58534b9..1299a4d 100644
--- a/services/core/java/com/android/server/wm/AccessibilityController.java
+++ b/services/core/java/com/android/server/wm/AccessibilityController.java
@@ -294,19 +294,6 @@
         }
     }
 
-    void onAppWindowTransition(int displayId, int transition) {
-        if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
-            mAccessibilityTracing.logTrace(TAG + ".onAppWindowTransition",
-                    FLAGS_MAGNIFICATION_CALLBACK,
-                    "displayId=" + displayId + "; transition=" + transition);
-        }
-        final DisplayMagnifier displayMagnifier = mDisplayMagnifiers.get(displayId);
-        if (displayMagnifier != null) {
-            displayMagnifier.onAppWindowTransition(displayId, transition);
-        }
-        // Not relevant for the window observer.
-    }
-
     void onWMTransition(int displayId, @TransitionType int type, @TransitionFlags int flags) {
         if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
             mAccessibilityTracing.logTrace(TAG + ".onWMTransition",
@@ -670,34 +657,6 @@
             mHandler.sendEmptyMessage(MyHandler.MESSAGE_NOTIFY_DISPLAY_SIZE_CHANGED);
         }
 
-        void onAppWindowTransition(int displayId, int transition) {
-            if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
-                mAccessibilityTracing.logTrace(LOG_TAG + ".onAppWindowTransition",
-                        FLAGS_MAGNIFICATION_CALLBACK,
-                        "displayId=" + displayId + "; transition=" + transition);
-            }
-            if (DEBUG_WINDOW_TRANSITIONS) {
-                Slog.i(LOG_TAG, "Window transition: "
-                        + AppTransition.appTransitionOldToString(transition)
-                        + " displayId: " + displayId);
-            }
-            final boolean isMagnifierActivated = isFullscreenMagnificationActivated();
-            if (!isMagnifierActivated) {
-                return;
-            }
-            switch (transition) {
-                case WindowManager.TRANSIT_OLD_ACTIVITY_OPEN:
-                case WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN:
-                case WindowManager.TRANSIT_OLD_TASK_OPEN:
-                case WindowManager.TRANSIT_OLD_TASK_TO_FRONT:
-                case WindowManager.TRANSIT_OLD_WALLPAPER_OPEN:
-                case WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE:
-                case WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN: {
-                    mUserContextChangedNotifier.onAppWindowTransition(transition);
-                }
-            }
-        }
-
         void onWMTransition(int displayId, @TransitionType int type, @TransitionFlags int flags) {
             if (mAccessibilityTracing.isTracingEnabled(FLAGS_MAGNIFICATION_CALLBACK)) {
                 mAccessibilityTracing.logTrace(LOG_TAG + ".onWMTransition",
@@ -734,7 +693,7 @@
             }
             if (DEBUG_WINDOW_TRANSITIONS) {
                 Slog.i(LOG_TAG, "Window transition: "
-                        + AppTransition.appTransitionOldToString(transition)
+                        + WindowManager.transitTypeToString(transition)
                         + " displayId: " + windowState.getDisplayId());
             }
             final boolean isMagnifierActivated = isFullscreenMagnificationActivated();
diff --git a/services/core/java/com/android/server/wm/ActivityClientController.java b/services/core/java/com/android/server/wm/ActivityClientController.java
index 7ce52b1..7da4beb 100644
--- a/services/core/java/com/android/server/wm/ActivityClientController.java
+++ b/services/core/java/com/android/server/wm/ActivityClientController.java
@@ -1113,11 +1113,11 @@
                     false /* fromClient */);
         }
 
+        final EnterPipRequestedItem item = new EnterPipRequestedItem(r.token);
         try {
-            final EnterPipRequestedItem item = new EnterPipRequestedItem(r.token);
-            mService.getLifecycleManager().scheduleTransactionItem(r.app.getThread(), item);
-            return true;
-        } catch (Exception e) {
+            return mService.getLifecycleManager().scheduleTransactionItem(r.app.getThread(), item);
+        } catch (RemoteException e) {
+            // TODO(b/323801078): remove Exception when cleanup
             Slog.w(TAG, "Failed to send enter pip requested item: "
                     + r.intent.getComponent(), e);
             return false;
@@ -1129,10 +1129,11 @@
      */
     void onPictureInPictureUiStateChanged(@NonNull ActivityRecord r,
             PictureInPictureUiState pipState) {
+        final PipStateTransactionItem item = new PipStateTransactionItem(r.token, pipState);
         try {
-            final PipStateTransactionItem item = new PipStateTransactionItem(r.token, pipState);
             mService.getLifecycleManager().scheduleTransactionItem(r.app.getThread(), item);
-        } catch (Exception e) {
+        } catch (RemoteException e) {
+            // TODO(b/323801078): remove Exception when cleanup
             Slog.w(TAG, "Failed to send pip state transaction item: "
                     + r.intent.getComponent(), e);
         }
@@ -1510,9 +1511,6 @@
         synchronized (mGlobalLock) {
             final ActivityRecord r = ActivityRecord.isInRootTaskLocked(token);
             if (r != null && r.isState(RESUMED, PAUSING)) {
-                r.mDisplayContent.mAppTransition.overridePendingAppTransition(
-                        packageName, enterAnim, exitAnim, backgroundColor, null, null,
-                        r.mOverrideTaskTransition);
                 r.mTransitionController.setOverrideAnimation(
                         TransitionInfo.AnimationOptions.makeCustomAnimOptions(packageName,
                                 enterAnim, 0 /* changeResId */, exitAnim,
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index d452d76..3cd4db7 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -253,6 +253,7 @@
 import android.app.Activity;
 import android.app.ActivityManager.TaskDescription;
 import android.app.ActivityOptions;
+import android.app.IApplicationThread;
 import android.app.IScreenCaptureObserver;
 import android.app.PendingIntent;
 import android.app.PictureInPictureParams;
@@ -672,9 +673,6 @@
     // TODO(b/317000737): Replace it with visibility states lookup.
     int mTransitionChangeFlags;
 
-    /** Whether we need to setup the animation to animate only within the letterbox. */
-    private boolean mNeedsLetterboxedAnimation;
-
     /**
      * @see #currentLaunchCanTurnScreenOn()
      */
@@ -1351,15 +1349,16 @@
                     this, displayId);
             return;
         }
-        try {
-            ProtoLog.v(WM_DEBUG_SWITCH, "Reporting activity moved to "
-                    + "display, activityRecord=%s, displayId=%d, config=%s", this, displayId,
-                    config);
+        ProtoLog.v(WM_DEBUG_SWITCH, "Reporting activity moved to "
+                        + "display, activityRecord=%s, displayId=%d, config=%s", this, displayId,
+                config);
 
-            final MoveToDisplayItem item =
-                    new MoveToDisplayItem(token, displayId, config, activityWindowInfo);
+        final MoveToDisplayItem item =
+                new MoveToDisplayItem(token, displayId, config, activityWindowInfo);
+        try {
             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(), item);
         } catch (RemoteException e) {
+            // TODO(b/323801078): remove Exception when cleanup
             // If process died, whatever.
         }
     }
@@ -1371,14 +1370,15 @@
                     + "update - client not running, activityRecord=%s", this);
             return;
         }
-        try {
-            ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending new config to %s, "
-                    + "config: %s", this, config);
+        ProtoLog.v(WM_DEBUG_CONFIGURATION, "Sending new config to %s, "
+                + "config: %s", this, config);
 
-            final ActivityConfigurationChangeItem item =
-                    new ActivityConfigurationChangeItem(token, config, activityWindowInfo);
+        final ActivityConfigurationChangeItem item =
+                new ActivityConfigurationChangeItem(token, config, activityWindowInfo);
+        try {
             mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(), item);
         } catch (RemoteException e) {
+            // TODO(b/323801078): remove Exception when cleanup
             // If process died, whatever.
         }
     }
@@ -1393,19 +1393,18 @@
         if (onTop) {
             app.addToPendingTop();
         }
-        try {
-            ProtoLog.v(WM_DEBUG_STATES, "Sending position change to %s, onTop: %b",
-                    this, onTop);
+        ProtoLog.v(WM_DEBUG_STATES, "Sending position change to %s, onTop: %b",
+                this, onTop);
 
-            final TopResumedActivityChangeItem item =
-                    new TopResumedActivityChangeItem(token, onTop);
-            mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(), item);
+        final TopResumedActivityChangeItem item = new TopResumedActivityChangeItem(token, onTop);
+        try {
+            return mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(), item);
         } catch (RemoteException e) {
+            // TODO(b/323801078): remove Exception when cleanup
             // If process died, whatever.
             Slog.w(TAG, "Failed to send top-resumed=" + onTop + " to " + this, e);
             return false;
         }
-        return true;
     }
 
     void updateMultiWindowMode() {
@@ -2604,14 +2603,21 @@
             removeStartingWindow();
             return;
         }
+        mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_ATTACH_TO_CLIENT;
+        final TransferSplashScreenViewStateItem item =
+                new TransferSplashScreenViewStateItem(token, parcelable, windowAnimationLeash);
+        boolean isSuccessful;
         try {
-            mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_ATTACH_TO_CLIENT;
-            final TransferSplashScreenViewStateItem item =
-                    new TransferSplashScreenViewStateItem(token, parcelable, windowAnimationLeash);
-            mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(), item);
-            scheduleTransferSplashScreenTimeout();
-        } catch (Exception e) {
+            isSuccessful = mAtmService.getLifecycleManager().scheduleTransactionItem(
+                    app.getThread(), item);
+        } catch (RemoteException e) {
+            // TODO(b/323801078): remove Exception when cleanup
             Slog.w(TAG, "onCopySplashScreenComplete fail: " + this);
+            isSuccessful = false;
+        }
+        if (isSuccessful) {
+            scheduleTransferSplashScreenTimeout();
+        } else {
             mStartingWindow.cancelAnimation();
             parcelable.clearIfNeeded();
             mTransferringSplashScreenState = TRANSFER_SPLASH_SCREEN_FINISH;
@@ -3957,11 +3963,23 @@
 
             boolean skipDestroy = false;
 
-            try {
-                if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + this);
+            if (DEBUG_SWITCH) Slog.i(TAG_SWITCH, "Destroying: " + this);
+            boolean isSuccessful;
+            final IApplicationThread client = app.getThread();
+            if (client == null) {
+                Slog.w(TAG_WM, "Failed to schedule DestroyActivityItem because client is inactive");
+                isSuccessful = false;
+            } else {
                 final DestroyActivityItem item = new DestroyActivityItem(token, finishing);
-                mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(), item);
-            } catch (Exception e) {
+                try {
+                    isSuccessful = mAtmService.getLifecycleManager().scheduleTransactionItem(
+                            client, item);
+                } catch (RemoteException e) {
+                    // TODO(b/323801078): remove Exception when cleanup
+                    isSuccessful = false;
+                }
+            }
+            if (!isSuccessful) {
                 // We can just ignore exceptions here...  if the process has crashed, our death
                 // notification will clean things up.
                 if (finishing) {
@@ -4884,13 +4902,17 @@
         }
 
         if (isState(RESUMED) && attachedToProcess()) {
+            final ArrayList<ResultInfo> list = new ArrayList<>();
+            list.add(new ResultInfo(resultWho, requestCode, resultCode, data, callerToken));
+            final ActivityResultItem item = new ActivityResultItem(token, list);
             try {
-                final ArrayList<ResultInfo> list = new ArrayList<>();
-                list.add(new ResultInfo(resultWho, requestCode, resultCode, data, callerToken));
-                final ActivityResultItem item = new ActivityResultItem(token, list);
-                mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(), item);
-                return;
-            } catch (Exception e) {
+                final boolean isSuccessful = mAtmService.getLifecycleManager()
+                        .scheduleTransactionItem(app.getThread(), item);
+                if (isSuccessful) {
+                    return;
+                }
+            } catch (RemoteException e) {
+                // TODO(b/323801078): remove Exception when cleanup
                 Slog.w(TAG, "Exception thrown sending result to " + this, e);
             }
         }
@@ -4917,6 +4939,7 @@
                             app.getThread(), activityResultItem);
                 }
             } catch (RemoteException e) {
+                // TODO(b/323801078): remove Exception when cleanup
                 Slog.w(TAG, "Exception thrown sending result to " + this, e);
             }
             // We return here to ensure that result for media projection setup is not stored as a
@@ -4989,7 +5012,6 @@
         }
         final ReferrerIntent rintent = new ReferrerIntent(intent, getFilteredReferrer(referrer),
                 callerToken);
-        boolean unsent = true;
         final boolean isTopActivityWhileSleeping = isSleeping() && isTopRunningActivity();
 
         // We want to immediately deliver the intent to the activity if:
@@ -4998,25 +5020,26 @@
         // - The device is sleeping and it is the top activity behind the lock screen (b/6700897).
         if ((mState == RESUMED || mState == PAUSED || isTopActivityWhileSleeping)
                 && attachedToProcess()) {
+            final ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
+            ar.add(rintent);
+            // Making sure the client state is RESUMED after transaction completed and doing
+            // so only if activity is currently RESUMED. Otherwise, client may have extra
+            // life-cycle calls to RESUMED (and PAUSED later).
+            final NewIntentItem item = new NewIntentItem(token, ar, mState == RESUMED /* resume */);
             try {
-                ArrayList<ReferrerIntent> ar = new ArrayList<>(1);
-                ar.add(rintent);
-                // Making sure the client state is RESUMED after transaction completed and doing
-                // so only if activity is currently RESUMED. Otherwise, client may have extra
-                // life-cycle calls to RESUMED (and PAUSED later).
-                final NewIntentItem item =
-                        new NewIntentItem(token, ar, mState == RESUMED /* resume */);
-                mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(), item);
-                unsent = false;
+                final boolean isSuccessful = mAtmService.getLifecycleManager()
+                        .scheduleTransactionItem(app.getThread(), item);
+                if (isSuccessful) {
+                    return;
+                }
             } catch (RemoteException e) {
-                Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
-            } catch (NullPointerException e) {
+                // TODO(b/323801078): remove Exception when cleanup
                 Slog.w(TAG, "Exception thrown sending new intent to " + this, e);
             }
         }
-        if (unsent) {
-            addNewIntentLocked(rintent);
-        }
+
+        // Didn't send.
+        addNewIntentLocked(rintent);
     }
 
     void updateOptionsLocked(ActivityOptions options) {
@@ -5580,18 +5603,6 @@
         commitVisibility(visible, performLayout, false /* fromTransition */);
     }
 
-    void setNeedsLetterboxedAnimation(boolean needsLetterboxedAnimation) {
-        mNeedsLetterboxedAnimation = needsLetterboxedAnimation;
-    }
-
-    boolean isNeedsLetterboxedAnimation() {
-        return mNeedsLetterboxedAnimation;
-    }
-
-    boolean isInLetterboxAnimation() {
-        return mNeedsLetterboxedAnimation && isAnimating();
-    }
-
     /** Updates draw state and shows drawn windows. */
     void commitFinishDrawing(SurfaceControl.Transaction t) {
         boolean committed = false;
@@ -6044,11 +6055,12 @@
             setState(PAUSING, "makeActiveIfNeeded");
             EventLogTags.writeWmPauseActivity(mUserId, System.identityHashCode(this),
                     shortComponentName, "userLeaving=false", "make-active");
+            final PauseActivityItem item = new PauseActivityItem(token, finishing,
+                    false /* userLeaving */, false /* dontReport */, mAutoEnteringPip);
             try {
-                final PauseActivityItem item = new PauseActivityItem(token, finishing,
-                        false /* userLeaving */, false /* dontReport */, mAutoEnteringPip);
                 mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(), item);
-            } catch (Exception e) {
+            } catch (RemoteException e) {
+                // TODO(b/323801078): remove Exception when cleanup
                 Slog.w(TAG, "Exception thrown sending pause: " + intent.getComponent(), e);
             }
         } else if (shouldStartActivity()) {
@@ -6057,10 +6069,11 @@
             }
             setState(STARTED, "makeActiveIfNeeded");
 
+            final StartActivityItem item = new StartActivityItem(token, takeSceneTransitionInfo());
             try {
-                mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
-                        new StartActivityItem(token, takeSceneTransitionInfo()));
-            } catch (Exception e) {
+                mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(), item);
+            } catch (RemoteException e) {
+                // TODO(b/323801078): remove Exception when cleanup
                 Slog.w(TAG, "Exception thrown sending start: " + intent.getComponent(), e);
             }
             // The activity may be waiting for stop, but that is no longer appropriate if we are
@@ -6343,23 +6356,29 @@
             return;
         }
         resumeKeyDispatchingLocked();
+        ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPING: %s (stop requested)", this);
+
+        setState(STOPPING, "stopIfPossible");
+        if (DEBUG_VISIBILITY) {
+            Slog.v(TAG_VISIBILITY, "Stopping:" + this);
+        }
+        EventLogTags.writeWmStopActivity(
+                mUserId, System.identityHashCode(this), shortComponentName);
+        final StopActivityItem item = new StopActivityItem(token);
+        boolean isSuccessful;
         try {
-            ProtoLog.v(WM_DEBUG_STATES, "Moving to STOPPING: %s (stop requested)", this);
-
-            setState(STOPPING, "stopIfPossible");
-            if (DEBUG_VISIBILITY) {
-                Slog.v(TAG_VISIBILITY, "Stopping:" + this);
-            }
-            EventLogTags.writeWmStopActivity(
-                    mUserId, System.identityHashCode(this), shortComponentName);
-            mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
-                    new StopActivityItem(token));
-
-            mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT);
-        } catch (Exception e) {
+            isSuccessful = mAtmService.getLifecycleManager().scheduleTransactionItem(
+                    app.getThread(), item);
+        } catch (RemoteException e) {
+            // TODO(b/323801078): remove Exception when cleanup
             // Maybe just ignore exceptions here...  if the process has crashed, our death
             // notification will clean things up.
             Slog.w(TAG, "Exception thrown during pause", e);
+            isSuccessful = false;
+        }
+        if (isSuccessful) {
+            mAtmService.mH.postDelayed(mStopTimeoutRunnable, STOP_TIMEOUT);
+        } else {
             // Just in case, assume it to be stopped.
             mAppStopped = true;
             mStoppedTime = SystemClock.uptimeMillis();
@@ -7253,10 +7272,6 @@
                 .setParent(getAnimationLeashParent())
                 .setName(getSurfaceControl() + " - animation-bounds")
                 .setCallsite("ActivityRecord.createAnimationBoundsLayer");
-        if (mNeedsLetterboxedAnimation) {
-            // Needs to be an effect layer to support rounded corners
-            builder.setEffectLayer();
-        }
         final SurfaceControl boundsLayer = builder.build();
         t.show(boundsLayer);
         return boundsLayer;
@@ -7274,11 +7289,6 @@
 
     @Override
     public void onLeashAnimationStarting(Transaction t, SurfaceControl leash) {
-        if (mNeedsLetterboxedAnimation) {
-            updateLetterboxSurfaceIfNeeded(findMainWindow(), t);
-            mNeedsAnimationBoundsLayer = true;
-        }
-
         // If the animation needs to be cropped then an animation bounds layer is created as a
         // child of the root pinned task or animation layer. The leash is then reparented to this
         // new layer.
@@ -7291,17 +7301,6 @@
             t.setLayer(leash, 0);
             t.setLayer(mAnimationBoundsLayer, getLastLayer());
 
-            if (mNeedsLetterboxedAnimation) {
-                final int cornerRadius = mAppCompatController.getLetterboxPolicy()
-                        .getRoundedCornersRadius(findMainWindow());
-
-                final Rect letterboxInnerBounds = new Rect();
-                getLetterboxInnerBounds(letterboxInnerBounds);
-
-                t.setCornerRadius(mAnimationBoundsLayer, cornerRadius)
-                        .setCrop(mAnimationBoundsLayer, letterboxInnerBounds);
-            }
-
             // Reparent leash to animation bounds layer.
             t.reparent(leash, mAnimationBoundsLayer);
         }
@@ -7355,10 +7354,6 @@
         }
 
         mNeedsAnimationBoundsLayer = false;
-        if (mNeedsLetterboxedAnimation) {
-            mNeedsLetterboxedAnimation = false;
-            updateLetterboxSurfaceIfNeeded(findMainWindow(), t);
-        }
     }
 
     @Override
@@ -8711,9 +8706,11 @@
         }
 
         // Figure out how to handle the changes between the configurations.
-        ProtoLog.v(WM_DEBUG_CONFIGURATION, "Checking to restart %s: changed=0x%s, "
-                + "handles=0x%s, mLastReportedConfiguration=%s", info.name,
-                Integer.toHexString(changes), Integer.toHexString(info.getRealConfigChanged()),
+        ProtoLog.v(WM_DEBUG_CONFIGURATION, "Checking to restart %s: changed=%s, "
+                + "handles=%s, not-handles=%s, mLastReportedConfiguration=%s", info.name,
+                Configuration.configurationDiffToString(changes),
+                Configuration.configurationDiffToString(info.getRealConfigChanged()),
+                Configuration.configurationDiffToString(changes & ~(info.getRealConfigChanged())),
                 mLastReportedConfiguration);
 
         if (shouldRelaunchLocked(changes, mTmpConfig)) {
@@ -8926,29 +8923,34 @@
                     task.mTaskId, shortComponentName, Integer.toHexString(configChangeFlags));
         }
 
+        ProtoLog.i(WM_DEBUG_STATES, "Moving to %s Relaunching %s callers=%s" ,
+                (andResume ? "RESUMED" : "PAUSED"), this, Debug.getCallers(6));
+        final ClientTransactionItem callbackItem = new ActivityRelaunchItem(token,
+                pendingResults, pendingNewIntents, configChangeFlags,
+                new MergedConfiguration(getProcessGlobalConfiguration(),
+                        getMergedOverrideConfiguration()),
+                preserveWindow, getActivityWindowInfo());
+        final ActivityLifecycleItem lifecycleItem;
+        if (andResume) {
+            lifecycleItem = new ResumeActivityItem(token, isTransitionForward(),
+                    shouldSendCompatFakeFocus());
+        } else {
+            lifecycleItem = new PauseActivityItem(token);
+        }
+        boolean isSuccessful;
         try {
-            ProtoLog.i(WM_DEBUG_STATES, "Moving to %s Relaunching %s callers=%s" ,
-                    (andResume ? "RESUMED" : "PAUSED"), this, Debug.getCallers(6));
-            final ClientTransactionItem callbackItem = new ActivityRelaunchItem(token,
-                    pendingResults, pendingNewIntents, configChangeFlags,
-                    new MergedConfiguration(getProcessGlobalConfiguration(),
-                            getMergedOverrideConfiguration()),
-                    preserveWindow, getActivityWindowInfo());
-            final ActivityLifecycleItem lifecycleItem;
-            if (andResume) {
-                lifecycleItem = new ResumeActivityItem(token, isTransitionForward(),
-                        shouldSendCompatFakeFocus());
-            } else {
-                lifecycleItem = new PauseActivityItem(token);
-            }
-            mAtmService.getLifecycleManager().scheduleTransactionItems(
+            isSuccessful = mAtmService.getLifecycleManager().scheduleTransactionItems(
                     app.getThread(), callbackItem, lifecycleItem);
+        } catch (RemoteException e) {
+            // TODO(b/323801078): remove Exception when cleanup
+            Slog.w(TAG, "Failed to relaunch " + this + ": " + e);
+            isSuccessful = false;
+        }
+        if (isSuccessful) {
             startRelaunching();
             // Note: don't need to call pauseIfSleepingLocked() here, because the caller will only
             // request resume if this activity is currently resumed, which implies we aren't
             // sleeping.
-        } catch (RemoteException e) {
-            Slog.w(TAG, "Failed to relaunch " + this + ": " + e);
         }
 
         if (andResume) {
@@ -9028,10 +9030,11 @@
     private void scheduleStopForRestartProcess() {
         // The process will be killed until the activity reports stopped with saved state (see
         // {@link ActivityTaskManagerService.activityStopped}).
+        final StopActivityItem item = new StopActivityItem(token);
         try {
-            mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(),
-                    new StopActivityItem(token));
+            mAtmService.getLifecycleManager().scheduleTransactionItem(app.getThread(), item);
         } catch (RemoteException e) {
+            // TODO(b/323801078): remove Exception when cleanup
             Slog.w(TAG, "Exception thrown during restart " + this, e);
         }
         mTaskSupervisor.scheduleRestartTimeout(this);
diff --git a/services/core/java/com/android/server/wm/ActivityRefresher.java b/services/core/java/com/android/server/wm/ActivityRefresher.java
index 25e38b3..8fe603c 100644
--- a/services/core/java/com/android/server/wm/ActivityRefresher.java
+++ b/services/core/java/com/android/server/wm/ActivityRefresher.java
@@ -88,17 +88,22 @@
                 new RefreshCallbackItem(activity.token, cycleThroughStop ? ON_STOP : ON_PAUSE);
         final ResumeActivityItem resumeActivityItem = new ResumeActivityItem(
                 activity.token, /* isForward */ false, /* shouldSendCompatFakeFocus */ false);
+        boolean isSuccessful;
         try {
-            activity.mAtmService.getLifecycleManager().scheduleTransactionItems(
+            isSuccessful = activity.mAtmService.getLifecycleManager().scheduleTransactionItems(
                     activity.app.getThread(), refreshCallbackItem, resumeActivityItem);
+        } catch (RemoteException e) {
+            isSuccessful = false;
+        }
+        if (isSuccessful) {
             mHandler.postDelayed(() -> {
                 synchronized (mWmService.mGlobalLock) {
                     onActivityRefreshed(activity);
                 }
             }, REFRESH_CALLBACK_TIMEOUT_MS);
-        } catch (RemoteException e) {
-            activity.mAppCompatController.getCameraOverrides()
-                    .setIsRefreshRequested(false);
+        } else {
+            activity.mAppCompatController.getCameraOverrides().setIsRefreshRequested(false);
+
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java
index bdde5fe..233f913 100644
--- a/services/core/java/com/android/server/wm/ActivityStarter.java
+++ b/services/core/java/com/android/server/wm/ActivityStarter.java
@@ -59,9 +59,7 @@
 import static android.security.Flags.preventIntentRedirectShowToast;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.WindowManager.TRANSIT_FLAG_AVOID_MOVE_TO_FRONT;
-import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.window.TaskFragmentOperation.OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT;
 
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_CONFIGURATION;
@@ -1992,6 +1990,11 @@
             }
         }
 
+        if (com.android.window.flags.Flags.earlyLaunchHint()) {
+            mRootWindowContainer.startPowerModeLaunchIfNeeded(
+                    false /* forceSend */, mStartActivity);
+        }
+
         if (mTargetRootTask == null) {
             mTargetRootTask = getOrCreateRootTask(mStartActivity, mLaunchFlags, targetTask,
                     mOptions);
@@ -2064,8 +2067,10 @@
 
         mStartActivity.getTaskFragment().clearLastPausedActivity();
 
-        mRootWindowContainer.startPowerModeLaunchIfNeeded(
-                false /* forceSend */, mStartActivity);
+        if (!com.android.window.flags.Flags.earlyLaunchHint()) {
+            mRootWindowContainer.startPowerModeLaunchIfNeeded(
+                    false /* forceSend */, mStartActivity);
+        }
 
         final boolean isTaskSwitch = startedTask != prevTopTask;
         mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,
@@ -2551,11 +2556,6 @@
                 if (actuallyMoved) {
                     // Only record if the activity actually moved.
                     mMovedToTopActivity = act;
-                    if (mNoAnimation) {
-                        act.mDisplayContent.prepareAppTransition(TRANSIT_NONE);
-                    } else {
-                        act.mDisplayContent.prepareAppTransition(TRANSIT_TO_FRONT);
-                    }
                 }
                 act.updateOptionsLocked(mOptions);
                 deliverNewIntent(act, intentGrants);
diff --git a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
index c45f7e8..a7f2153 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskSupervisor.java
@@ -125,6 +125,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
+import android.os.DeadObjectException;
 import android.os.Debug;
 import android.os.Handler;
 import android.os.IBinder;
@@ -1045,16 +1046,23 @@
             // transaction.
             mService.getLifecycleManager().dispatchPendingTransaction(proc.getThread());
         }
+        final boolean isSuccessful;
         try {
-            mService.getLifecycleManager().scheduleTransactionItems(
+            isSuccessful = mService.getLifecycleManager().scheduleTransactionItems(
                     proc.getThread(),
                     // Immediately dispatch the transaction, so that if it fails, the server can
                     // restart the process and retry now.
                     true /* shouldDispatchImmediately */,
                     launchActivityItem, lifecycleItem);
         } catch (RemoteException e) {
+            // TODO(b/323801078): remove Exception when cleanup
             return e;
         }
+        if (com.android.window.flags.Flags.cleanupDispatchPendingTransactionsRemoteException()
+                && !isSuccessful) {
+            return new DeadObjectException("Failed to dispatch the ClientTransaction to dead"
+                    + " process. See earlier log for more details.");
+        }
 
         if (procConfig.seq > mRootWindowContainer.getConfiguration().seq) {
             // If the seq is increased, there should be something changed (e.g. registered
diff --git a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java
index 6873270..27511b2 100644
--- a/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatLetterboxPolicy.java
@@ -217,7 +217,7 @@
         }
 
         final boolean shouldShowLetterboxUi =
-                (mActivityRecord.isInLetterboxAnimation() || mActivityRecord.isVisible()
+                (mActivityRecord.isVisible()
                         || mActivityRecord.isVisibleRequested())
                         && mainWindow.areAppWindowBoundsLetterboxed()
                         // Check for FLAG_SHOW_WALLPAPER explicitly instead of using
@@ -360,8 +360,7 @@
                         .mAppCompatController.getReachabilityPolicy();
                 mLetterbox = new Letterbox(() -> mActivityRecord.makeChildSurface(null),
                         mActivityRecord.mWmService.mTransactionFactory,
-                        reachabilityPolicy, letterboxOverrides,
-                        this::getLetterboxParentSurface);
+                        reachabilityPolicy, letterboxOverrides);
                 mActivityRecord.mAppCompatController.getReachabilityPolicy()
                         .setLetterboxInnerBoundsSupplier(mLetterbox::getInnerFrame);
             }
@@ -469,15 +468,6 @@
         public boolean isFullyTransparentBarAllowed(@NonNull Rect rect) {
             return !isRunning() || mLetterbox.notIntersectsOrFullyContains(rect);
         }
-
-        @Nullable
-        private SurfaceControl getLetterboxParentSurface() {
-            if (mActivityRecord.isInLetterboxAnimation()) {
-                return mActivityRecord.getTask().getSurfaceControl();
-            }
-            return mActivityRecord.getSurfaceControl();
-        }
-
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/AppCompatLetterboxUtils.java b/services/core/java/com/android/server/wm/AppCompatLetterboxUtils.java
index 83d7cb7..e5b61db 100644
--- a/services/core/java/com/android/server/wm/AppCompatLetterboxUtils.java
+++ b/services/core/java/com/android/server/wm/AppCompatLetterboxUtils.java
@@ -36,12 +36,7 @@
             outLetterboxPosition.set(0, 0);
             return;
         }
-        if (activity.isInLetterboxAnimation()) {
-            // In this case we attach the letterbox to the task instead of the activity.
-            activity.getTask().getPosition(outLetterboxPosition);
-        } else {
-            activity.getPosition(outLetterboxPosition);
-        }
+        activity.getPosition(outLetterboxPosition);
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java b/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java
index 8165638..92b91464 100644
--- a/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java
+++ b/services/core/java/com/android/server/wm/AppCompatRoundedCorners.java
@@ -58,7 +58,7 @@
     @VisibleForTesting
     @Nullable
     Rect getCropBoundsIfNeeded(@NonNull final WindowState mainWindow) {
-        if (!requiresRoundedCorners(mainWindow) || mActivityRecord.isInLetterboxAnimation()) {
+        if (!requiresRoundedCorners(mainWindow)) {
             // We don't want corner radius on the window.
             // In the case the ActivityRecord requires a letterboxed animation we never want
             // rounded corners on the window because rounded corners are applied at the
diff --git a/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java b/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java
index 2cfa242..b03aa52 100644
--- a/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java
+++ b/services/core/java/com/android/server/wm/AppCompatSizeCompatModePolicy.java
@@ -23,6 +23,7 @@
 import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
 import static android.content.res.Configuration.ORIENTATION_UNDEFINED;
 
+import static com.android.window.flags.Flags.enableSizeCompatModeImprovementsForConnectedDisplays;
 import static com.android.server.wm.AppCompatUtils.isInDesktopMode;
 
 import android.annotation.NonNull;
@@ -357,6 +358,11 @@
         // relatively fixed.
         overrideConfig.colorMode = fullConfig.colorMode;
         overrideConfig.densityDpi = fullConfig.densityDpi;
+        if (enableSizeCompatModeImprovementsForConnectedDisplays()) {
+            overrideConfig.touchscreen = fullConfig.touchscreen;
+            overrideConfig.navigation = fullConfig.navigation;
+            overrideConfig.fontScale = fullConfig.fontScale;
+        }
         // The smallest screen width is the short side of screen bounds. Because the bounds
         // and density won't be changed, smallestScreenWidthDp is also fixed.
         overrideConfig.smallestScreenWidthDp = fullConfig.smallestScreenWidthDp;
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
deleted file mode 100644
index 12d4a21..0000000
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ /dev/null
@@ -1,1587 +0,0 @@
-/*
- * Copyright (C) 2011 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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;
-
-import static android.view.WindowManager.LayoutParams;
-import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_CLOSE;
-import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_FLAG_OPEN_BEHIND;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
-import static android.view.WindowManager.TRANSIT_NONE;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_ACTIVITY_RELAUNCH;
-import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_DREAM_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
-import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
-import static android.view.WindowManager.TRANSIT_OLD_NONE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_BACK;
-import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_FRONT;
-import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_UNSET;
-import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_CLOSE;
-import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_INTRA_OPEN;
-import static android.view.WindowManager.TRANSIT_OLD_WALLPAPER_OPEN;
-import static android.view.WindowManager.TRANSIT_OPEN;
-import static android.view.WindowManager.TRANSIT_RELAUNCH;
-import static android.view.WindowManager.TRANSIT_TO_BACK;
-import static android.view.WindowManager.TRANSIT_TO_FRONT;
-
-import static com.android.internal.R.styleable.WindowAnimation_activityCloseEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_activityCloseExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_activityOpenEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_activityOpenExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_dreamActivityCloseExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_dreamActivityOpenEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_dreamActivityOpenExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindSourceAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_launchTaskBehindTargetAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskCloseEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskCloseExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskOpenEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskOpenExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskToBackEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskToBackExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskToFrontEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_taskToFrontExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperCloseExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraCloseExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperIntraOpenExitAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenEnterAnimation;
-import static com.android.internal.R.styleable.WindowAnimation_wallpaperOpenExitAnimation;
-import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM;
-import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_APP_TRANSITIONS_ANIM;
-import static com.android.server.wm.AppTransitionProto.APP_TRANSITION_STATE;
-import static com.android.server.wm.AppTransitionProto.LAST_USED_APP_TRANSITION;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
-import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
-import static com.android.server.wm.WindowManagerInternal.AppTransitionListener;
-import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_AFTER_ANIM;
-import static com.android.server.wm.WindowStateAnimator.ROOT_TASK_CLIP_NONE;
-
-import android.annotation.ColorInt;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.graphics.drawable.Drawable;
-import android.hardware.HardwareBuffer;
-import android.os.Binder;
-import android.os.Debug;
-import android.os.Handler;
-import android.os.IBinder;
-import android.os.IRemoteCallback;
-import android.os.RemoteException;
-import android.os.SystemClock;
-import android.os.UserHandle;
-import android.util.Pair;
-import android.util.Slog;
-import android.util.SparseArray;
-import android.util.proto.ProtoOutputStream;
-import android.view.AppTransitionAnimationSpec;
-import android.view.IAppTransitionAnimationSpecsFuture;
-import android.view.RemoteAnimationAdapter;
-import android.view.WindowManager.TransitionFlags;
-import android.view.WindowManager.TransitionOldType;
-import android.view.WindowManager.TransitionType;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.ScaleAnimation;
-import android.view.animation.TranslateAnimation;
-
-import com.android.internal.annotations.VisibleForTesting;
-import com.android.internal.policy.TransitionAnimation;
-import com.android.internal.protolog.ProtoLog;
-import com.android.internal.protolog.common.LogLevel;
-import com.android.internal.util.DumpUtils.Dump;
-import com.android.internal.util.function.pooled.PooledLambda;
-import com.android.internal.util.function.pooled.PooledPredicate;
-import com.android.server.wm.ActivityRecord.CustomAppTransition;
-
-import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
-
-// State management of app transitions.  When we are preparing for a
-// transition, mNextAppTransition will be the kind of transition to
-// perform or TRANSIT_NONE if we are not waiting.  If we are waiting,
-// mOpeningApps and mClosingApps are the lists of tokens that will be
-// made visible or hidden at the next transition.
-public class AppTransition implements Dump {
-    private static final String TAG = TAG_WITH_CLASS_NAME ? "AppTransition" : TAG_WM;
-
-    static final int DEFAULT_APP_TRANSITION_DURATION = 336;
-
-    /**
-     * Maximum duration for the clip reveal animation. This is used when there is a lot of movement
-     * involved, to make it more understandable.
-     */
-    private static final long APP_TRANSITION_TIMEOUT_MS = 5000;
-    static final int MAX_APP_TRANSITION_DURATION = 3 * 1000; // 3 secs.
-
-    private final Context mContext;
-    private final WindowManagerService mService;
-    private final DisplayContent mDisplayContent;
-
-    @VisibleForTesting
-    final TransitionAnimation mTransitionAnimation;
-
-    private @TransitionFlags int mNextAppTransitionFlags = 0;
-    private final ArrayList<Integer> mNextAppTransitionRequests = new ArrayList<>();
-    private @TransitionOldType int mLastUsedAppTransition = TRANSIT_OLD_UNSET;
-    private String mLastOpeningApp;
-    private String mLastClosingApp;
-    private String mLastChangingApp;
-
-    private static final int NEXT_TRANSIT_TYPE_NONE = 0;
-    private static final int NEXT_TRANSIT_TYPE_CUSTOM = 1;
-    private static final int NEXT_TRANSIT_TYPE_SCALE_UP = 2;
-    private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP = 3;
-    private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN = 4;
-    private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP = 5;
-    private static final int NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN = 6;
-    private static final int NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE = 7;
-    private static final int NEXT_TRANSIT_TYPE_CLIP_REVEAL = 8;
-
-    /**
-     * Refers to the transition to activity started by using {@link
-     * android.content.pm.crossprofile.CrossProfileApps#startMainActivity(ComponentName, UserHandle)
-     * }.
-     */
-    private static final int NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS = 9;
-    private static final int NEXT_TRANSIT_TYPE_REMOTE = 10;
-
-    private int mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
-    private boolean mNextAppTransitionOverrideRequested;
-
-    private String mNextAppTransitionPackage;
-    // Used for thumbnail transitions. True if we're scaling up, false if scaling down
-    private boolean mNextAppTransitionScaleUp;
-    private IRemoteCallback mNextAppTransitionCallback;
-    private IRemoteCallback mNextAppTransitionFutureCallback;
-    private IRemoteCallback mAnimationFinishedCallback;
-    private int mNextAppTransitionEnter;
-    private int mNextAppTransitionExit;
-    private @ColorInt int mNextAppTransitionBackgroundColor;
-    private int mNextAppTransitionInPlace;
-    private boolean mNextAppTransitionIsSync;
-
-    // Keyed by WindowContainer hashCode.
-    private final SparseArray<AppTransitionAnimationSpec> mNextAppTransitionAnimationsSpecs
-            = new SparseArray<>();
-    private IAppTransitionAnimationSpecsFuture mNextAppTransitionAnimationsSpecsFuture;
-    private boolean mNextAppTransitionAnimationsSpecsPending;
-    private AppTransitionAnimationSpec mDefaultNextAppTransitionAnimationSpec;
-
-    private final Rect mTmpRect = new Rect();
-
-    private final static int APP_STATE_IDLE = 0;
-    private final static int APP_STATE_READY = 1;
-    private final static int APP_STATE_RUNNING = 2;
-    private final static int APP_STATE_TIMEOUT = 3;
-    private int mAppTransitionState = APP_STATE_IDLE;
-
-    private final ArrayList<AppTransitionListener> mListeners = new ArrayList<>();
-    private final ExecutorService mDefaultExecutor = Executors.newSingleThreadExecutor();
-
-    private final int mDefaultWindowAnimationStyleResId;
-    private boolean mOverrideTaskTransition;
-
-    final Handler mHandler;
-    final Runnable mHandleAppTransitionTimeoutRunnable = () -> handleAppTransitionTimeout();
-
-    AppTransition(Context context, WindowManagerService service, DisplayContent displayContent) {
-        mContext = context;
-        mService = service;
-        mHandler = new Handler(service.mH.getLooper());
-        mDisplayContent = displayContent;
-        mTransitionAnimation = new TransitionAnimation(
-                context, ProtoLog.isEnabled(WM_DEBUG_ANIM, LogLevel.DEBUG), TAG);
-
-        final TypedArray windowStyle = mContext.getTheme().obtainStyledAttributes(
-                com.android.internal.R.styleable.Window);
-        mDefaultWindowAnimationStyleResId = windowStyle.getResourceId(
-                com.android.internal.R.styleable.Window_windowAnimationStyle, 0);
-        windowStyle.recycle();
-    }
-
-    boolean isTransitionSet() {
-        return !mNextAppTransitionRequests.isEmpty();
-    }
-
-    boolean isUnoccluding() {
-        return mNextAppTransitionRequests.contains(TRANSIT_KEYGUARD_UNOCCLUDE);
-    }
-
-    boolean transferFrom(AppTransition other) {
-        mNextAppTransitionRequests.addAll(other.mNextAppTransitionRequests);
-        return prepare();
-    }
-
-    void setLastAppTransition(@TransitionOldType int transit, ActivityRecord openingApp,
-            ActivityRecord closingApp, ActivityRecord changingApp) {
-        mLastUsedAppTransition = transit;
-        mLastOpeningApp = "" + openingApp;
-        mLastClosingApp = "" + closingApp;
-        mLastChangingApp = "" + changingApp;
-    }
-
-    boolean isReady() {
-        return mAppTransitionState == APP_STATE_READY
-                || mAppTransitionState == APP_STATE_TIMEOUT;
-    }
-
-    void setReady() {
-        setAppTransitionState(APP_STATE_READY);
-        fetchAppTransitionSpecsFromFuture();
-    }
-
-    boolean isRunning() {
-        return mAppTransitionState == APP_STATE_RUNNING;
-    }
-
-    void setIdle() {
-        setAppTransitionState(APP_STATE_IDLE);
-    }
-
-    boolean isIdle() {
-        return mAppTransitionState == APP_STATE_IDLE;
-    }
-
-    boolean isTimeout() {
-        return mAppTransitionState == APP_STATE_TIMEOUT;
-    }
-
-    void setTimeout() {
-        setAppTransitionState(APP_STATE_TIMEOUT);
-    }
-
-    /**
-     * Gets the animation overridden by app via {@link #overridePendingAppTransition}.
-     */
-    @Nullable
-    Animation getNextAppRequestedAnimation(boolean enter) {
-        final Animation a = mTransitionAnimation.loadAppTransitionAnimation(
-                mNextAppTransitionPackage,
-                enter ? mNextAppTransitionEnter : mNextAppTransitionExit);
-        if (mNextAppTransitionBackgroundColor != 0 && a != null) {
-            a.setBackdropColor(mNextAppTransitionBackgroundColor);
-        }
-        return a;
-    }
-
-    /**
-     * Gets the animation background color overridden by app via
-     * {@link #overridePendingAppTransition}.
-     */
-    @ColorInt int getNextAppTransitionBackgroundColor() {
-        return mNextAppTransitionBackgroundColor;
-    }
-
-    @VisibleForTesting
-    boolean isNextAppTransitionOverrideRequested() {
-        return mNextAppTransitionOverrideRequested;
-    }
-
-    HardwareBuffer getAppTransitionThumbnailHeader(WindowContainer container) {
-        AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
-                container.hashCode());
-        if (spec == null) {
-            spec = mDefaultNextAppTransitionAnimationSpec;
-        }
-        return spec != null ? spec.buffer : null;
-    }
-
-    /** Returns whether the next thumbnail transition is aspect scaled up. */
-    boolean isNextThumbnailTransitionAspectScaled() {
-        return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
-                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
-    }
-
-    /** Returns whether the next thumbnail transition is scaling up. */
-    boolean isNextThumbnailTransitionScaleUp() {
-        return mNextAppTransitionScaleUp;
-    }
-
-    boolean isNextAppTransitionThumbnailUp() {
-        return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
-                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP;
-    }
-
-    boolean isNextAppTransitionThumbnailDown() {
-        return mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN ||
-                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
-    }
-
-    boolean isNextAppTransitionOpenCrossProfileApps() {
-        return mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
-    }
-
-    /**
-     * @return true if and only if we are currently fetching app transition specs from the future
-     *         passed into {@link #overridePendingAppTransitionMultiThumbFuture}
-     */
-    boolean isFetchingAppTransitionsSpecs() {
-        return mNextAppTransitionAnimationsSpecsPending;
-    }
-
-    private boolean prepare() {
-        if (!isRunning()) {
-            setAppTransitionState(APP_STATE_IDLE);
-            notifyAppTransitionPendingLocked();
-            return true;
-        }
-        return false;
-    }
-
-    /**
-     * @return bit-map of WindowManagerPolicy#FINISH_LAYOUT_REDO_* to indicate whether another
-     *         layout pass needs to be done
-     */
-    int goodToGo(@TransitionOldType int transit, ActivityRecord topOpeningApp) {
-        mNextAppTransitionFlags = 0;
-        mNextAppTransitionRequests.clear();
-        setAppTransitionState(APP_STATE_RUNNING);
-        final WindowContainer wc =
-                topOpeningApp != null ? topOpeningApp.getAnimatingContainer() : null;
-        final AnimationAdapter topOpeningAnim = wc != null ? wc.getAnimation() : null;
-
-        int redoLayout = notifyAppTransitionStartingLocked(
-                topOpeningAnim != null
-                        ? topOpeningAnim.getStatusBarTransitionsStartTime()
-                        : SystemClock.uptimeMillis(),
-                AnimationAdapter.STATUS_BAR_TRANSITION_DURATION);
-
-        if ((isTaskOpenTransitOld(transit) || transit == TRANSIT_OLD_WALLPAPER_CLOSE)
-                && topOpeningAnim != null) {
-            if (mDisplayContent.getDisplayPolicy().shouldAttachNavBarToAppDuringTransition()) {
-                final NavBarFadeAnimationController controller =
-                        new NavBarFadeAnimationController(mDisplayContent);
-                // For remote animation case, the nav bar fades out and in is controlled by the
-                // remote side. For non-remote animation case, we play the fade out/in animation
-                // here. We play the nav bar fade-out animation when the app transition animation
-                // starts and play the fade-in animation sequentially once the fade-out is finished.
-                controller.fadeOutAndInSequentially(topOpeningAnim.getDurationHint(),
-                        null /* fadeOutParent */, topOpeningApp.getSurfaceControl());
-            }
-        }
-        return redoLayout;
-    }
-
-    void clear() {
-        clear(true /* clearAppOverride */);
-    }
-
-    private void clear(boolean clearAppOverride) {
-        mNextAppTransitionType = NEXT_TRANSIT_TYPE_NONE;
-        mNextAppTransitionOverrideRequested = false;
-        mNextAppTransitionAnimationsSpecs.clear();
-        mNextAppTransitionAnimationsSpecsFuture = null;
-        mDefaultNextAppTransitionAnimationSpec = null;
-        mAnimationFinishedCallback = null;
-        mOverrideTaskTransition = false;
-        mNextAppTransitionIsSync = false;
-        if (clearAppOverride) {
-            mNextAppTransitionPackage = null;
-            mNextAppTransitionEnter = 0;
-            mNextAppTransitionExit = 0;
-            mNextAppTransitionBackgroundColor = 0;
-        }
-    }
-
-    void freeze() {
-        final boolean keyguardGoingAwayCancelled = mNextAppTransitionRequests.contains(
-                TRANSIT_KEYGUARD_GOING_AWAY);
-
-        mNextAppTransitionRequests.clear();
-        clear();
-        setReady();
-        notifyAppTransitionCancelledLocked(keyguardGoingAwayCancelled);
-    }
-
-    private void setAppTransitionState(int state) {
-        mAppTransitionState = state;
-        updateBooster();
-    }
-
-    /**
-     * Updates whether we currently boost wm locked sections and the animation thread. We want to
-     * boost the priorities to a more important value whenever an app transition is going to happen
-     * soon or an app transition is running.
-     */
-    void updateBooster() {
-        WindowManagerService.sThreadPriorityBooster.setAppTransitionRunning(needsBoosting());
-    }
-
-    private boolean needsBoosting() {
-        return !mNextAppTransitionRequests.isEmpty()
-                || mAppTransitionState == APP_STATE_READY
-                || mAppTransitionState == APP_STATE_RUNNING;
-    }
-
-    void registerListenerLocked(AppTransitionListener listener) {
-        mListeners.add(listener);
-    }
-
-    void unregisterListener(AppTransitionListener listener) {
-        mListeners.remove(listener);
-    }
-
-    public void notifyAppTransitionFinishedLocked(IBinder token) {
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onAppTransitionFinishedLocked(token);
-        }
-    }
-
-    private void notifyAppTransitionPendingLocked() {
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onAppTransitionPendingLocked();
-        }
-    }
-
-    private void notifyAppTransitionCancelledLocked(boolean keyguardGoingAwayCancelled) {
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onAppTransitionCancelledLocked(keyguardGoingAwayCancelled);
-        }
-    }
-
-    private void notifyAppTransitionTimeoutLocked() {
-        for (int i = 0; i < mListeners.size(); i++) {
-            mListeners.get(i).onAppTransitionTimeoutLocked();
-        }
-    }
-
-    private int notifyAppTransitionStartingLocked(long statusBarAnimationStartTime,
-            long statusBarAnimationDuration) {
-        int redoLayout = 0;
-        for (int i = 0; i < mListeners.size(); i++) {
-            redoLayout |= mListeners.get(i).onAppTransitionStartingLocked(
-                    statusBarAnimationStartTime, statusBarAnimationDuration);
-        }
-        return redoLayout;
-    }
-
-    @VisibleForTesting
-    int getDefaultWindowAnimationStyleResId() {
-        return mDefaultWindowAnimationStyleResId;
-    }
-
-    /** Returns window animation style ID from {@link LayoutParams} or from system in some cases */
-    @VisibleForTesting
-    int getAnimationStyleResId(@NonNull LayoutParams lp) {
-        return mTransitionAnimation.getAnimationStyleResId(lp);
-    }
-
-    @VisibleForTesting
-    @Nullable
-    Animation loadAnimationSafely(Context context, int resId) {
-        return TransitionAnimation.loadAnimationSafely(context, resId, TAG);
-    }
-
-    private static int mapOpenCloseTransitTypes(int transit, boolean enter) {
-        int animAttr = 0;
-        switch (transit) {
-            case TRANSIT_OLD_ACTIVITY_OPEN:
-            case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN:
-                animAttr = enter
-                        ? WindowAnimation_activityOpenEnterAnimation
-                        : WindowAnimation_activityOpenExitAnimation;
-                break;
-            case TRANSIT_OLD_ACTIVITY_CLOSE:
-            case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE:
-                animAttr = enter
-                        ? WindowAnimation_activityCloseEnterAnimation
-                        : WindowAnimation_activityCloseExitAnimation;
-                break;
-            case TRANSIT_OLD_TASK_OPEN:
-                animAttr = enter
-                        ? WindowAnimation_taskOpenEnterAnimation
-                        : WindowAnimation_taskOpenExitAnimation;
-                break;
-            case TRANSIT_OLD_TASK_CLOSE:
-                animAttr = enter
-                        ? WindowAnimation_taskCloseEnterAnimation
-                        : WindowAnimation_taskCloseExitAnimation;
-                break;
-            case TRANSIT_OLD_TASK_TO_FRONT:
-                animAttr = enter
-                        ? WindowAnimation_taskToFrontEnterAnimation
-                        : WindowAnimation_taskToFrontExitAnimation;
-                break;
-            case TRANSIT_OLD_TASK_TO_BACK:
-                animAttr = enter
-                        ? WindowAnimation_taskToBackEnterAnimation
-                        : WindowAnimation_taskToBackExitAnimation;
-                break;
-            case TRANSIT_OLD_WALLPAPER_OPEN:
-                animAttr = enter
-                        ? WindowAnimation_wallpaperOpenEnterAnimation
-                        : WindowAnimation_wallpaperOpenExitAnimation;
-                break;
-            case TRANSIT_OLD_WALLPAPER_CLOSE:
-                animAttr = enter
-                        ? WindowAnimation_wallpaperCloseEnterAnimation
-                        : WindowAnimation_wallpaperCloseExitAnimation;
-                break;
-            case TRANSIT_OLD_WALLPAPER_INTRA_OPEN:
-                animAttr = enter
-                        ? WindowAnimation_wallpaperIntraOpenEnterAnimation
-                        : WindowAnimation_wallpaperIntraOpenExitAnimation;
-                break;
-            case TRANSIT_OLD_WALLPAPER_INTRA_CLOSE:
-                animAttr = enter
-                        ? WindowAnimation_wallpaperIntraCloseEnterAnimation
-                        : WindowAnimation_wallpaperIntraCloseExitAnimation;
-                break;
-            case TRANSIT_OLD_TASK_OPEN_BEHIND:
-                animAttr = enter
-                        ? WindowAnimation_launchTaskBehindSourceAnimation
-                        : WindowAnimation_launchTaskBehindTargetAnimation;
-                break;
-            // TODO(b/189386466): Use activity transition as the fallback. Investigate if we
-            //  need new TaskFragment transition.
-            case TRANSIT_OLD_TASK_FRAGMENT_OPEN:
-                animAttr = enter
-                        ? WindowAnimation_activityOpenEnterAnimation
-                        : WindowAnimation_activityOpenExitAnimation;
-                break;
-            // TODO(b/189386466): Use activity transition as the fallback. Investigate if we
-            //  need new TaskFragment transition.
-            case TRANSIT_OLD_TASK_FRAGMENT_CLOSE:
-                animAttr = enter
-                        ? WindowAnimation_activityCloseEnterAnimation
-                        : WindowAnimation_activityCloseExitAnimation;
-                break;
-            case TRANSIT_OLD_DREAM_ACTIVITY_OPEN:
-                animAttr = enter
-                        ? WindowAnimation_dreamActivityOpenEnterAnimation
-                        : WindowAnimation_dreamActivityOpenExitAnimation;
-                break;
-            case TRANSIT_OLD_DREAM_ACTIVITY_CLOSE:
-                animAttr = enter
-                        ? 0
-                        : WindowAnimation_dreamActivityCloseExitAnimation;
-                break;
-        }
-
-        return animAttr;
-    }
-
-    @Nullable
-    Animation loadAnimationAttr(LayoutParams lp, int animAttr, int transit) {
-        return mTransitionAnimation.loadAnimationAttr(lp, animAttr, transit);
-    }
-
-    private void getDefaultNextAppTransitionStartRect(Rect rect) {
-        if (mDefaultNextAppTransitionAnimationSpec == null ||
-                mDefaultNextAppTransitionAnimationSpec.rect == null) {
-            Slog.e(TAG, "Starting rect for app requested, but none available", new Throwable());
-            rect.setEmpty();
-        } else {
-            rect.set(mDefaultNextAppTransitionAnimationSpec.rect);
-        }
-    }
-
-    private void putDefaultNextAppTransitionCoordinates(int left, int top, int width, int height,
-            HardwareBuffer buffer) {
-        mDefaultNextAppTransitionAnimationSpec = new AppTransitionAnimationSpec(-1 /* taskId */,
-                buffer, new Rect(left, top, left + width, top + height));
-    }
-
-    /**
-     * Creates an overlay with a background color and a thumbnail for the cross profile apps
-     * animation.
-     */
-    HardwareBuffer createCrossProfileAppsThumbnail(
-            Drawable thumbnailDrawable, Rect frame) {
-        return mTransitionAnimation.createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
-    }
-
-    Animation createCrossProfileAppsThumbnailAnimationLocked(Rect appRect) {
-        return mTransitionAnimation.createCrossProfileAppsThumbnailAnimationLocked(appRect);
-    }
-
-    /**
-     * This animation runs for the thumbnail that gets cross faded with the enter/exit activity
-     * when a thumbnail is specified with the pending animation override.
-     */
-    Animation createThumbnailAspectScaleAnimationLocked(Rect appRect, @Nullable Rect contentInsets,
-            HardwareBuffer thumbnailHeader, WindowContainer container, int orientation) {
-        AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
-                container.hashCode());
-        return mTransitionAnimation.createThumbnailAspectScaleAnimationLocked(appRect,
-                contentInsets, thumbnailHeader, orientation, spec != null ? spec.rect : null,
-                mDefaultNextAppTransitionAnimationSpec != null
-                        ? mDefaultNextAppTransitionAnimationSpec.rect : null,
-                mNextAppTransitionScaleUp);
-    }
-
-    private AnimationSet createAspectScaledThumbnailFreeformAnimationLocked(Rect sourceFrame,
-            Rect destFrame, @Nullable Rect surfaceInsets, boolean enter) {
-        final float sourceWidth = sourceFrame.width();
-        final float sourceHeight = sourceFrame.height();
-        final float destWidth = destFrame.width();
-        final float destHeight = destFrame.height();
-        final float scaleH = enter ? sourceWidth / destWidth : destWidth / sourceWidth;
-        final float scaleV = enter ? sourceHeight / destHeight : destHeight / sourceHeight;
-        AnimationSet set = new AnimationSet(true);
-        final int surfaceInsetsH = surfaceInsets == null
-                ? 0 : surfaceInsets.left + surfaceInsets.right;
-        final int surfaceInsetsV = surfaceInsets == null
-                ? 0 : surfaceInsets.top + surfaceInsets.bottom;
-        // We want the scaling to happen from the center of the surface. In order to achieve that,
-        // we need to account for surface insets that will be used to enlarge the surface.
-        final float scaleHCenter = ((enter ? destWidth : sourceWidth) + surfaceInsetsH) / 2;
-        final float scaleVCenter = ((enter ? destHeight : sourceHeight) + surfaceInsetsV) / 2;
-        final ScaleAnimation scale = enter ?
-                new ScaleAnimation(scaleH, 1, scaleV, 1, scaleHCenter, scaleVCenter)
-                : new ScaleAnimation(1, scaleH, 1, scaleV, scaleHCenter, scaleVCenter);
-        final int sourceHCenter = sourceFrame.left + sourceFrame.width() / 2;
-        final int sourceVCenter = sourceFrame.top + sourceFrame.height() / 2;
-        final int destHCenter = destFrame.left + destFrame.width() / 2;
-        final int destVCenter = destFrame.top + destFrame.height() / 2;
-        final int fromX = enter ? sourceHCenter - destHCenter : destHCenter - sourceHCenter;
-        final int fromY = enter ? sourceVCenter - destVCenter : destVCenter - sourceVCenter;
-        final TranslateAnimation translation = enter ? new TranslateAnimation(fromX, 0, fromY, 0)
-                : new TranslateAnimation(0, fromX, 0, fromY);
-        set.addAnimation(scale);
-        set.addAnimation(translation);
-        setAppTransitionFinishedCallbackIfNeeded(set);
-        return set;
-    }
-
-    /**
-     * @return true if and only if the first frame of the transition can be skipped, i.e. the first
-     *         frame of the transition doesn't change the visuals on screen, so we can start
-     *         directly with the second one
-     */
-    boolean canSkipFirstFrame() {
-        return mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM
-                && !mNextAppTransitionOverrideRequested
-                && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE
-                && mNextAppTransitionType != NEXT_TRANSIT_TYPE_CLIP_REVEAL
-                && !mNextAppTransitionRequests.contains(TRANSIT_KEYGUARD_GOING_AWAY);
-    }
-
-    /**
-     *
-     * @param frame These are the bounds of the window when it finishes the animation. This is where
-     *              the animation must usually finish in entrance animation, as the next frame will
-     *              display the window at these coordinates. In case of exit animation, this is
-     *              where the animation must start, as the frame before the animation is displaying
-     *              the window at these bounds.
-     * @param insets Knowing where the window will be positioned is not enough. Some parts of the
-     *               window might be obscured, usually by the system windows (status bar and
-     *               navigation bar) and we use content insets to convey that information. This
-     *               usually affects the animation aspects vertically, as the system decoration is
-     *               at the top and the bottom. For example when we animate from full screen to
-     *               recents, we want to exclude the covered parts, because they won't match the
-     *               thumbnail after the last frame is executed.
-     * @param surfaceInsets In rare situation the surface is larger than the content and we need to
-     *                      know about this to make the animation frames match. We currently use
-     *                      this for freeform windows, which have larger surfaces to display
-     *                      shadows. When we animate them from recents, we want to match the content
-     *                      to the recents thumbnail and hence need to account for the surface being
-     *                      bigger.
-     */
-    @Nullable
-    Animation loadAnimation(LayoutParams lp, int transit, boolean enter, int uiMode,
-            int orientation, Rect frame, Rect displayFrame, Rect insets,
-            @Nullable Rect surfaceInsets, @Nullable Rect stableInsets, boolean isVoiceInteraction,
-            boolean freeform, WindowContainer container) {
-
-        final boolean canCustomizeAppTransition = container.canCustomizeAppTransition();
-
-        if (mNextAppTransitionOverrideRequested) {
-            if (canCustomizeAppTransition || mOverrideTaskTransition) {
-                mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM;
-            } else {
-                ProtoLog.e(WM_DEBUG_APP_TRANSITIONS_ANIM, "applyAnimation: "
-                        + " override requested, but it is prohibited by policy.");
-            }
-        }
-
-        Animation a;
-        if (isKeyguardGoingAwayTransitOld(transit) && enter) {
-            a = mTransitionAnimation.loadKeyguardExitAnimation(mNextAppTransitionFlags,
-                    transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER);
-        } else if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
-                || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM) {
-            a = null;
-        } else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE && !enter) {
-            a = mTransitionAnimation.loadKeyguardUnoccludeAnimation();
-        } else if (transit == TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE) {
-            a = null;
-        } else if (isVoiceInteraction && (transit == TRANSIT_OLD_ACTIVITY_OPEN
-                || transit == TRANSIT_OLD_TASK_OPEN
-                || transit == TRANSIT_OLD_TASK_TO_FRONT)) {
-            a = mTransitionAnimation.loadVoiceActivityOpenAnimation(enter);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,
-                    appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else if (isVoiceInteraction && (transit == TRANSIT_OLD_ACTIVITY_CLOSE
-                || transit == TRANSIT_OLD_TASK_CLOSE
-                || transit == TRANSIT_OLD_TASK_TO_BACK)) {
-            a = mTransitionAnimation.loadVoiceActivityExitAnimation(enter);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation voice: anim=%s transit=%s isEntrance=%b Callers=%s", a,
-                    appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else if (transit == TRANSIT_OLD_ACTIVITY_RELAUNCH) {
-            a = mTransitionAnimation.createRelaunchAnimation(frame, insets,
-                    mDefaultNextAppTransitionAnimationSpec != null
-                            ? mDefaultNextAppTransitionAnimationSpec.rect : null);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s transit=%s Callers=%s", a,
-                    appTransitionOldToString(transit), Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
-            a = getNextAppRequestedAnimation(enter);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM transit=%s "
-                            + "isEntrance=%b Callers=%s",
-                    a, appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE) {
-            a = mTransitionAnimation.loadAppTransitionAnimation(
-                    mNextAppTransitionPackage, mNextAppTransitionInPlace);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s nextAppTransition=ANIM_CUSTOM_IN_PLACE "
-                            + "transit=%s Callers=%s",
-                    a, appTransitionOldToString(transit), Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL) {
-            a = mTransitionAnimation.createClipRevealAnimationLockedCompat(
-                    transit, enter, frame, displayFrame,
-                    mDefaultNextAppTransitionAnimationSpec != null
-                            ? mDefaultNextAppTransitionAnimationSpec.rect : null);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s nextAppTransition=ANIM_CLIP_REVEAL "
-                            + "transit=%s Callers=%s",
-                    a, appTransitionOldToString(transit), Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_SCALE_UP) {
-            a = mTransitionAnimation.createScaleUpAnimationLockedCompat(transit, enter, frame,
-                    mDefaultNextAppTransitionAnimationSpec != null
-                            ? mDefaultNextAppTransitionAnimationSpec.rect : null);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s nextAppTransition=ANIM_SCALE_UP transit=%s "
-                            + "isEntrance=%s Callers=%s",
-                    a, appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP ||
-                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN) {
-            mNextAppTransitionScaleUp =
-                    (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP);
-            final HardwareBuffer thumbnailHeader = getAppTransitionThumbnailHeader(container);
-            a = mTransitionAnimation.createThumbnailEnterExitAnimationLockedCompat(enter,
-                    mNextAppTransitionScaleUp, frame, transit, thumbnailHeader,
-                    mDefaultNextAppTransitionAnimationSpec != null
-                            ? mDefaultNextAppTransitionAnimationSpec.rect : null);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
-                            + "Callers=%s",
-                    a,  mNextAppTransitionScaleUp
-                            ? "ANIM_THUMBNAIL_SCALE_UP" : "ANIM_THUMBNAIL_SCALE_DOWN",
-                    appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP ||
-                mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN) {
-            mNextAppTransitionScaleUp =
-                    (mNextAppTransitionType == NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP);
-            AppTransitionAnimationSpec spec = mNextAppTransitionAnimationsSpecs.get(
-                    container.hashCode());
-            a = mTransitionAnimation.createAspectScaledThumbnailEnterExitAnimationLocked(enter,
-                    mNextAppTransitionScaleUp, orientation, transit, frame, insets, surfaceInsets,
-                    stableInsets, freeform, spec != null ? spec.rect : null,
-                    mDefaultNextAppTransitionAnimationSpec != null
-                            ? mDefaultNextAppTransitionAnimationSpec.rect : null);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s nextAppTransition=%s transit=%s isEntrance=%b "
-                            + "Callers=%s",
-                    a, mNextAppTransitionScaleUp
-                            ? "ANIM_THUMBNAIL_ASPECT_SCALE_UP"
-                        : "ANIM_THUMBNAIL_ASPECT_SCALE_DOWN",
-                    appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else if (mNextAppTransitionType == NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS && enter) {
-            a = mTransitionAnimation.loadCrossProfileAppEnterAnimation();
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS: "
-                            + "anim=%s transit=%s isEntrance=true Callers=%s",
-                    a, appTransitionOldToString(transit), Debug.getCallers(3));
-        } else if (isChangeTransitOld(transit)) {
-            // In the absence of a specific adapter, we just want to keep everything stationary.
-            a = new AlphaAnimation(1.f, 1.f);
-            a.setDuration(WindowChangeAnimationSpec.ANIMATION_DURATION);
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s transit=%s isEntrance=%b Callers=%s",
-                    a, appTransitionOldToString(transit), enter, Debug.getCallers(3));
-        } else {
-            int animAttr = mapOpenCloseTransitTypes(transit, enter);
-            if (animAttr != 0) {
-                final CustomAppTransition customAppTransition =
-                        getCustomAppTransition(animAttr, container);
-                if (customAppTransition != null) {
-                    a = loadCustomActivityAnimation(customAppTransition, enter, container);
-                } else {
-                    if (canCustomizeAppTransition) {
-                        a = loadAnimationAttr(lp, animAttr, transit);
-                    } else {
-                        a = mTransitionAnimation.loadDefaultAnimationAttr(animAttr, transit);
-                    }
-                }
-            } else {
-                a = null;
-            }
-
-            ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM,
-                    "applyAnimation: anim=%s animAttr=0x%x transit=%s isEntrance=%b "
-                            + " canCustomizeAppTransition=%b Callers=%s",
-                    a, animAttr, appTransitionOldToString(transit), enter,
-                    canCustomizeAppTransition, Debug.getCallers(3));
-        }
-        setAppTransitionFinishedCallbackIfNeeded(a);
-
-        return a;
-    }
-
-    CustomAppTransition getCustomAppTransition(int animAttr, WindowContainer container) {
-        ActivityRecord customAnimationSource = container.asActivityRecord();
-        if (customAnimationSource == null) {
-            return null;
-        }
-
-        // Only top activity can customize activity animation.
-        // If the animation is for the one below, try to get from the above activity.
-        if (animAttr == WindowAnimation_activityOpenExitAnimation
-                || animAttr == WindowAnimation_activityCloseEnterAnimation) {
-            customAnimationSource = customAnimationSource.getTask()
-                    .getActivityAbove(customAnimationSource);
-            if (customAnimationSource == null) {
-                return null;
-            }
-        }
-        switch (animAttr) {
-            case WindowAnimation_activityOpenEnterAnimation:
-            case WindowAnimation_activityOpenExitAnimation:
-                return customAnimationSource.getCustomAnimation(true /* open */);
-            case WindowAnimation_activityCloseEnterAnimation:
-            case WindowAnimation_activityCloseExitAnimation:
-                return customAnimationSource.getCustomAnimation(false /* open */);
-        }
-        return null;
-    }
-    private Animation loadCustomActivityAnimation(@NonNull CustomAppTransition custom,
-            boolean enter, WindowContainer container) {
-        final ActivityRecord customAnimationSource = container.asActivityRecord();
-        final Animation a = mTransitionAnimation.loadAppTransitionAnimation(
-                customAnimationSource.packageName, enter
-                        ? custom.mEnterAnim : custom.mExitAnim);
-        if (a != null && custom.mBackgroundColor != 0) {
-            a.setBackdropColor(custom.mBackgroundColor);
-            a.setShowBackdrop(true);
-        }
-        return a;
-    }
-
-    int getAppRootTaskClipMode() {
-        return mNextAppTransitionRequests.contains(TRANSIT_RELAUNCH)
-                || mNextAppTransitionRequests.contains(TRANSIT_KEYGUARD_GOING_AWAY)
-                || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CLIP_REVEAL
-                ? ROOT_TASK_CLIP_NONE
-                : ROOT_TASK_CLIP_AFTER_ANIM;
-    }
-
-    @TransitionFlags
-    public int getTransitFlags() {
-        return mNextAppTransitionFlags;
-    }
-
-    void postAnimationCallback() {
-        if (mNextAppTransitionCallback != null) {
-            mHandler.sendMessage(PooledLambda.obtainMessage(AppTransition::doAnimationCallback,
-                    mNextAppTransitionCallback));
-            mNextAppTransitionCallback = null;
-        }
-    }
-
-    void overridePendingAppTransition(String packageName, int enterAnim, int exitAnim,
-            @ColorInt int backgroundColor, IRemoteCallback startedCallback,
-            IRemoteCallback endedCallback, boolean overrideTaskTransaction) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionOverrideRequested = true;
-            mNextAppTransitionPackage = packageName;
-            mNextAppTransitionEnter = enterAnim;
-            mNextAppTransitionExit = exitAnim;
-            mNextAppTransitionBackgroundColor = backgroundColor;
-            postAnimationCallback();
-            mNextAppTransitionCallback = startedCallback;
-            mAnimationFinishedCallback = endedCallback;
-            mOverrideTaskTransition = overrideTaskTransaction;
-        }
-    }
-
-    void overridePendingAppTransitionScaleUp(int startX, int startY, int startWidth,
-            int startHeight) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = NEXT_TRANSIT_TYPE_SCALE_UP;
-            putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
-            postAnimationCallback();
-        }
-    }
-
-    void overridePendingAppTransitionClipReveal(int startX, int startY,
-                                                int startWidth, int startHeight) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = NEXT_TRANSIT_TYPE_CLIP_REVEAL;
-            putDefaultNextAppTransitionCoordinates(startX, startY, startWidth, startHeight, null);
-            postAnimationCallback();
-        }
-    }
-
-    void overridePendingAppTransitionThumb(HardwareBuffer srcThumb, int startX, int startY,
-                                           IRemoteCallback startedCallback, boolean scaleUp) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP
-                    : NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN;
-            mNextAppTransitionScaleUp = scaleUp;
-            putDefaultNextAppTransitionCoordinates(startX, startY, 0, 0, srcThumb);
-            postAnimationCallback();
-            mNextAppTransitionCallback = startedCallback;
-        }
-    }
-
-    void overridePendingAppTransitionAspectScaledThumb(HardwareBuffer srcThumb, int startX,
-            int startY, int targetWidth, int targetHeight, IRemoteCallback startedCallback,
-            boolean scaleUp) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
-                    : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
-            mNextAppTransitionScaleUp = scaleUp;
-            putDefaultNextAppTransitionCoordinates(startX, startY, targetWidth, targetHeight,
-                    srcThumb);
-            postAnimationCallback();
-            mNextAppTransitionCallback = startedCallback;
-        }
-    }
-
-    void overridePendingAppTransitionMultiThumb(AppTransitionAnimationSpec[] specs,
-            IRemoteCallback onAnimationStartedCallback, IRemoteCallback onAnimationFinishedCallback,
-            boolean scaleUp) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
-                    : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
-            mNextAppTransitionScaleUp = scaleUp;
-            if (specs != null) {
-                for (int i = 0; i < specs.length; i++) {
-                    AppTransitionAnimationSpec spec = specs[i];
-                    if (spec != null) {
-                        final PooledPredicate p = PooledLambda.obtainPredicate(
-                                Task::isTaskId, PooledLambda.__(Task.class), spec.taskId);
-                        final WindowContainer container = mDisplayContent.getTask(p);
-                        p.recycle();
-                        if (container == null) {
-                            continue;
-                        }
-                        mNextAppTransitionAnimationsSpecs.put(container.hashCode(), spec);
-                        if (i == 0) {
-                            // In full screen mode, the transition code depends on the default spec
-                            // to be set.
-                            Rect rect = spec.rect;
-                            putDefaultNextAppTransitionCoordinates(rect.left, rect.top,
-                                    rect.width(), rect.height(), spec.buffer);
-                        }
-                    }
-                }
-            }
-            postAnimationCallback();
-            mNextAppTransitionCallback = onAnimationStartedCallback;
-            mAnimationFinishedCallback = onAnimationFinishedCallback;
-        }
-    }
-
-    void overridePendingAppTransitionMultiThumbFuture(
-            IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
-            boolean scaleUp) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = scaleUp ? NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP
-                    : NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN;
-            mNextAppTransitionAnimationsSpecsFuture = specsFuture;
-            mNextAppTransitionScaleUp = scaleUp;
-            mNextAppTransitionFutureCallback = callback;
-            if (isReady()) {
-                fetchAppTransitionSpecsFromFuture();
-            }
-        }
-    }
-
-    void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter) {
-        overridePendingAppTransitionRemote(remoteAnimationAdapter, false /* sync */,
-                false /* isActivityEmbedding*/);
-    }
-
-    void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter,
-            boolean sync, boolean isActivityEmbedding) {
-    }
-
-    void overrideInPlaceAppTransition(String packageName, int anim) {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE;
-            mNextAppTransitionPackage = packageName;
-            mNextAppTransitionInPlace = anim;
-        }
-    }
-
-    /**
-     * @see {@link #NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS}
-     */
-    void overridePendingAppTransitionStartCrossProfileApps() {
-        if (canOverridePendingAppTransition()) {
-            clear();
-            mNextAppTransitionType = NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS;
-            postAnimationCallback();
-        }
-    }
-
-    private boolean canOverridePendingAppTransition() {
-        // Remote animations always take precedence
-        return isTransitionSet() &&  mNextAppTransitionType != NEXT_TRANSIT_TYPE_REMOTE;
-    }
-
-    /**
-     * If a future is set for the app transition specs, fetch it in another thread.
-     */
-    private void fetchAppTransitionSpecsFromFuture() {
-        if (mNextAppTransitionAnimationsSpecsFuture != null) {
-            mNextAppTransitionAnimationsSpecsPending = true;
-            final IAppTransitionAnimationSpecsFuture future
-                    = mNextAppTransitionAnimationsSpecsFuture;
-            mNextAppTransitionAnimationsSpecsFuture = null;
-            mDefaultExecutor.execute(() -> {
-                AppTransitionAnimationSpec[] specs = null;
-                try {
-                    Binder.allowBlocking(future.asBinder());
-                    specs = future.get();
-                } catch (RemoteException e) {
-                    Slog.w(TAG, "Failed to fetch app transition specs: " + e);
-                }
-                synchronized (mService.mGlobalLock) {
-                    mNextAppTransitionAnimationsSpecsPending = false;
-                    overridePendingAppTransitionMultiThumb(specs,
-                            mNextAppTransitionFutureCallback, null /* finishedCallback */,
-                            mNextAppTransitionScaleUp);
-                    mNextAppTransitionFutureCallback = null;
-                    mService.requestTraversal();
-                }
-            });
-        }
-    }
-
-    @Override
-    public String toString() {
-        StringBuilder sb = new StringBuilder();
-        sb.append("mNextAppTransitionRequests=[");
-
-        boolean separator = false;
-        for (Integer transit : mNextAppTransitionRequests) {
-            if (separator) {
-                sb.append(", ");
-            }
-            sb.append(appTransitionToString(transit));
-            separator = true;
-        }
-        sb.append("]");
-        sb.append(", mNextAppTransitionFlags="
-                + appTransitionFlagsToString(mNextAppTransitionFlags));
-        return sb.toString();
-    }
-
-    /**
-     * Returns the human readable name of a old window transition.
-     *
-     * @param transition The old window transition.
-     * @return The transition symbolic name.
-     */
-    public static String appTransitionOldToString(@TransitionOldType int transition) {
-        switch (transition) {
-            case TRANSIT_OLD_UNSET: {
-                return "TRANSIT_OLD_UNSET";
-            }
-            case TRANSIT_OLD_NONE: {
-                return "TRANSIT_OLD_NONE";
-            }
-            case TRANSIT_OLD_ACTIVITY_OPEN: {
-                return "TRANSIT_OLD_ACTIVITY_OPEN";
-            }
-            case TRANSIT_OLD_ACTIVITY_CLOSE: {
-                return "TRANSIT_OLD_ACTIVITY_CLOSE";
-            }
-            case TRANSIT_OLD_TASK_OPEN: {
-                return "TRANSIT_OLD_TASK_OPEN";
-            }
-            case TRANSIT_OLD_TASK_CLOSE: {
-                return "TRANSIT_OLD_TASK_CLOSE";
-            }
-            case TRANSIT_OLD_TASK_TO_FRONT: {
-                return "TRANSIT_OLD_TASK_TO_FRONT";
-            }
-            case TRANSIT_OLD_TASK_TO_BACK: {
-                return "TRANSIT_OLD_TASK_TO_BACK";
-            }
-            case TRANSIT_OLD_WALLPAPER_CLOSE: {
-                return "TRANSIT_OLD_WALLPAPER_CLOSE";
-            }
-            case TRANSIT_OLD_WALLPAPER_OPEN: {
-                return "TRANSIT_OLD_WALLPAPER_OPEN";
-            }
-            case TRANSIT_OLD_WALLPAPER_INTRA_OPEN: {
-                return "TRANSIT_OLD_WALLPAPER_INTRA_OPEN";
-            }
-            case TRANSIT_OLD_WALLPAPER_INTRA_CLOSE: {
-                return "TRANSIT_OLD_WALLPAPER_INTRA_CLOSE";
-            }
-            case TRANSIT_OLD_TASK_OPEN_BEHIND: {
-                return "TRANSIT_OLD_TASK_OPEN_BEHIND";
-            }
-            case TRANSIT_OLD_ACTIVITY_RELAUNCH: {
-                return "TRANSIT_OLD_ACTIVITY_RELAUNCH";
-            }
-            case TRANSIT_OLD_KEYGUARD_GOING_AWAY: {
-                return "TRANSIT_OLD_KEYGUARD_GOING_AWAY";
-            }
-            case TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER: {
-                return "TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER";
-            }
-            case TRANSIT_OLD_KEYGUARD_OCCLUDE: {
-                return "TRANSIT_OLD_KEYGUARD_OCCLUDE";
-            }
-            case TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM: {
-                return "TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM";
-            }
-            case TRANSIT_OLD_KEYGUARD_UNOCCLUDE: {
-                return "TRANSIT_OLD_KEYGUARD_UNOCCLUDE";
-            }
-            case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN: {
-                return "TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN";
-            }
-            case TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE: {
-                return "TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE";
-            }
-            case TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE: {
-                return "TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE";
-            }
-            case TRANSIT_OLD_TASK_FRAGMENT_OPEN: {
-                return "TRANSIT_OLD_TASK_FRAGMENT_OPEN";
-            }
-            case TRANSIT_OLD_TASK_FRAGMENT_CLOSE: {
-                return "TRANSIT_OLD_TASK_FRAGMENT_CLOSE";
-            }
-            case TRANSIT_OLD_TASK_FRAGMENT_CHANGE: {
-                return "TRANSIT_OLD_TASK_FRAGMENT_CHANGE";
-            }
-            case TRANSIT_OLD_DREAM_ACTIVITY_OPEN: {
-                return "TRANSIT_OLD_DREAM_ACTIVITY_OPEN";
-            }
-            case TRANSIT_OLD_DREAM_ACTIVITY_CLOSE: {
-                return "TRANSIT_OLD_DREAM_ACTIVITY_CLOSE";
-            }
-            default: {
-                return "<UNKNOWN: " + transition + ">";
-            }
-        }
-    }
-
-    /**
-     * Returns the human readable name of a window transition.
-     *
-     * @param transition The window transition.
-     * @return The transition symbolic name.
-     */
-    public static String appTransitionToString(@TransitionType int transition) {
-        switch (transition) {
-            case TRANSIT_NONE: {
-                return "TRANSIT_NONE";
-            }
-            case TRANSIT_OPEN: {
-                return "TRANSIT_OPEN";
-            }
-            case TRANSIT_CLOSE: {
-                return "TRANSIT_CLOSE";
-            }
-            case TRANSIT_TO_FRONT: {
-                return "TRANSIT_TO_FRONT";
-            }
-            case TRANSIT_TO_BACK: {
-                return "TRANSIT_TO_BACK";
-            }
-            case TRANSIT_RELAUNCH: {
-                return "TRANSIT_RELAUNCH";
-            }
-            case TRANSIT_CHANGE: {
-                return "TRANSIT_CHANGE";
-            }
-            case TRANSIT_KEYGUARD_GOING_AWAY: {
-                return "TRANSIT_KEYGUARD_GOING_AWAY";
-            }
-            case TRANSIT_KEYGUARD_OCCLUDE: {
-                return "TRANSIT_KEYGUARD_OCCLUDE";
-            }
-            case TRANSIT_KEYGUARD_UNOCCLUDE: {
-                return "TRANSIT_KEYGUARD_UNOCCLUDE";
-            }
-            default: {
-                return "<UNKNOWN: " + transition + ">";
-            }
-        }
-    }
-
-    private String appStateToString() {
-        switch (mAppTransitionState) {
-            case APP_STATE_IDLE:
-                return "APP_STATE_IDLE";
-            case APP_STATE_READY:
-                return "APP_STATE_READY";
-            case APP_STATE_RUNNING:
-                return "APP_STATE_RUNNING";
-            case APP_STATE_TIMEOUT:
-                return "APP_STATE_TIMEOUT";
-            default:
-                return "unknown state=" + mAppTransitionState;
-        }
-    }
-
-    private String transitTypeToString() {
-        switch (mNextAppTransitionType) {
-            case NEXT_TRANSIT_TYPE_NONE:
-                return "NEXT_TRANSIT_TYPE_NONE";
-            case NEXT_TRANSIT_TYPE_CUSTOM:
-                return "NEXT_TRANSIT_TYPE_CUSTOM";
-            case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
-                return "NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE";
-            case NEXT_TRANSIT_TYPE_SCALE_UP:
-                return "NEXT_TRANSIT_TYPE_SCALE_UP";
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
-                return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP";
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
-                return "NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN";
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
-                return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP";
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN:
-                return "NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN";
-            case NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS:
-                return "NEXT_TRANSIT_TYPE_OPEN_CROSS_PROFILE_APPS";
-            default:
-                return "unknown type=" + mNextAppTransitionType;
-        }
-    }
-
-    private static final ArrayList<Pair<Integer, String>> sFlagToString;
-
-    static {
-        sFlagToString = new ArrayList<>();
-        sFlagToString.add(new Pair<>(TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE,
-                "TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_SHADE"));
-        sFlagToString.add(new Pair<>(TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION,
-                "TRANSIT_FLAG_KEYGUARD_GOING_AWAY_NO_ANIMATION"));
-        sFlagToString.add(new Pair<>(TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER,
-                "TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER"));
-        sFlagToString.add(new Pair<>(TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION,
-                "TRANSIT_FLAG_KEYGUARD_GOING_AWAY_SUBTLE_ANIMATION"));
-        sFlagToString.add(new Pair<>(
-                TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_CLEAR_SNAPSHOT,
-                "TRANSIT_FLAG_KEYGUARD_GOING_AWAY_TO_LAUNCHER_WITH_IN_WINDOW_ANIMATIONS"));
-        sFlagToString.add(new Pair<>(TRANSIT_FLAG_APP_CRASHED,
-                "TRANSIT_FLAG_APP_CRASHED"));
-        sFlagToString.add(new Pair<>(TRANSIT_FLAG_OPEN_BEHIND,
-                "TRANSIT_FLAG_OPEN_BEHIND"));
-    }
-
-    /**
-     * Returns the human readable names of transit flags.
-     *
-     * @param flags a bitmask combination of transit flags.
-     * @return The combination of symbolic names.
-     */
-    public static String appTransitionFlagsToString(int flags) {
-        String sep = "";
-        StringBuilder sb = new StringBuilder();
-        for (Pair<Integer, String> pair : sFlagToString) {
-            if ((flags & pair.first) != 0) {
-                sb.append(sep);
-                sb.append(pair.second);
-                sep = " | ";
-            }
-        }
-        return sb.toString();
-    }
-
-    void dumpDebug(ProtoOutputStream proto, long fieldId) {
-        final long token = proto.start(fieldId);
-        proto.write(APP_TRANSITION_STATE, mAppTransitionState);
-        proto.write(LAST_USED_APP_TRANSITION, mLastUsedAppTransition);
-        proto.end(token);
-    }
-
-    @Override
-    public void dump(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.println(this);
-        pw.print(prefix); pw.print("mAppTransitionState="); pw.println(appStateToString());
-        if (mNextAppTransitionType != NEXT_TRANSIT_TYPE_NONE) {
-            pw.print(prefix); pw.print("mNextAppTransitionType=");
-                    pw.println(transitTypeToString());
-        }
-        if (mNextAppTransitionOverrideRequested
-                || mNextAppTransitionType == NEXT_TRANSIT_TYPE_CUSTOM) {
-            pw.print(prefix); pw.print("mNextAppTransitionPackage=");
-            pw.println(mNextAppTransitionPackage);
-            pw.print(prefix); pw.print("mNextAppTransitionEnter=0x");
-            pw.print(Integer.toHexString(mNextAppTransitionEnter));
-            pw.print(" mNextAppTransitionExit=0x");
-            pw.println(Integer.toHexString(mNextAppTransitionExit));
-            pw.print(" mNextAppTransitionBackgroundColor=0x");
-            pw.println(Integer.toHexString(mNextAppTransitionBackgroundColor));
-        }
-        switch (mNextAppTransitionType) {
-            case NEXT_TRANSIT_TYPE_CUSTOM_IN_PLACE:
-                pw.print(prefix); pw.print("mNextAppTransitionPackage=");
-                        pw.println(mNextAppTransitionPackage);
-                pw.print(prefix); pw.print("mNextAppTransitionInPlace=0x");
-                        pw.print(Integer.toHexString(mNextAppTransitionInPlace));
-                break;
-            case NEXT_TRANSIT_TYPE_SCALE_UP: {
-                getDefaultNextAppTransitionStartRect(mTmpRect);
-                pw.print(prefix); pw.print("mNextAppTransitionStartX=");
-                        pw.print(mTmpRect.left);
-                        pw.print(" mNextAppTransitionStartY=");
-                        pw.println(mTmpRect.top);
-                pw.print(prefix); pw.print("mNextAppTransitionStartWidth=");
-                        pw.print(mTmpRect.width());
-                        pw.print(" mNextAppTransitionStartHeight=");
-                        pw.println(mTmpRect.height());
-                break;
-            }
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_UP:
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_SCALE_DOWN:
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_UP:
-            case NEXT_TRANSIT_TYPE_THUMBNAIL_ASPECT_SCALE_DOWN: {
-                pw.print(prefix); pw.print("mDefaultNextAppTransitionAnimationSpec=");
-                        pw.println(mDefaultNextAppTransitionAnimationSpec);
-                pw.print(prefix); pw.print("mNextAppTransitionAnimationsSpecs=");
-                        pw.println(mNextAppTransitionAnimationsSpecs);
-                pw.print(prefix); pw.print("mNextAppTransitionScaleUp=");
-                        pw.println(mNextAppTransitionScaleUp);
-                break;
-            }
-        }
-        if (mNextAppTransitionCallback != null) {
-            pw.print(prefix); pw.print("mNextAppTransitionCallback=");
-                    pw.println(mNextAppTransitionCallback);
-        }
-        if (mLastUsedAppTransition != TRANSIT_OLD_NONE) {
-            pw.print(prefix); pw.print("mLastUsedAppTransition=");
-                    pw.println(appTransitionOldToString(mLastUsedAppTransition));
-            pw.print(prefix); pw.print("mLastOpeningApp=");
-                    pw.println(mLastOpeningApp);
-            pw.print(prefix); pw.print("mLastClosingApp=");
-                    pw.println(mLastClosingApp);
-            pw.print(prefix); pw.print("mLastChangingApp=");
-            pw.println(mLastChangingApp);
-        }
-    }
-
-    boolean prepareAppTransition(@TransitionType int transit, @TransitionFlags int flags) {
-        if (WindowManagerService.sEnableShellTransitions) {
-            return false;
-        }
-        mNextAppTransitionRequests.add(transit);
-        mNextAppTransitionFlags |= flags;
-        updateBooster();
-        removeAppTransitionTimeoutCallbacks();
-        mHandler.postDelayed(mHandleAppTransitionTimeoutRunnable,
-                APP_TRANSITION_TIMEOUT_MS);
-        return prepare();
-    }
-
-    /**
-     * @return true if {@param transit} is representing a transition in which Keyguard is going
-     *         away, false otherwise
-     */
-    public static boolean isKeyguardGoingAwayTransitOld(int transit) {
-        return transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY
-                || transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
-    }
-
-    static boolean isKeyguardOccludeTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
-                || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM
-                || transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
-    }
-
-    static boolean isKeyguardTransitOld(@TransitionOldType int transit) {
-        return isKeyguardGoingAwayTransitOld(transit) || isKeyguardOccludeTransitOld(transit);
-    }
-
-    static boolean isTaskTransitOld(@TransitionOldType int transit) {
-        return isTaskOpenTransitOld(transit)
-                || isTaskCloseTransitOld(transit);
-    }
-
-    static boolean isTaskCloseTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_TASK_CLOSE
-                || transit == TRANSIT_OLD_TASK_TO_BACK;
-    }
-
-    private static  boolean isTaskOpenTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_TASK_OPEN
-                || transit == TRANSIT_OLD_TASK_OPEN_BEHIND
-                || transit == TRANSIT_OLD_TASK_TO_FRONT;
-    }
-
-    static boolean isActivityTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_ACTIVITY_OPEN
-                || transit == TRANSIT_OLD_ACTIVITY_CLOSE
-                || transit == TRANSIT_OLD_ACTIVITY_RELAUNCH;
-    }
-
-    static boolean isTaskFragmentTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_TASK_FRAGMENT_OPEN
-                || transit == TRANSIT_OLD_TASK_FRAGMENT_CLOSE
-                || transit == TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
-    }
-
-    static boolean isChangeTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE
-                || transit == TRANSIT_OLD_TASK_FRAGMENT_CHANGE;
-    }
-
-    static boolean isClosingTransitOld(@TransitionOldType int transit) {
-        return transit == TRANSIT_OLD_ACTIVITY_CLOSE
-                || transit == TRANSIT_OLD_TASK_CLOSE
-                || transit == TRANSIT_OLD_WALLPAPER_CLOSE
-                || transit == TRANSIT_OLD_WALLPAPER_INTRA_CLOSE
-                || transit == TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE
-                || transit == TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE;
-    }
-
-    static boolean isNormalTransit(@TransitionType int transit) {
-        return transit == TRANSIT_OPEN
-                || transit == TRANSIT_CLOSE
-                || transit == TRANSIT_TO_FRONT
-                || transit == TRANSIT_TO_BACK;
-    }
-
-    static boolean isKeyguardTransit(@TransitionType int transit) {
-        return transit == TRANSIT_KEYGUARD_GOING_AWAY
-                || transit == TRANSIT_KEYGUARD_OCCLUDE
-                || transit == TRANSIT_KEYGUARD_UNOCCLUDE;
-    }
-
-    @TransitionType int getKeyguardTransition() {
-        if (mNextAppTransitionRequests.indexOf(TRANSIT_KEYGUARD_GOING_AWAY) != -1) {
-            return TRANSIT_KEYGUARD_GOING_AWAY;
-        }
-        final int unoccludeIndex = mNextAppTransitionRequests.indexOf(TRANSIT_KEYGUARD_UNOCCLUDE);
-        final int occludeIndex = mNextAppTransitionRequests.indexOf(TRANSIT_KEYGUARD_OCCLUDE);
-        // No keyguard related transition requests.
-        if (unoccludeIndex == -1 && occludeIndex == -1) {
-            return TRANSIT_NONE;
-        }
-        // In case we unocclude Keyguard and occlude it again, meaning that we never actually
-        // unoccclude/occlude Keyguard, but just run a normal transition.
-        if (unoccludeIndex != -1 && unoccludeIndex < occludeIndex) {
-            return TRANSIT_NONE;
-        }
-        return unoccludeIndex != -1 ? TRANSIT_KEYGUARD_UNOCCLUDE : TRANSIT_KEYGUARD_OCCLUDE;
-    }
-
-    @TransitionType int getFirstAppTransition() {
-        for (int i = 0; i < mNextAppTransitionRequests.size(); ++i) {
-            final @TransitionType int transit = mNextAppTransitionRequests.get(i);
-            if (transit != TRANSIT_NONE && !isKeyguardTransit(transit)) {
-                return transit;
-            }
-        }
-        return TRANSIT_NONE;
-    }
-
-    boolean containsTransitRequest(@TransitionType int transit) {
-        return mNextAppTransitionRequests.contains(transit);
-    }
-
-    private void handleAppTransitionTimeout() {
-    }
-
-    private static void doAnimationCallback(@NonNull IRemoteCallback callback) {
-        try {
-            ((IRemoteCallback) callback).sendResult(null);
-        } catch (RemoteException e) {
-        }
-    }
-
-    private void setAppTransitionFinishedCallbackIfNeeded(Animation anim) {
-        final IRemoteCallback callback = mAnimationFinishedCallback;
-        if (callback != null && anim != null) {
-            anim.setAnimationListener(new Animation.AnimationListener() {
-                @Override
-                public void onAnimationStart(Animation animation) { }
-
-                @Override
-                public void onAnimationEnd(Animation animation) {
-                    mHandler.sendMessage(PooledLambda.obtainMessage(
-                            AppTransition::doAnimationCallback, callback));
-                }
-
-                @Override
-                public void onAnimationRepeat(Animation animation) { }
-            });
-        }
-    }
-
-    void removeAppTransitionTimeoutCallbacks() {
-        mHandler.removeCallbacks(mHandleAppTransitionTimeoutRunnable);
-    }
-}
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index e9d9ace..e9b7649 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -691,8 +691,8 @@
             return false;
         }
         if (window.mAttrs.windowAnimations != 0) {
-            final TransitionAnimation transitionAnimation = window.getDisplayContent()
-                    .mAppTransition.mTransitionAnimation;
+            final TransitionAnimation transitionAnimation = window.mDisplayContent
+                    .mTransitionAnimation;
             final int attr = com.android.internal.R.styleable
                     .WindowAnimation_activityCloseExitAnimation;
             final int appResId = transitionAnimation.getAnimationResId(
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index 36686fc..2287a68 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -288,9 +288,10 @@
     }
 
     private boolean isHomeApp(int uid, @Nullable String packageName) {
-        if (getService().mHomeProcess != null) {
-            // Fast check
-            return uid == getService().mHomeProcess.mUid;
+        WindowProcessController homeProcess = getService().mHomeProcess;
+        if (homeProcess != null && (homeProcess.mUid != SYSTEM_UID || packageName == null)) {
+            // Fast check (skip if sharing system UID and we have a package name)
+            return uid == homeProcess.mUid;
         }
         if (packageName == null) {
             return false;
diff --git a/services/core/java/com/android/server/wm/DesktopModeHelper.java b/services/core/java/com/android/server/wm/DesktopModeHelper.java
index dc42b32..d91fca9 100644
--- a/services/core/java/com/android/server/wm/DesktopModeHelper.java
+++ b/services/core/java/com/android/server/wm/DesktopModeHelper.java
@@ -17,6 +17,7 @@
 package com.android.server.wm;
 
 import static android.app.Flags.enableConnectedDisplaysWallpaper;
+import static android.window.DesktopExperienceFlags.ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE;
 
 import android.annotation.NonNull;
 import android.content.Context;
@@ -66,7 +67,7 @@
      * Return {@code true} if the current device can hosts desktop sessions on its internal display.
      */
     @VisibleForTesting
-    static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
+    private static boolean canInternalDisplayHostDesktops(@NonNull Context context) {
         return context.getResources().getBoolean(R.bool.config_canInternalDisplayHostDesktops);
     }
 
@@ -83,8 +84,11 @@
         if (!shouldEnforceDeviceRestrictions()) {
             return true;
         }
-        final boolean desktopModeSupported = isDesktopModeSupported(context)
-                && canInternalDisplayHostDesktops(context);
+        // If projected display is enabled, #canInternalDisplayHostDesktops is no longer a
+        // requirement.
+        final boolean desktopModeSupported = ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE.isTrue()
+                ? isDesktopModeSupported(context) : (isDesktopModeSupported(context)
+                && canInternalDisplayHostDesktops(context));
         final boolean desktopModeSupportedByDevOptions =
                 Flags.enableDesktopModeThroughDevOption()
                         && isDesktopModeDevOptionsSupported(context);
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 574ab05..353ccd5 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -82,7 +82,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_DESTROY;
 import static android.view.WindowManager.TRANSIT_CHANGE;
-import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.view.inputmethod.ImeTracker.DEBUG_IME_VISIBILITY;
@@ -100,7 +99,6 @@
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WALLPAPER;
 import static com.android.internal.protolog.WmProtoLogGroups.WM_SHOW_TRANSACTIONS;
 import static com.android.internal.util.LatencyTracker.ACTION_ROTATE_SCREEN;
-import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
@@ -108,7 +106,7 @@
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.ActivityTaskManagerService.POWER_MODE_REASON_CHANGE_DISPLAY;
 import static com.android.server.wm.DisplayContentProto.APP_TRANSITION;
-import static com.android.server.wm.DisplayContentProto.CURRENT_FOCUS;
+import static com.android.server.wm.DisplayContentProto.CURRENT_FOCUS_IDENTIFIER;
 import static com.android.server.wm.DisplayContentProto.DISPLAY_FRAMES;
 import static com.android.server.wm.DisplayContentProto.DISPLAY_INFO;
 import static com.android.server.wm.DisplayContentProto.DISPLAY_READY;
@@ -118,9 +116,9 @@
 import static com.android.server.wm.DisplayContentProto.FOCUSED_ROOT_TASK_ID;
 import static com.android.server.wm.DisplayContentProto.ID;
 import static com.android.server.wm.DisplayContentProto.IME_POLICY;
-import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_CONTROL_TARGET;
-import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_INPUT_TARGET;
-import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_TARGET;
+import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_CONTROL_TARGET_IDENTIFIER;
+import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_INPUT_TARGET_IDENTIFIER;
+import static com.android.server.wm.DisplayContentProto.INPUT_METHOD_LAYERING_TARGET_IDENTIFIER;
 import static com.android.server.wm.DisplayContentProto.IS_SLEEPING;
 import static com.android.server.wm.DisplayContentProto.KEEP_CLEAR_AREAS;
 import static com.android.server.wm.DisplayContentProto.MIN_SIZE_OF_RESIZEABLE_TASK_DP;
@@ -156,7 +154,6 @@
 import static com.android.server.wm.utils.DisplayInfoOverrides.copyDisplayInfoFields;
 import static com.android.server.wm.utils.RegionUtils.forEachRectReverse;
 import static com.android.server.wm.utils.RegionUtils.rectListToRegion;
-import static com.android.window.flags.Flags.enablePersistingDensityScaleForConnectedDisplays;
 import static com.android.window.flags.Flags.enablePresentationForConnectedDisplays;
 
 import android.annotation.IntDef;
@@ -237,6 +234,7 @@
 import android.view.WindowManager.DisplayImePolicy;
 import android.view.WindowManagerPolicyConstants.PointerEventListener;
 import android.view.inputmethod.ImeTracker;
+import android.window.DesktopExperienceFlags;
 import android.window.DisplayWindowPolicyController;
 import android.window.IDisplayAreaOrganizer;
 import android.window.ScreenCapture;
@@ -248,6 +246,7 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.logging.MetricsLogger;
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
+import com.android.internal.policy.TransitionAnimation;
 import com.android.internal.protolog.ProtoLog;
 import com.android.internal.util.ToBooleanFunction;
 import com.android.internal.util.function.pooled.PooledLambda;
@@ -365,7 +364,8 @@
     private boolean mTmpInitial;
     private int mMaxUiWidth = 0;
 
-    final AppTransition mAppTransition;
+    // TODO(b/400335290): extract the needed methods and remove this field.
+    final TransitionAnimation mTransitionAnimation;
 
     final UnknownAppVisibilityController mUnknownAppVisibilityController;
 
@@ -1180,7 +1180,7 @@
         mHoldScreenWakeLock.setReferenceCounted(false);
 
         mFixedRotationTransitionListener = new FixedRotationTransitionListener(mDisplayId);
-        mAppTransition = new AppTransition(mWmService.mContext, mWmService, this);
+        mTransitionAnimation = new TransitionAnimation(mWmService.mContext, false /* debug */, TAG);
         mTransitionController.registerLegacyListener(mFixedRotationTransitionListener);
         mUnknownAppVisibilityController = new UnknownAppVisibilityController(mWmService, this);
         mRemoteDisplayChangeController = new RemoteDisplayChangeController(this);
@@ -3154,7 +3154,7 @@
             }
         }
         // Update the base density if there is a forced density ratio.
-        if (enablePersistingDensityScaleForConnectedDisplays()
+        if (DesktopExperienceFlags.ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS.isTrue()
                 && mIsDensityForced && mExternalDisplayForcedDensityRatio != 0.0f) {
             mBaseDisplayDensity = (int)
                     (mInitialDisplayDensity * mExternalDisplayForcedDensityRatio + 0.5);
@@ -3189,7 +3189,7 @@
             density = 0;
         }
         // Save the new density ratio to settings for external displays.
-        if (enablePersistingDensityScaleForConnectedDisplays()
+        if (DesktopExperienceFlags.ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS.isTrue()
                 && mDisplayInfo.type == TYPE_EXTERNAL) {
             mExternalDisplayForcedDensityRatio = (float)
                     mBaseDisplayDensity / getInitialDisplayDensity();
@@ -3258,16 +3258,15 @@
     }
 
     void onDisplayInfoChangeApplied() {
-        if (!enableDisplayContentModeManagement()) {
+        if (!DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
             Slog.e(TAG, "ShouldShowSystemDecors shouldn't be updated when the flag is off.");
         }
 
-        final boolean shouldShowContent;
         if (!allowContentModeSwitch()) {
             return;
         }
-        shouldShowContent = mDisplay.canHostTasks();
 
+        final boolean shouldShowContent = mDisplay.canHostTasks();
         if (shouldShowContent == mWmService.mDisplayWindowSettings
                 .shouldShowSystemDecorsLocked(this)) {
             return;
@@ -3277,9 +3276,21 @@
         if (!shouldShowContent) {
             clearAllTasksOnDisplay(null /* clearTasksCallback */, false /* isRemovingDisplay */);
         }
+
+        // If the display is allowed to show content, then it belongs to the display topology;
+        // vice versa.
+        mWmService.mDisplayManagerInternal.onDisplayBelongToTopologyChanged(mDisplayId,
+                /* inTopology= */ shouldShowContent);
     }
 
      /**
+      * Whether the display is allowed to switch the content mode between extended and mirroring.
+      * If the content mode is extended, the display will start home activity and show system
+      * decorations, such as wallpapaer, status bar and navigation bar.
+      * If the content mode is mirroring, the display will not show home activity or system
+      * decorations.
+      * The content mode is switched when {@link Display#canHostTasks()} changes.
+      *
       * Note that we only allow displays that are able to show system decorations to use the content
       * mode switch; however, not all displays that are able to show system decorations are allowed
       * to use the content mode switch.
@@ -3295,6 +3306,10 @@
             return false;
         }
 
+        if (shouldNeverShowSystemDecorations()) {
+            return false;
+        }
+
         // TODO(b/391965805): Remove this after introducing FLAG_ALLOW_CONTENT_MODE_SWITCH.
         if ((mDisplay.getFlags() & Display.FLAG_REAR) != 0) {
             return false;
@@ -3612,18 +3627,20 @@
         }
 
         if (mImeLayeringTarget != null) {
-            mImeLayeringTarget.dumpDebug(proto, INPUT_METHOD_TARGET, logLevel);
+            mImeLayeringTarget.writeIdentifierToProto(
+                    proto, INPUT_METHOD_LAYERING_TARGET_IDENTIFIER);
         }
-        if (mImeInputTarget != null) {
-            mImeInputTarget.dumpProto(proto, INPUT_METHOD_INPUT_TARGET, logLevel);
+        if (mImeInputTarget != null && mImeInputTarget.getWindowState() != null) {
+            mImeInputTarget.getWindowState().writeIdentifierToProto(
+                    proto, INPUT_METHOD_INPUT_TARGET_IDENTIFIER);
         }
         if (mImeControlTarget != null
                 && mImeControlTarget.getWindow() != null) {
-            mImeControlTarget.getWindow().dumpDebug(proto, INPUT_METHOD_CONTROL_TARGET,
-                    logLevel);
+            mImeControlTarget.getWindow().writeIdentifierToProto(
+                    proto, INPUT_METHOD_CONTROL_TARGET_IDENTIFIER);
         }
         if (mCurrentFocus != null) {
-            mCurrentFocus.dumpDebug(proto, CURRENT_FOCUS, logLevel);
+            mCurrentFocus.writeIdentifierToProto(proto, CURRENT_FOCUS_IDENTIFIER);
         }
         if (mInsetsStateController != null) {
             mInsetsStateController.dumpDebug(proto, logLevel);
@@ -5634,29 +5651,11 @@
     }
 
     /**
-     * @deprecated new transition should use {@link #requestTransitionAndLegacyPrepare(int, int)}
-     */
-    @Deprecated
-    void prepareAppTransition(@WindowManager.TransitionType int transit) {
-        prepareAppTransition(transit, 0 /* flags */);
-    }
-
-    /**
-     * @deprecated new transition should use {@link #requestTransitionAndLegacyPrepare(int, int)}
-     */
-    @Deprecated
-    void prepareAppTransition(@WindowManager.TransitionType int transit,
-            @WindowManager.TransitionFlags int flags) {
-        mAppTransition.prepareAppTransition(transit, flags);
-    }
-
-    /**
      * Helper that both requests a transition (using the new transition system) and prepares
      * the legacy transition system. Use this when both systems have the same start-point.
      *
      * @see TransitionController#requestTransitionIfNeeded(int, int, WindowContainer,
      *      WindowContainer)
-     * @see AppTransition#prepareAppTransition
      */
     void requestTransitionAndLegacyPrepare(@WindowManager.TransitionType int transit,
             @WindowManager.TransitionFlags int flags, @Nullable WindowContainer trigger) {
@@ -5675,16 +5674,23 @@
         return type == TRANSIT_OPEN || type == TRANSIT_TO_FRONT;
     }
 
+    private boolean shouldNeverShowSystemDecorations() {
+        if (mDisplayId == mWmService.mVr2dDisplayId) {
+            // VR virtual display will be used to run and render 2D app within a VR experience.
+            return true;
+        }
+        if (!isTrusted()) {
+            // Do not show system decorations on untrusted virtual display.
+            return true;
+        }
+        return false;
+    }
+
     /**
      * @see Display#FLAG_SHOULD_SHOW_SYSTEM_DECORATIONS
      */
     boolean isSystemDecorationsSupported() {
-        if (mDisplayId == mWmService.mVr2dDisplayId) {
-            // VR virtual display will be used to run and render 2D app within a VR experience.
-            return false;
-        }
-        if (!isTrusted()) {
-            // Do not show system decorations on untrusted virtual display.
+        if (shouldNeverShowSystemDecorations()) {
             return false;
         }
         if (mWmService.mDisplayWindowSettings.shouldShowSystemDecorsLocked(this)
@@ -6544,19 +6550,9 @@
             // If keyguard is not locked, the change of flags won't affect activity visibility.
             return;
         }
-        // We might change the visibilities here, so prepare an empty app transition which might be
-        // overridden later if we actually change visibilities.
-        final boolean wasTransitionSet = mAppTransition.isTransitionSet();
-        if (!wasTransitionSet) {
-            prepareAppTransition(TRANSIT_NONE);
-        }
         mRootWindowContainer.ensureActivitiesVisible();
-
-        // If there was a transition set already we don't want to interfere with it as we might be
-        // starting it too early.
-        if (!wasTransitionSet) {
-            executeAppTransition();
-        }
+        // In case there is a visibility change.
+        executeAppTransition();
     }
 
     /**
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index ec5b503f..313b77e 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -67,7 +67,6 @@
 
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_ANIM;
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_SCREEN_ON;
-import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
 import static com.android.server.policy.PhoneWindowManager.TOAST_WINDOW_TIMEOUT;
 import static com.android.server.policy.WindowManagerPolicy.TRANSIT_PREVIEW_DONE;
 import static com.android.server.policy.WindowManagerPolicy.WindowManagerFuncs.LID_ABSENT;
@@ -107,6 +106,7 @@
 import android.view.InsetsFrameProvider;
 import android.view.InsetsSource;
 import android.view.InsetsState;
+import android.view.PrivacyIndicatorBounds;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewDebug;
@@ -119,6 +119,7 @@
 import android.view.WindowManagerGlobal;
 import android.view.accessibility.AccessibilityManager;
 import android.window.ClientWindowFrames;
+import android.window.DesktopExperienceFlags;
 import android.window.DesktopModeFlags;
 
 import com.android.internal.R;
@@ -747,7 +748,7 @@
     }
 
     void updateHasNavigationBarIfNeeded() {
-        if (!enableDisplayContentModeManagement()) {
+        if (!DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
             Slog.e(TAG, "mHasNavigationBar shouldn't be updated when the flag is off.");
         }
 
@@ -1875,7 +1876,7 @@
     }
 
     void notifyDisplayAddSystemDecorations() {
-        if (enableDisplayContentModeManagement()) {
+        if (DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
             final int displayId = getDisplayId();
             final boolean isSystemDecorationsSupported =
                     mDisplayContent.isSystemDecorationsSupported();
@@ -2121,6 +2122,8 @@
         }
 
         private static class Cache {
+            static final int TYPE_REGULAR_BARS = WindowInsets.Type.statusBars()
+                    | WindowInsets.Type.navigationBars();
             /**
              * If {@link #mPreserveId} is this value, it is in the middle of updating display
              * configuration before a transition is started. Then the active cache should be used.
@@ -2130,6 +2133,14 @@
             int mPreserveId;
             boolean mActive;
 
+            /**
+             * When display switches, mRegularBarsInsets will assign to mPreservedInsets, and the
+             * insets sources of previous device state will copy to mRegularBarsInsets.
+             */
+            ArrayList<InsetsSource> mPreservedInsets;
+            ArrayList<InsetsSource> mRegularBarsInsets;
+            PrivacyIndicatorBounds mPrivacyIndicatorBounds;
+
             Cache(DisplayContent dc) {
                 mDecorInsets = new DecorInsets(dc);
             }
@@ -2138,6 +2149,17 @@
                 return mPreserveId == ID_UPDATING_CONFIG || mDecorInsets.mDisplayContent
                         .mTransitionController.inTransition(mPreserveId);
             }
+
+            static ArrayList<InsetsSource> copyRegularBarInsets(InsetsState srcState) {
+                final ArrayList<InsetsSource> state = new ArrayList<>();
+                for (int i = srcState.sourceSize() - 1; i >= 0; i--) {
+                    final InsetsSource source = srcState.sourceAt(i);
+                    if ((source.getType() & TYPE_REGULAR_BARS) != 0) {
+                        state.add(new InsetsSource(source));
+                    }
+                }
+                return state;
+            }
         }
     }
 
@@ -2213,24 +2235,60 @@
     @VisibleForTesting
     void updateCachedDecorInsets() {
         DecorInsets prevCache = null;
+        PrivacyIndicatorBounds privacyIndicatorBounds = null;
         if (mCachedDecorInsets == null) {
             mCachedDecorInsets = new DecorInsets.Cache(mDisplayContent);
         } else {
             prevCache = new DecorInsets(mDisplayContent);
             prevCache.setTo(mCachedDecorInsets.mDecorInsets);
+            privacyIndicatorBounds = mCachedDecorInsets.mPrivacyIndicatorBounds;
+            mCachedDecorInsets.mPreservedInsets = mCachedDecorInsets.mRegularBarsInsets;
         }
         // Set a special id to preserve it before a real id is available from transition.
         mCachedDecorInsets.mPreserveId = DecorInsets.Cache.ID_UPDATING_CONFIG;
         // Cache the current insets.
         mCachedDecorInsets.mDecorInsets.setTo(mDecorInsets);
+        if (com.android.window.flags.Flags.useCachedInsetsForDisplaySwitch()) {
+            mCachedDecorInsets.mRegularBarsInsets = DecorInsets.Cache.copyRegularBarInsets(
+                    mDisplayContent.mDisplayFrames.mInsetsState);
+            mCachedDecorInsets.mPrivacyIndicatorBounds =
+                    mDisplayContent.mCurrentPrivacyIndicatorBounds;
+        } else {
+            mCachedDecorInsets.mRegularBarsInsets = null;
+            mCachedDecorInsets.mPrivacyIndicatorBounds = null;
+        }
         // Switch current to previous cache.
         if (prevCache != null) {
             mDecorInsets.setTo(prevCache);
+            if (privacyIndicatorBounds != null) {
+                mDisplayContent.mCurrentPrivacyIndicatorBounds = privacyIndicatorBounds;
+            }
             mCachedDecorInsets.mActive = true;
         }
     }
 
     /**
+     * This returns a new InsetsState with replacing the insets in target device state when the
+     * display is switching (e.g. fold/unfold). Otherwise, it returns the original state. This is
+     * to avoid dispatching old insets source before the insets providers update new insets.
+     */
+    InsetsState replaceInsetsSourcesIfNeeded(InsetsState originalState, boolean copyState) {
+        if (mCachedDecorInsets == null || mCachedDecorInsets.mPreservedInsets == null
+                || !shouldKeepCurrentDecorInsets()) {
+            return originalState;
+        }
+        final ArrayList<InsetsSource> preservedSources = mCachedDecorInsets.mPreservedInsets;
+        final InsetsState state = copyState ? new InsetsState(originalState) : originalState;
+        for (int i = preservedSources.size() - 1; i >= 0; i--) {
+            final InsetsSource cacheSource = preservedSources.get(i);
+            if (state.peekSource(cacheSource.getId()) != null) {
+                state.addSource(new InsetsSource(cacheSource));
+            }
+        }
+        return state;
+    }
+
+    /**
      * Called after the display configuration is updated according to the physical change. Suppose
      * there should be a display change transition, so associate the cached decor insets with the
      * transition to limit the lifetime of using the cache.
diff --git a/services/core/java/com/android/server/wm/DisplayWindowSettings.java b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
index c6892e9..5657920 100644
--- a/services/core/java/com/android/server/wm/DisplayWindowSettings.java
+++ b/services/core/java/com/android/server/wm/DisplayWindowSettings.java
@@ -23,7 +23,6 @@
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_MOVE_TO_PRIMARY;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
 
-import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
 import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_AUTO;
 import static com.android.server.wm.DisplayContent.FORCE_SCALING_MODE_DISABLED;
 
@@ -37,6 +36,7 @@
 import android.view.Surface;
 import android.view.WindowManager;
 import android.view.WindowManager.DisplayImePolicy;
+import android.window.DesktopExperienceFlags;
 
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.wm.DisplayContent.ForceScalingMode;
@@ -240,6 +240,11 @@
         mSettingsProvider.updateOverrideSettings(displayInfo, overrideSettings);
     }
 
+    /**
+     * Returns {@code true} if either the display is the default display, or the display is allowed
+     * to dynamically add/remove system decorations and the system decorations should be shown on it
+     * currently.
+     */
     boolean shouldShowSystemDecorsLocked(@NonNull DisplayContent dc) {
         if (dc.getDisplayId() == Display.DEFAULT_DISPLAY) {
             // Default display should show system decors.
@@ -255,7 +260,7 @@
         final boolean changed = (shouldShow != shouldShowSystemDecorsLocked(dc));
         setShouldShowSystemDecorsInternalLocked(dc, shouldShow);
 
-        if (enableDisplayContentModeManagement()) {
+        if (DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
             if (dc.isDefaultDisplay || dc.isPrivate() || !changed) {
                 return;
             }
diff --git a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
index f52446f..2cac63c 100644
--- a/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/ImeInsetsSourceProvider.java
@@ -22,7 +22,7 @@
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_IME;
 import static com.android.server.wm.DisplayContent.IME_TARGET_CONTROL;
 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
-import static com.android.server.wm.ImeInsetsSourceProviderProto.IME_TARGET_FROM_IME;
+import static com.android.server.wm.ImeInsetsSourceProviderProto.IME_TARGET_FROM_IME_IDENTIFIER;
 import static com.android.server.wm.ImeInsetsSourceProviderProto.INSETS_SOURCE_PROVIDER;
 import static com.android.server.wm.WindowManagerService.H.UPDATE_MULTI_WINDOW_STACKS;
 
@@ -104,7 +104,8 @@
             if (!mGivenInsetsReady && isServerVisible() && !givenInsetsPending
                     && mControlTarget != null) {
                 ProtoLog.d(WM_DEBUG_IME,
-                        "onPostLayout: IME control ready to be dispatched, ws=%s", ws);
+                        "onPostLayout: IME control ready to be dispatched, controlTarget=%s",
+                        mControlTarget);
                 mGivenInsetsReady = true;
                 ImeTracker.forLogging().onProgress(mStatsToken,
                         ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED);
@@ -115,13 +116,15 @@
                 // If the server visibility didn't change (still visible), and mGivenInsetsReady
                 // is set, we won't call into notifyControlChanged. Therefore, we can reset the
                 // statsToken, if available.
-                ProtoLog.w(WM_DEBUG_IME, "onPostLayout cancel statsToken, ws=%s", ws);
+                ProtoLog.w(WM_DEBUG_IME, "onPostLayout cancel statsToken, controlTarget=%s",
+                        mControlTarget);
                 ImeTracker.forLogging().onCancelled(mStatsToken,
                         ImeTracker.PHASE_WM_POST_LAYOUT_NOTIFY_CONTROLS_CHANGED);
                 mStatsToken = null;
             } else if (wasServerVisible && !isServerVisible()) {
-                ProtoLog.d(WM_DEBUG_IME, "onPostLayout: setImeShowing(false) was: %s, ws=%s",
-                        isImeShowing(), ws);
+                ProtoLog.d(WM_DEBUG_IME,
+                        "onPostLayout: setImeShowing(false) was: %s, controlTarget=%s",
+                        isImeShowing(), mControlTarget);
                 setImeShowing(false);
             }
         }
@@ -774,7 +777,7 @@
         final WindowState imeRequesterWindow =
                 mImeRequester != null ? mImeRequester.getWindow() : null;
         if (imeRequesterWindow != null) {
-            imeRequesterWindow.dumpDebug(proto, IME_TARGET_FROM_IME, logLevel);
+            imeRequesterWindow.writeIdentifierToProto(proto, IME_TARGET_FROM_IME_IDENTIFIER);
         }
         proto.end(token);
     }
diff --git a/services/core/java/com/android/server/wm/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index 2872214..06754c4 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -229,6 +229,7 @@
             state = originalState;
         }
         state = adjustVisibilityForIme(target, state, state == originalState);
+        state = mPolicy.replaceInsetsSourcesIfNeeded(state, state == originalState);
         return adjustInsetsForRoundedCorners(target.mToken, state, state == originalState);
     }
 
diff --git a/services/core/java/com/android/server/wm/InsetsSourceProvider.java b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
index d1585d0..b748902 100644
--- a/services/core/java/com/android/server/wm/InsetsSourceProvider.java
+++ b/services/core/java/com/android/server/wm/InsetsSourceProvider.java
@@ -21,16 +21,16 @@
 import static com.android.server.wm.InsetsSourceProviderProto.CLIENT_VISIBLE;
 import static com.android.server.wm.InsetsSourceProviderProto.CONTROL;
 import static com.android.server.wm.InsetsSourceProviderProto.CONTROLLABLE;
-import static com.android.server.wm.InsetsSourceProviderProto.CONTROL_TARGET;
+import static com.android.server.wm.InsetsSourceProviderProto.CONTROL_TARGET_IDENTIFIER;
 import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL;
-import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL_TARGET;
+import static com.android.server.wm.InsetsSourceProviderProto.FAKE_CONTROL_TARGET_IDENTIFIER;
 import static com.android.server.wm.InsetsSourceProviderProto.FRAME;
 import static com.android.server.wm.InsetsSourceProviderProto.IS_LEASH_READY_FOR_DISPATCHING;
-import static com.android.server.wm.InsetsSourceProviderProto.PENDING_CONTROL_TARGET;
+import static com.android.server.wm.InsetsSourceProviderProto.PENDING_CONTROL_TARGET_IDENTIFIER;
 import static com.android.server.wm.InsetsSourceProviderProto.SEAMLESS_ROTATING;
 import static com.android.server.wm.InsetsSourceProviderProto.SERVER_VISIBLE;
 import static com.android.server.wm.InsetsSourceProviderProto.SOURCE;
-import static com.android.server.wm.InsetsSourceProviderProto.SOURCE_WINDOW_STATE;
+import static com.android.server.wm.InsetsSourceProviderProto.SOURCE_WINDOW_STATE_IDENTIFIER;
 import static com.android.server.wm.SurfaceAnimator.ANIMATION_TYPE_INSETS_CONTROL;
 
 import android.annotation.NonNull;
@@ -803,14 +803,16 @@
             mControl.dumpDebug(proto, CONTROL);
         }
         if (mControlTarget != null && mControlTarget.getWindow() != null) {
-            mControlTarget.getWindow().dumpDebug(proto, CONTROL_TARGET, logLevel);
+            mControlTarget.getWindow().writeIdentifierToProto(proto, CONTROL_TARGET_IDENTIFIER);
         }
         if (mPendingControlTarget != null && mPendingControlTarget != mControlTarget
                 && mPendingControlTarget.getWindow() != null) {
-            mPendingControlTarget.getWindow().dumpDebug(proto, PENDING_CONTROL_TARGET, logLevel);
+            mPendingControlTarget.getWindow().writeIdentifierToProto(
+                    proto, PENDING_CONTROL_TARGET_IDENTIFIER);
         }
         if (mFakeControlTarget != null && mFakeControlTarget.getWindow() != null) {
-            mFakeControlTarget.getWindow().dumpDebug(proto, FAKE_CONTROL_TARGET, logLevel);
+            mFakeControlTarget.getWindow().writeIdentifierToProto(
+                    proto, FAKE_CONTROL_TARGET_IDENTIFIER);
         }
         if (mAdapter != null && mAdapter.mCapturedLeash != null) {
             mAdapter.mCapturedLeash.dumpDebug(proto, CAPTURED_LEASH);
@@ -821,7 +823,8 @@
         proto.write(SEAMLESS_ROTATING, mSeamlessRotating);
         proto.write(CONTROLLABLE, mControllable);
         if (mWindowContainer != null && mWindowContainer.asWindowState() != null) {
-            mWindowContainer.asWindowState().dumpDebug(proto, SOURCE_WINDOW_STATE, logLevel);
+            mWindowContainer.asWindowState().writeIdentifierToProto(
+                    proto, SOURCE_WINDOW_STATE_IDENTIFIER);
         }
         proto.end(token);
     }
diff --git a/services/core/java/com/android/server/wm/KeyguardController.java b/services/core/java/com/android/server/wm/KeyguardController.java
index 4eeed5e..ff1e400 100644
--- a/services/core/java/com/android/server/wm/KeyguardController.java
+++ b/services/core/java/com/android/server/wm/KeyguardController.java
@@ -28,7 +28,6 @@
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_OCCLUDING;
 import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_UNOCCLUDING;
-import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_OCCLUDE;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_OPEN;
@@ -310,7 +309,6 @@
             state.writeEventLog("keyguardGoingAway");
             final int transitFlags = convertTransitFlags(flags);
             final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
-            dc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, transitFlags);
             // We are deprecating TRANSIT_KEYGUARD_GOING_AWAY for Shell transition and use
             // TRANSIT_FLAG_KEYGUARD_GOING_AWAY to indicate that it should animate keyguard going
             // away.
@@ -490,8 +488,6 @@
                     if (trigger != null) {
                         transition.collect(trigger);
                     }
-                } else {
-                    dc.prepareAppTransition(transitType, transitFlags);
                 }
             } else {
                 if (tc.inTransition()) {
@@ -515,7 +511,6 @@
     private void handleDismissInsecureKeyguard(DisplayContent dc) {
         mService.deferWindowLayout();
         try {
-            dc.prepareAppTransition(TRANSIT_KEYGUARD_GOING_AWAY, 0 /* transitFlags */);
             // We are deprecating TRANSIT_KEYGUARD_GOING_AWAY for Shell transition and use
             // TRANSIT_FLAG_KEYGUARD_GOING_AWAY to indicate that it should animate keyguard going
             // away.
@@ -542,14 +537,6 @@
         mWindowManager.dismissKeyguard(null /* callback */, null /* message */);
         final KeyguardDisplayState state = getDisplayState(displayId);
         state.mDismissalRequested = true;
-
-        // If we are about to unocclude the Keyguard, but we can dismiss it without security,
-        // we immediately dismiss the Keyguard so the activity gets shown without a flicker.
-        final DisplayContent dc = mRootWindowContainer.getDefaultDisplay();
-        if (state.mKeyguardShowing && canDismissKeyguard()
-                && dc.mAppTransition.containsTransitRequest(TRANSIT_KEYGUARD_UNOCCLUDE)) {
-            mWindowManager.executeAppTransition();
-        }
     }
 
     ActivityRecord getTopOccludingActivity(int displayId) {
diff --git a/services/core/java/com/android/server/wm/Letterbox.java b/services/core/java/com/android/server/wm/Letterbox.java
index 29c0c7b..3a4d2ca 100644
--- a/services/core/java/com/android/server/wm/Letterbox.java
+++ b/services/core/java/com/android/server/wm/Letterbox.java
@@ -54,7 +54,6 @@
 
     private final Supplier<SurfaceControl.Builder> mSurfaceControlFactory;
     private final Supplier<SurfaceControl.Transaction> mTransactionFactory;
-    private final Supplier<SurfaceControl> mParentSurfaceSupplier;
 
     private final Rect mOuter = new Rect();
     private final Rect mInner = new Rect();
@@ -83,13 +82,11 @@
     public Letterbox(Supplier<SurfaceControl.Builder> surfaceControlFactory,
             Supplier<SurfaceControl.Transaction> transactionFactory,
             @NonNull AppCompatReachabilityPolicy appCompatReachabilityPolicy,
-            @NonNull AppCompatLetterboxOverrides appCompatLetterboxOverrides,
-            Supplier<SurfaceControl> parentSurface) {
+            @NonNull AppCompatLetterboxOverrides appCompatLetterboxOverrides) {
         mSurfaceControlFactory = surfaceControlFactory;
         mTransactionFactory = transactionFactory;
         mAppCompatReachabilityPolicy = appCompatReachabilityPolicy;
         mAppCompatLetterboxOverrides = appCompatLetterboxOverrides;
-        mParentSurfaceSupplier = parentSurface;
     }
 
     /**
@@ -343,7 +340,6 @@
         private SurfaceControl mInputSurface;
         private Color mColor;
         private boolean mHasWallpaperBackground;
-        private SurfaceControl mParentSurface;
 
         private final Rect mSurfaceFrameRelative = new Rect();
         private final Rect mLayoutFrameGlobal = new Rect();
@@ -437,9 +433,8 @@
                 }
 
                 mColor = mAppCompatLetterboxOverrides.getLetterboxBackgroundColor();
-                mParentSurface = mParentSurfaceSupplier.get();
                 t.setColor(mSurface, getRgbColorArray());
-                setPositionAndReparent(t, mSurface);
+                setPositionAndCrop(t, mSurface);
 
                 mHasWallpaperBackground = mAppCompatLetterboxOverrides
                         .hasWallpaperBackgroundForLetterbox();
@@ -448,7 +443,7 @@
                 t.show(mSurface);
 
                 if (mInputSurface != null) {
-                    setPositionAndReparent(inputT, mInputSurface);
+                    setPositionAndCrop(inputT, mInputSurface);
                     inputT.setTrustedOverlay(mInputSurface, true);
                     inputT.show(mInputSurface);
                 }
@@ -470,12 +465,11 @@
             }
         }
 
-        private void setPositionAndReparent(@NonNull SurfaceControl.Transaction t,
+        private void setPositionAndCrop(@NonNull SurfaceControl.Transaction t,
                 @NonNull SurfaceControl surface) {
             t.setPosition(surface, mSurfaceFrameRelative.left, mSurfaceFrameRelative.top);
             t.setWindowCrop(surface, mSurfaceFrameRelative.width(),
                     mSurfaceFrameRelative.height());
-            t.reparent(surface, mParentSurface);
         }
 
         private void updateAlphaAndBlur(SurfaceControl.Transaction t) {
@@ -511,14 +505,13 @@
 
         public boolean needsApplySurfaceChanges() {
             return !mSurfaceFrameRelative.equals(mLayoutFrameRelative)
-                    // If mSurfaceFrameRelative is empty then mHasWallpaperBackground, mColor,
-                    // and mParentSurface may never be updated in applySurfaceChanges but this
-                    // doesn't mean that update is needed.
+                    // If mSurfaceFrameRelative is empty, then mHasWallpaperBackground and mColor
+                    // may never be updated in applySurfaceChanges but this doesn't mean that
+                    // update is needed.
                     || !mSurfaceFrameRelative.isEmpty()
                     && (mAppCompatLetterboxOverrides.hasWallpaperBackgroundForLetterbox()
                         != mHasWallpaperBackground
-                    || !mAppCompatLetterboxOverrides.getLetterboxBackgroundColor().equals(mColor)
-                    || mParentSurfaceSupplier.get() != mParentSurface);
+                    || !mAppCompatLetterboxOverrides.getLetterboxBackgroundColor().equals(mColor));
         }
     }
 }
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index e864ecf..cf201c9 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -36,6 +36,7 @@
 import static android.view.WindowManager.TRANSIT_PIP;
 import static android.view.WindowManager.TRANSIT_SLEEP;
 import static android.view.WindowManager.TRANSIT_WAKE;
+import static android.window.DesktopExperienceFlags.ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT;
 
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_FOCUS_LIGHT;
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_KEEP_SCREEN_ON;
@@ -45,7 +46,6 @@
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_TASKS;
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WALLPAPER;
 import static com.android.internal.protolog.WmProtoLogGroups.WM_SHOW_SURFACE_ALLOC;
-import static com.android.server.display.feature.flags.Flags.enableDisplayContentModeManagement;
 import static com.android.server.policy.PhoneWindowManager.SYSTEM_DIALOG_REASON_ASSIST;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -1371,7 +1371,8 @@
         // When display content mode management flag is enabled, the task display area is marked as
         // removed when switching from extended display to mirroring display. We need to restart the
         // task display area before starting the home.
-        if (enableDisplayContentModeManagement() && taskDisplayArea.shouldKeepNoTask()) {
+        if (ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()
+                && taskDisplayArea.shouldKeepNoTask()) {
             taskDisplayArea.setShouldKeepNoTask(false);
         }
 
@@ -2771,10 +2772,17 @@
                 return;
             }
 
-            if (enableDisplayContentModeManagement() && display.allowContentModeSwitch()) {
-                mWindowManager.mDisplayWindowSettings
-                        .setShouldShowSystemDecorsInternalLocked(display,
-                                display.mDisplay.canHostTasks());
+            if (ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
+                if (display.allowContentModeSwitch()) {
+                    mWindowManager.mDisplayWindowSettings
+                            .setShouldShowSystemDecorsInternalLocked(display,
+                                    display.mDisplay.canHostTasks());
+                }
+
+                final boolean inTopology = mWindowManager.mDisplayWindowSettings
+                        .shouldShowSystemDecorsLocked(display);
+                mWmService.mDisplayManagerInternal.onDisplayBelongToTopologyChanged(displayId,
+                        inTopology);
             }
 
             startSystemDecorations(display, "displayAdded");
@@ -2823,7 +2831,7 @@
                 displayContent.requestDisplayUpdate(
                         () -> {
                             clearDisplayInfoCaches(displayId);
-                            if (enableDisplayContentModeManagement()) {
+                            if (ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT.isTrue()) {
                                 displayContent.onDisplayInfoChangeApplied();
                             }
                         });
diff --git a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
index bbc35a3..fba29d4 100644
--- a/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
+++ b/services/core/java/com/android/server/wm/SurfaceAnimationRunner.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.os.Trace.TRACE_TAG_WINDOW_MANAGER;
 import static android.util.TimeUtils.NANOS_PER_MS;
 import static android.view.Choreographer.CALLBACK_TRAVERSAL;
 import static android.view.Choreographer.getSfInstance;
@@ -27,25 +26,13 @@
 import android.animation.AnimatorListenerAdapter;
 import android.animation.ValueAnimator;
 import android.annotation.Nullable;
-import android.graphics.BitmapShader;
-import android.graphics.Canvas;
-import android.graphics.Insets;
-import android.graphics.Paint;
-import android.graphics.PixelFormat;
-import android.graphics.Rect;
 import android.hardware.power.Boost;
 import android.os.Handler;
 import android.os.PowerManagerInternal;
-import android.os.Trace;
 import android.util.ArrayMap;
-import android.util.Log;
 import android.view.Choreographer;
-import android.view.Surface;
 import android.view.SurfaceControl;
 import android.view.SurfaceControl.Transaction;
-import android.view.animation.Animation;
-import android.view.animation.Transformation;
-import android.window.ScreenCapture;
 
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.annotations.VisibleForTesting;
@@ -53,9 +40,6 @@
 import com.android.server.AnimationThread;
 import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
 
-import java.util.ArrayList;
-import java.util.concurrent.ExecutorService;
-import java.util.concurrent.Executors;
 import java.util.function.Supplier;
 
 /**
@@ -73,12 +57,6 @@
      */
     private final Object mCancelLock = new Object();
 
-    /**
-     * Lock for synchronizing {@link #mEdgeExtensions} to prevent race conditions when managing
-     * created edge extension surfaces.
-     */
-    private final Object mEdgeExtensionLock = new Object();
-
     @VisibleForTesting
     Choreographer mChoreographer;
 
@@ -91,12 +69,6 @@
     private final PowerManagerInternal mPowerManagerInternal;
     private boolean mApplyScheduled;
 
-    // Executor to perform the edge extension.
-    // With two threads because in practice we will want to extend two surfaces in one animation,
-    // in which case we want to be able to parallelize those two extensions to cut down latency in
-    // starting the animation.
-    private final ExecutorService mEdgeExtensionExecutor = Executors.newFixedThreadPool(2);
-
     @GuardedBy("mLock")
     @VisibleForTesting
     final ArrayMap<SurfaceControl, RunningAnimation> mPendingAnimations = new ArrayMap<>();
@@ -112,11 +84,6 @@
     @GuardedBy("mLock")
     private boolean mAnimationStartDeferred;
 
-    // Mapping animation leashes to a list of edge extension surfaces associated with them
-    @GuardedBy("mEdgeExtensionLock")
-    private final ArrayMap<SurfaceControl, ArrayList<SurfaceControl>> mEdgeExtensions =
-            new ArrayMap<>();
-
     /**
      * There should only ever be one instance of this class. Usual spot for it is with
      * {@link WindowManagerService}
@@ -175,64 +142,9 @@
         synchronized (mLock) {
             final RunningAnimation runningAnim = new RunningAnimation(a, animationLeash,
                     finishCallback);
-            boolean requiresEdgeExtension = requiresEdgeExtension(a);
-
-            if (requiresEdgeExtension) {
-                final ArrayList<SurfaceControl> extensionSurfaces = new ArrayList<>();
-                synchronized (mEdgeExtensionLock) {
-                    mEdgeExtensions.put(animationLeash, extensionSurfaces);
-                }
-
-                mPreProcessingAnimations.put(animationLeash, runningAnim);
-
-                // We must wait for t to be committed since otherwise the leash doesn't have the
-                // windows we want to screenshot and extend as children.
-                t.addTransactionCommittedListener(mEdgeExtensionExecutor, () -> {
-                    if (!animationLeash.isValid()) {
-                        Log.e(TAG, "Animation leash is not valid");
-                        synchronized (mEdgeExtensionLock) {
-                            mEdgeExtensions.remove(animationLeash);
-                        }
-                        synchronized (mLock) {
-                            mPreProcessingAnimations.remove(animationLeash);
-                        }
-                        return;
-                    }
-                    final WindowAnimationSpec animationSpec = a.asWindowAnimationSpec();
-
-                    final Transaction edgeExtensionCreationTransaction = new Transaction();
-                    edgeExtendWindow(animationLeash,
-                            animationSpec.getRootTaskBounds(), animationSpec.getAnimation(),
-                            edgeExtensionCreationTransaction);
-
-                    synchronized (mLock) {
-                        // only run if animation is not yet canceled by this point
-                        if (mPreProcessingAnimations.get(animationLeash) == runningAnim) {
-                            // In the case the animation is cancelled, edge extensions are removed
-                            // onAnimationLeashLost which is called before onAnimationCancelled.
-                            // So we need to check if the edge extensions have already been removed
-                            // or not, and if so we don't want to apply the transaction.
-                            synchronized (mEdgeExtensionLock) {
-                                if (!mEdgeExtensions.isEmpty()) {
-                                    edgeExtensionCreationTransaction.apply();
-                                }
-                            }
-
-                            mPreProcessingAnimations.remove(animationLeash);
-                            mPendingAnimations.put(animationLeash, runningAnim);
-                            if (!mAnimationStartDeferred && mPreProcessingAnimations.isEmpty()) {
-                                mChoreographer.postFrameCallback(this::startAnimations);
-                            }
-                        }
-                    }
-                });
-            }
-
-            if (!requiresEdgeExtension) {
-                mPendingAnimations.put(animationLeash, runningAnim);
-                if (!mAnimationStartDeferred && mPreProcessingAnimations.isEmpty()) {
-                    mChoreographer.postFrameCallback(this::startAnimations);
-                }
+            mPendingAnimations.put(animationLeash, runningAnim);
+            if (!mAnimationStartDeferred && mPreProcessingAnimations.isEmpty()) {
+                mChoreographer.postFrameCallback(this::startAnimations);
             }
 
             // Some animations (e.g. move animations) require the initial transform to be
@@ -241,10 +153,6 @@
         }
     }
 
-    private boolean requiresEdgeExtension(AnimationSpec a) {
-        return a.asWindowAnimationSpec() != null && a.asWindowAnimationSpec().hasExtension();
-    }
-
     void onAnimationCancelled(SurfaceControl leash) {
         synchronized (mLock) {
             if (mPendingAnimations.containsKey(leash)) {
@@ -374,161 +282,6 @@
         mApplyScheduled = false;
     }
 
-    private void edgeExtendWindow(SurfaceControl leash, Rect bounds, Animation a,
-            Transaction transaction) {
-        final Transformation transformationAtStart = new Transformation();
-        a.getTransformationAt(0, transformationAtStart);
-        final Transformation transformationAtEnd = new Transformation();
-        a.getTransformationAt(1, transformationAtEnd);
-
-        // We want to create an extension surface that is the maximal size and the animation will
-        // take care of cropping any part that overflows.
-        final Insets maxExtensionInsets = Insets.min(
-                transformationAtStart.getInsets(), transformationAtEnd.getInsets());
-
-        final int targetSurfaceHeight = bounds.height();
-        final int targetSurfaceWidth = bounds.width();
-
-        if (maxExtensionInsets.left < 0) {
-            final Rect edgeBounds = new Rect(bounds.left, bounds.top, bounds.left + 1,
-                    bounds.bottom);
-            final Rect extensionRect = new Rect(0, 0,
-                    -maxExtensionInsets.left, targetSurfaceHeight);
-            final int xPos = bounds.left + maxExtensionInsets.left;
-            final int yPos = bounds.top;
-            createExtensionSurface(leash, edgeBounds,
-                    extensionRect, xPos, yPos, "Left Edge Extension", transaction);
-        }
-
-        if (maxExtensionInsets.top < 0) {
-            final Rect edgeBounds = new Rect(bounds.left, bounds.top, targetSurfaceWidth,
-                    bounds.top + 1);
-            final Rect extensionRect = new Rect(0, 0,
-                    targetSurfaceWidth, -maxExtensionInsets.top);
-            final int xPos = bounds.left;
-            final int yPos = bounds.top + maxExtensionInsets.top;
-            createExtensionSurface(leash, edgeBounds,
-                    extensionRect, xPos, yPos, "Top Edge Extension", transaction);
-        }
-
-        if (maxExtensionInsets.right < 0) {
-            final Rect edgeBounds = new Rect(bounds.right - 1, bounds.top, bounds.right,
-                    bounds.bottom);
-            final Rect extensionRect = new Rect(0, 0,
-                    -maxExtensionInsets.right, targetSurfaceHeight);
-            final int xPos = bounds.right;
-            final int yPos = bounds.top;
-            createExtensionSurface(leash, edgeBounds,
-                    extensionRect, xPos, yPos, "Right Edge Extension", transaction);
-        }
-
-        if (maxExtensionInsets.bottom < 0) {
-            final Rect edgeBounds = new Rect(bounds.left, bounds.bottom - 1,
-                    bounds.right, bounds.bottom);
-            final Rect extensionRect = new Rect(0, 0,
-                    targetSurfaceWidth, -maxExtensionInsets.bottom);
-            final int xPos = bounds.left;
-            final int yPos = bounds.bottom;
-            createExtensionSurface(leash, edgeBounds,
-                    extensionRect, xPos, yPos, "Bottom Edge Extension", transaction);
-        }
-    }
-
-    private void createExtensionSurface(SurfaceControl leash, Rect edgeBounds,
-            Rect extensionRect, int xPos, int yPos, String layerName,
-            Transaction startTransaction) {
-        Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "createExtensionSurface");
-        doCreateExtensionSurface(leash, edgeBounds, extensionRect, xPos, yPos, layerName,
-                startTransaction);
-        Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
-    }
-
-    private void doCreateExtensionSurface(SurfaceControl leash, Rect edgeBounds,
-            Rect extensionRect, int xPos, int yPos, String layerName,
-            Transaction startTransaction) {
-        ScreenCapture.LayerCaptureArgs captureArgs =
-                new ScreenCapture.LayerCaptureArgs.Builder(leash /* surfaceToExtend */)
-                        .setSourceCrop(edgeBounds)
-                        .setFrameScale(1)
-                        .setPixelFormat(PixelFormat.RGBA_8888)
-                        .setChildrenOnly(true)
-                        .setAllowProtected(true)
-                        .setCaptureSecureLayers(true)
-                        .build();
-        final ScreenCapture.ScreenshotHardwareBuffer edgeBuffer =
-                ScreenCapture.captureLayers(captureArgs);
-
-        if (edgeBuffer == null) {
-            // The leash we are trying to screenshot may have been removed by this point, which is
-            // likely the reason for ending up with a null edgeBuffer, in which case we just want to
-            // return and do nothing.
-            Log.e(TAG, "Failed to create edge extension - edge buffer is null");
-            return;
-        }
-
-        final SurfaceControl edgeExtensionLayer = new SurfaceControl.Builder()
-                .setName(layerName)
-                .setHidden(true)
-                .setCallsite("DefaultTransitionHandler#startAnimation")
-                .setOpaque(true)
-                .setBufferSize(extensionRect.width(), extensionRect.height())
-                .build();
-
-        BitmapShader shader = new BitmapShader(edgeBuffer.asBitmap(),
-                android.graphics.Shader.TileMode.CLAMP,
-                android.graphics.Shader.TileMode.CLAMP);
-        final Paint paint = new Paint();
-        paint.setShader(shader);
-
-        final Surface surface = new Surface(edgeExtensionLayer);
-        Canvas c = surface.lockHardwareCanvas();
-        c.drawRect(extensionRect, paint);
-        surface.unlockCanvasAndPost(c);
-        surface.release();
-
-        synchronized (mEdgeExtensionLock) {
-            if (!mEdgeExtensions.containsKey(leash)) {
-                // The animation leash has already been removed, so we don't want to attach the
-                // edgeExtension layer and should immediately remove it instead.
-                startTransaction.remove(edgeExtensionLayer);
-                return;
-            }
-
-            startTransaction.reparent(edgeExtensionLayer, leash);
-            startTransaction.setLayer(edgeExtensionLayer, Integer.MIN_VALUE);
-            startTransaction.setPosition(edgeExtensionLayer, xPos, yPos);
-            startTransaction.setVisibility(edgeExtensionLayer, true);
-
-            mEdgeExtensions.get(leash).add(edgeExtensionLayer);
-        }
-    }
-
-    private float getScaleXForExtensionSurface(Rect edgeBounds, Rect extensionRect) {
-        if (edgeBounds.width() == extensionRect.width()) {
-            // Top or bottom edge extension, no need to scale the X axis of the extension surface.
-            return 1;
-        }
-        if (edgeBounds.width() == 1) {
-            // Left or right edge extension, scale the surface to be the extensionRect's width.
-            return extensionRect.width();
-        }
-
-        throw new RuntimeException("Unexpected edgeBounds and extensionRect widths");
-    }
-
-    private float getScaleYForExtensionSurface(Rect edgeBounds, Rect extensionRect) {
-        if (edgeBounds.height() == extensionRect.height()) {
-            // Left or right edge extension, no need to scale the Y axis of the extension surface.
-            return 1;
-        }
-        if (edgeBounds.height() == 1) {
-            // Top or bottom edge extension, scale the surface to be the extensionRect's height.
-            return extensionRect.height();
-        }
-
-        throw new RuntimeException("Unexpected edgeBounds and extensionRect heights");
-    }
-
     private static final class RunningAnimation {
         final AnimationSpec mAnimSpec;
         final SurfaceControl mLeash;
@@ -545,22 +298,6 @@
         }
     }
 
-    protected void onAnimationLeashLost(SurfaceControl animationLeash,
-            Transaction t) {
-        synchronized (mEdgeExtensionLock) {
-            if (!mEdgeExtensions.containsKey(animationLeash)) {
-                return;
-            }
-
-            final ArrayList<SurfaceControl> edgeExtensions = mEdgeExtensions.get(animationLeash);
-            for (int i = 0; i < edgeExtensions.size(); i++) {
-                final SurfaceControl extension = edgeExtensions.get(i);
-                t.remove(extension);
-            }
-            mEdgeExtensions.remove(animationLeash);
-        }
-    }
-
     @VisibleForTesting
     interface AnimatorFactory {
         ValueAnimator makeAnimator();
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 22f0278..d16c301 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4497,7 +4497,7 @@
     }
 
     void onPictureInPictureParamsChanged() {
-        if (inPinnedWindowingMode() || Flags.enableDesktopWindowingPip()) {
+        if (inPinnedWindowingMode() || DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PIP.isTrue()) {
             dispatchTaskInfoChangedIfNeeded(true /* force */);
         }
     }
diff --git a/services/core/java/com/android/server/wm/TaskFragment.java b/services/core/java/com/android/server/wm/TaskFragment.java
index f95698a..5183c6b 100644
--- a/services/core/java/com/android/server/wm/TaskFragment.java
+++ b/services/core/java/com/android/server/wm/TaskFragment.java
@@ -88,6 +88,7 @@
 import android.graphics.Point;
 import android.graphics.Rect;
 import android.os.IBinder;
+import android.os.RemoteException;
 import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.DisplayMetrics;
@@ -1751,67 +1752,80 @@
                 }
             }
 
-            try {
-                final IApplicationThread appThread = next.app.getThread();
-                // Deliver all pending results.
-                final ArrayList<ResultInfo> a = next.results;
-                if (a != null) {
-                    final int size = a.size();
-                    if (!next.finishing && size > 0) {
-                        if (DEBUG_RESULTS) {
-                            Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a);
-                        }
-                        final ActivityResultItem item = new ActivityResultItem(next.token, a);
-                        mAtmService.getLifecycleManager().scheduleTransactionItem(appThread, item);
+            final IApplicationThread appThread = next.app.getThread();
+            // Deliver all pending results.
+            final ArrayList<ResultInfo> a = next.results;
+            if (a != null) {
+                final int size = a.size();
+                if (!next.finishing && size > 0) {
+                    if (DEBUG_RESULTS) {
+                        Slog.v(TAG_RESULTS, "Delivering results to " + next + ": " + a);
+                    }
+                    final ActivityResultItem item = new ActivityResultItem(next.token, a);
+                    boolean isSuccessful;
+                    try {
+                        isSuccessful = mAtmService.getLifecycleManager().scheduleTransactionItem(
+                                appThread, item);
+                    } catch (RemoteException e) {
+                        // TODO(b/323801078): remove Exception when cleanup
+                        isSuccessful = false;
+                    }
+                    if (!isSuccessful) {
+                        onResumeTopActivityRemoteFailure(lastState, next, lastResumedActivity,
+                                lastFocusedRootTask);
+                        return true;
                     }
                 }
+            }
 
-                if (next.newIntents != null) {
-                    final NewIntentItem item =
-                            new NewIntentItem(next.token, next.newIntents, true /* resume */);
-                    mAtmService.getLifecycleManager().scheduleTransactionItem(appThread, item);
+            if (next.newIntents != null) {
+                final NewIntentItem item =
+                        new NewIntentItem(next.token, next.newIntents, true /* resume */);
+                boolean isSuccessful;
+                try {
+                    isSuccessful = mAtmService.getLifecycleManager().scheduleTransactionItem(
+                            appThread, item);
+                } catch (RemoteException e) {
+                    // TODO(b/323801078): remove Exception when cleanup
+                    isSuccessful = false;
                 }
+                if (!isSuccessful) {
+                    onResumeTopActivityRemoteFailure(lastState, next, lastResumedActivity,
+                            lastFocusedRootTask);
+                    return true;
+                }
+            }
 
-                // Well the app will no longer be stopped.
-                // Clear app token stopped state in window manager if needed.
-                next.notifyAppResumed();
+            // Well the app will no longer be stopped.
+            // Clear app token stopped state in window manager if needed.
+            next.notifyAppResumed();
 
-                EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
-                        next.getTask().mTaskId, next.shortComponentName);
+            EventLogTags.writeWmResumeActivity(next.mUserId, System.identityHashCode(next),
+                    next.getTask().mTaskId, next.shortComponentName);
 
-                mAtmService.getAppWarningsLocked().onResumeActivity(next);
-                final int topProcessState = mAtmService.mTopProcessState;
-                next.app.setPendingUiCleanAndForceProcessStateUpTo(topProcessState);
-                next.abortAndClearOptionsAnimation();
-                final ResumeActivityItem resumeActivityItem = new ResumeActivityItem(
-                        next.token, topProcessState, dc.isNextTransitionForward(),
-                        next.shouldSendCompatFakeFocus());
-                mAtmService.getLifecycleManager().scheduleTransactionItem(
+            mAtmService.getAppWarningsLocked().onResumeActivity(next);
+            final int topProcessState = mAtmService.mTopProcessState;
+            next.app.setPendingUiCleanAndForceProcessStateUpTo(topProcessState);
+            next.abortAndClearOptionsAnimation();
+            final ResumeActivityItem resumeActivityItem = new ResumeActivityItem(
+                    next.token, topProcessState, dc.isNextTransitionForward(),
+                    next.shouldSendCompatFakeFocus());
+            boolean isSuccessful;
+            try {
+                isSuccessful = mAtmService.getLifecycleManager().scheduleTransactionItem(
                         appThread, resumeActivityItem);
-
-                ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Resumed %s", next);
-            } catch (Exception e) {
-                // Whoops, need to restart this activity!
-                ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: "
-                        + "%s", lastState, next);
-                next.setState(lastState, "resumeTopActivityInnerLocked");
-
-                // lastResumedActivity being non-null implies there is a lastStack present.
-                if (lastResumedActivity != null) {
-                    lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
-                }
-
-                Slog.i(TAG, "Restarting because process died: " + next);
-                if (!next.hasBeenLaunched) {
-                    next.hasBeenLaunched = true;
-                } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null
-                        && lastFocusedRootTask.isTopRootTaskInDisplayArea()) {
-                    next.showStartingWindow(false /* taskSwitch */);
-                }
-                mTaskSupervisor.startSpecificActivity(next, true, false);
+            } catch (RemoteException e) {
+                // TODO(b/323801078): remove Exception when cleanup
+                isSuccessful = false;
+            }
+            if (!isSuccessful) {
+                onResumeTopActivityRemoteFailure(lastState, next, lastResumedActivity,
+                        lastFocusedRootTask);
                 return true;
             }
 
+            ProtoLog.d(WM_DEBUG_STATES, "resumeTopActivity: Resumed %s", next);
+
             next.completeResumeLocked();
         } else {
             // Whoops, need to restart this activity!
@@ -1830,6 +1844,29 @@
         return true;
     }
 
+    /** Likely app process has been killed. Needs to restart this activity. */
+    private void onResumeTopActivityRemoteFailure(@NonNull ActivityRecord.State lastState,
+            @NonNull ActivityRecord next, @Nullable ActivityRecord lastResumedActivity,
+            @Nullable Task lastFocusedRootTask) {
+        ProtoLog.v(WM_DEBUG_STATES, "Resume failed; resetting state to %s: "
+                + "%s", lastState, next);
+        next.setState(lastState, "resumeTopActivityInnerLocked");
+
+        // lastResumedActivity being non-null implies there is a lastStack present.
+        if (lastResumedActivity != null) {
+            lastResumedActivity.setState(RESUMED, "resumeTopActivityInnerLocked");
+        }
+
+        Slog.i(TAG, "Restarting because process died: " + next);
+        if (!next.hasBeenLaunched) {
+            next.hasBeenLaunched = true;
+        } else if (SHOW_APP_STARTING_PREVIEW && lastFocusedRootTask != null
+                && lastFocusedRootTask.isTopRootTaskInDisplayArea()) {
+            next.showStartingWindow(false /* taskSwitch */);
+        }
+        mTaskSupervisor.startSpecificActivity(next, true, false);
+    }
+
     boolean shouldSleepOrShutDownActivities() {
         return shouldSleepActivities() || mAtmService.mShuttingDown;
     }
@@ -2034,17 +2071,23 @@
     void schedulePauseActivity(ActivityRecord prev, boolean userLeaving,
             boolean pauseImmediately, boolean autoEnteringPip, String reason) {
         ProtoLog.v(WM_DEBUG_STATES, "Enqueueing pending pause: %s", prev);
-        try {
-            prev.mPauseSchedulePendingForPip = false;
-            EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
-                    prev.shortComponentName, "userLeaving=" + userLeaving, reason);
+        prev.mPauseSchedulePendingForPip = false;
+        EventLogTags.writeWmPauseActivity(prev.mUserId, System.identityHashCode(prev),
+                prev.shortComponentName, "userLeaving=" + userLeaving, reason);
 
-            final PauseActivityItem item = new PauseActivityItem(prev.token, prev.finishing,
-                    userLeaving, pauseImmediately, autoEnteringPip);
-            mAtmService.getLifecycleManager().scheduleTransactionItem(prev.app.getThread(), item);
-        } catch (Exception e) {
+        final PauseActivityItem item = new PauseActivityItem(prev.token, prev.finishing,
+                userLeaving, pauseImmediately, autoEnteringPip);
+        boolean isSuccessful;
+        try {
+            isSuccessful = mAtmService.getLifecycleManager().scheduleTransactionItem(
+                    prev.app.getThread(), item);
+        } catch (RemoteException e) {
+            // TODO(b/323801078): remove Exception when cleanup
             // Ignore exception, if process died other code will cleanup.
             Slog.w(TAG, "Exception thrown during pause", e);
+            isSuccessful = false;
+        }
+        if (!isSuccessful) {
             mPausingActivity = null;
             mLastPausedActivity = null;
             mTaskSupervisor.mNoHistoryActivities.remove(prev);
diff --git a/services/core/java/com/android/server/wm/ViewServer.java b/services/core/java/com/android/server/wm/ViewServer.java
index ecf5652..971e6f9 100644
--- a/services/core/java/com/android/server/wm/ViewServer.java
+++ b/services/core/java/com/android/server/wm/ViewServer.java
@@ -19,7 +19,10 @@
 
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
+import static com.android.server.wm.WindowManagerInternal.WindowFocusChangeListener;
+import static com.android.server.wm.WindowManagerService.WindowChangeListener;
 
+import android.os.IBinder;
 import android.util.Slog;
 
 import java.net.ServerSocket;
@@ -206,7 +209,7 @@
         return result;
     }
 
-    class ViewServerWorker implements Runnable, WindowManagerService.WindowChangeListener {
+    class ViewServerWorker implements Runnable, WindowChangeListener, WindowFocusChangeListener {
         private Socket mClient;
         private boolean mNeedWindowListUpdate;
         private boolean mNeedFocusedWindowUpdate;
@@ -284,7 +287,7 @@
             }
         }
 
-        public void focusChanged() {
+        public void focusChanged(IBinder focusedWindowToken) {
             synchronized(this) {
                 mNeedFocusedWindowUpdate = true;
                 notifyAll();
@@ -293,6 +296,7 @@
 
         private boolean windowManagerAutolistLoop() {
             mWindowManager.addWindowChangeListener(this);
+            mWindowManager.addWindowFocusChangeListener(this);
             BufferedWriter out = null;
             try {
                 out = new BufferedWriter(new OutputStreamWriter(mClient.getOutputStream()));
@@ -332,6 +336,7 @@
                     }
                 }
                 mWindowManager.removeWindowChangeListener(this);
+                mWindowManager.removeWindowFocusChangeListener(this);
             }
             return true;
         }
diff --git a/services/core/java/com/android/server/wm/WallpaperController.java b/services/core/java/com/android/server/wm/WallpaperController.java
index 644417e..3a4d9d2 100644
--- a/services/core/java/com/android/server/wm/WallpaperController.java
+++ b/services/core/java/com/android/server/wm/WallpaperController.java
@@ -21,7 +21,6 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
 import static android.view.Display.DEFAULT_DISPLAY;
 import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-import static android.view.WindowManager.TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER;
 
 import static com.android.internal.protolog.WmProtoLogGroups.WM_DEBUG_WALLPAPER;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
@@ -118,42 +117,20 @@
     private boolean mShouldOffsetWallpaperCenter;
 
     private final ToBooleanFunction<WindowState> mFindWallpaperTargetFunction = w -> {
-        final boolean useShellTransition = w.mTransitionController.isShellTransitionsEnabled();
-        if (!useShellTransition) {
-            if (w.mActivityRecord != null && !w.mActivityRecord.isVisible()
-                    && !w.mActivityRecord.isAnimating(TRANSITION | PARENTS)) {
-                // If this window's app token is hidden and not animating, it is of no interest.
-                if (DEBUG_WALLPAPER) Slog.v(TAG, "Skipping hidden and not animating token: " + w);
-                return false;
-            }
-        } else {
-            final ActivityRecord ar = w.mActivityRecord;
-            // The animating window can still be visible on screen if it is in transition, so we
-            // should check whether this window can be wallpaper target even when visibleRequested
-            // is false.
-            if (ar != null && !ar.isVisibleRequested() && !ar.isVisible()) {
-                // An activity that is not going to remain visible shouldn't be the target.
-                return false;
-            }
+        final ActivityRecord ar = w.mActivityRecord;
+        // The animating window can still be visible on screen if it is in transition, so we
+        // should check whether this window can be wallpaper target even when visibleRequested
+        // is false.
+        if (ar != null && !ar.isVisibleRequested() && !ar.isVisible()) {
+            // An activity that is not going to remain visible shouldn't be the target.
+            return false;
         }
         if (DEBUG_WALLPAPER) Slog.v(TAG, "Win " + w + ": isOnScreen=" + w.isOnScreen()
                 + " mDrawState=" + w.mWinAnimator.mDrawState);
 
-        final WindowContainer animatingContainer = w.mActivityRecord != null
-                ? w.mActivityRecord.getAnimatingContainer() : null;
-        if (!useShellTransition && animatingContainer != null
-                && animatingContainer.isAnimating(TRANSITION | PARENTS)
-                && AppTransition.isKeyguardGoingAwayTransitOld(animatingContainer.mTransit)
-                && (animatingContainer.mTransitFlags
-                & TRANSIT_FLAG_KEYGUARD_GOING_AWAY_WITH_WALLPAPER) != 0) {
-            // Keep the wallpaper visible when Keyguard is going away.
-            mFindResults.setUseTopWallpaperAsTarget(true);
-        }
-
         if (mService.mPolicy.isKeyguardLocked()) {
             if (w.canShowWhenLocked()) {
-                if (mService.mPolicy.isKeyguardOccluded() || (useShellTransition
-                        ? w.inTransition() : mService.mPolicy.isKeyguardUnoccluding())) {
+                if (mService.mPolicy.isKeyguardOccluded() || w.inTransition()) {
                     // The lowest show-when-locked window decides whether to show wallpaper.
                     mFindResults.mNeedsShowWhenLockedWallpaper = !isFullscreen(w.mAttrs)
                             || (w.mActivityRecord != null && !w.mActivityRecord.fillsParent());
@@ -176,15 +153,11 @@
             }
         }
 
-        final boolean animationWallpaper = animatingContainer != null
-                && animatingContainer.getAnimation() != null
-                && animatingContainer.getAnimation().getShowWallpaper();
-        final boolean hasWallpaper = w.hasWallpaper() || animationWallpaper;
         if (isBackNavigationTarget(w)) {
             if (DEBUG_WALLPAPER) Slog.v(TAG, "Found back animation wallpaper target: " + w);
             mFindResults.setWallpaperTarget(w);
             return true;
-        } else if (hasWallpaper
+        } else if (w.hasWallpaper()
                 && (w.mActivityRecord != null ? w.isOnScreen() : w.isReadyForDisplay())) {
             if (DEBUG_WALLPAPER) Slog.v(TAG, "Found wallpaper target: " + w);
             mFindResults.setWallpaperTarget(w);
diff --git a/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java b/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java
deleted file mode 100644
index d3530c5..0000000
--- a/services/core/java/com/android/server/wm/WindowChangeAnimationSpec.java
+++ /dev/null
@@ -1,200 +0,0 @@
-/*
- * Copyright (C) 2018 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT 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;
-
-import static com.android.server.wm.AnimationAdapter.STATUS_BAR_TRANSITION_DURATION;
-import static com.android.server.wm.AnimationSpecProto.WINDOW;
-import static com.android.server.wm.WindowAnimationSpecProto.ANIMATION;
-
-import android.graphics.Matrix;
-import android.graphics.Rect;
-import android.os.SystemClock;
-import android.util.proto.ProtoOutputStream;
-import android.view.DisplayInfo;
-import android.view.SurfaceControl;
-import android.view.SurfaceControl.Transaction;
-import android.view.animation.AlphaAnimation;
-import android.view.animation.Animation;
-import android.view.animation.AnimationSet;
-import android.view.animation.ClipRectAnimation;
-import android.view.animation.ScaleAnimation;
-import android.view.animation.Transformation;
-import android.view.animation.TranslateAnimation;
-
-import com.android.server.wm.LocalAnimationAdapter.AnimationSpec;
-
-import java.io.PrintWriter;
-
-/**
- * Animation spec for changing window animations.
- */
-public class WindowChangeAnimationSpec implements AnimationSpec {
-
-    private final ThreadLocal<TmpValues> mThreadLocalTmps = ThreadLocal.withInitial(TmpValues::new);
-    private final boolean mIsAppAnimation;
-    private final Rect mStartBounds;
-    private final Rect mEndBounds;
-    private final Rect mTmpRect = new Rect();
-
-    private Animation mAnimation;
-    private final boolean mIsThumbnail;
-
-    static final int ANIMATION_DURATION = AppTransition.DEFAULT_APP_TRANSITION_DURATION;
-
-    public WindowChangeAnimationSpec(Rect startBounds, Rect endBounds, DisplayInfo displayInfo,
-            float durationScale, boolean isAppAnimation, boolean isThumbnail) {
-        mStartBounds = new Rect(startBounds);
-        mEndBounds = new Rect(endBounds);
-        mIsAppAnimation = isAppAnimation;
-        mIsThumbnail = isThumbnail;
-        createBoundsInterpolator((int) (ANIMATION_DURATION * durationScale), displayInfo);
-    }
-
-    @Override
-    public boolean getShowWallpaper() {
-        return false;
-    }
-
-    @Override
-    public long getDuration() {
-        return mAnimation.getDuration();
-    }
-
-    /**
-     * This animator behaves slightly differently depending on whether the window is growing
-     * or shrinking:
-     * If growing, it will do a clip-reveal after quicker fade-out/scale of the smaller (old)
-     * snapshot.
-     * If shrinking, it will do an opposite clip-reveal on the old snapshot followed by a quicker
-     * fade-out of the bigger (old) snapshot while simultaneously shrinking the new window into
-     * place.
-     * @param duration
-     * @param displayInfo
-     */
-    private void createBoundsInterpolator(long duration, DisplayInfo displayInfo) {
-        boolean growing = mEndBounds.width() - mStartBounds.width()
-                + mEndBounds.height() - mStartBounds.height() >= 0;
-        float scalePart = 0.7f;
-        long scalePeriod = (long) (duration * scalePart);
-        float startScaleX = scalePart * ((float) mStartBounds.width()) / mEndBounds.width()
-                + (1.f - scalePart);
-        float startScaleY = scalePart * ((float) mStartBounds.height()) / mEndBounds.height()
-                + (1.f - scalePart);
-        if (mIsThumbnail) {
-            AnimationSet animSet = new AnimationSet(true);
-            Animation anim = new AlphaAnimation(1.f, 0.f);
-            anim.setDuration(scalePeriod);
-            if (!growing) {
-                anim.setStartOffset(duration - scalePeriod);
-            }
-            animSet.addAnimation(anim);
-            float endScaleX = 1.f / startScaleX;
-            float endScaleY = 1.f / startScaleY;
-            anim = new ScaleAnimation(endScaleX, endScaleX, endScaleY, endScaleY);
-            anim.setDuration(duration);
-            animSet.addAnimation(anim);
-            mAnimation = animSet;
-            mAnimation.initialize(mStartBounds.width(), mStartBounds.height(),
-                    mEndBounds.width(), mEndBounds.height());
-        } else {
-            AnimationSet animSet = new AnimationSet(true);
-            final Animation scaleAnim = new ScaleAnimation(startScaleX, 1, startScaleY, 1);
-            scaleAnim.setDuration(scalePeriod);
-            if (!growing) {
-                scaleAnim.setStartOffset(duration - scalePeriod);
-            }
-            animSet.addAnimation(scaleAnim);
-            final Animation translateAnim = new TranslateAnimation(mStartBounds.left,
-                    mEndBounds.left, mStartBounds.top, mEndBounds.top);
-            translateAnim.setDuration(duration);
-            animSet.addAnimation(translateAnim);
-            Rect startClip = new Rect(mStartBounds);
-            Rect endClip = new Rect(mEndBounds);
-            startClip.offsetTo(0, 0);
-            endClip.offsetTo(0, 0);
-            final Animation clipAnim = new ClipRectAnimation(startClip, endClip);
-            clipAnim.setDuration(duration);
-            animSet.addAnimation(clipAnim);
-            mAnimation = animSet;
-            mAnimation.initialize(mStartBounds.width(), mStartBounds.height(),
-                    displayInfo.appWidth, displayInfo.appHeight);
-        }
-    }
-
-    @Override
-    public void apply(Transaction t, SurfaceControl leash, long currentPlayTime) {
-        final TmpValues tmp = mThreadLocalTmps.get();
-        if (mIsThumbnail) {
-            mAnimation.getTransformation(currentPlayTime, tmp.mTransformation);
-            t.setMatrix(leash, tmp.mTransformation.getMatrix(), tmp.mFloats);
-            t.setAlpha(leash, tmp.mTransformation.getAlpha());
-        } else {
-            mAnimation.getTransformation(currentPlayTime, tmp.mTransformation);
-            final Matrix matrix = tmp.mTransformation.getMatrix();
-            t.setMatrix(leash, matrix, tmp.mFloats);
-
-            // The following applies an inverse scale to the clip-rect so that it crops "after" the
-            // scale instead of before.
-            tmp.mVecs[1] = tmp.mVecs[2] = 0;
-            tmp.mVecs[0] = tmp.mVecs[3] = 1;
-            matrix.mapVectors(tmp.mVecs);
-            tmp.mVecs[0] = 1.f / tmp.mVecs[0];
-            tmp.mVecs[3] = 1.f / tmp.mVecs[3];
-            final Rect clipRect = tmp.mTransformation.getClipRect();
-            mTmpRect.left = (int) (clipRect.left * tmp.mVecs[0] + 0.5f);
-            mTmpRect.right = (int) (clipRect.right * tmp.mVecs[0] + 0.5f);
-            mTmpRect.top = (int) (clipRect.top * tmp.mVecs[3] + 0.5f);
-            mTmpRect.bottom = (int) (clipRect.bottom * tmp.mVecs[3] + 0.5f);
-            t.setWindowCrop(leash, mTmpRect);
-        }
-    }
-
-    @Override
-    public long calculateStatusBarTransitionStartTime() {
-        long uptime = SystemClock.uptimeMillis();
-        return Math.max(uptime, uptime + ((long) (((float) mAnimation.getDuration()) * 0.99f))
-                - STATUS_BAR_TRANSITION_DURATION);
-    }
-
-    @Override
-    public boolean canSkipFirstFrame() {
-        return false;
-    }
-
-    @Override
-    public boolean needsEarlyWakeup() {
-        return mIsAppAnimation;
-    }
-
-    @Override
-    public void dump(PrintWriter pw, String prefix) {
-        pw.print(prefix); pw.println(mAnimation.getDuration());
-    }
-
-    @Override
-    public void dumpDebugInner(ProtoOutputStream proto) {
-        final long token = proto.start(WINDOW);
-        proto.write(ANIMATION, mAnimation.toString());
-        proto.end(token);
-    }
-
-    private static class TmpValues {
-        final Transformation mTransformation = new Transformation();
-        final float[] mFloats = new float[9];
-        final float[] mVecs = new float[4];
-    }
-}
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 1c3510d..466ed78 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -97,7 +97,6 @@
 import com.android.server.wm.SurfaceAnimator.AnimationType;
 import com.android.server.wm.SurfaceAnimator.OnAnimationFinishedCallback;
 import com.android.server.wm.utils.AlwaysTruePredicate;
-import com.android.window.flags.Flags;
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
@@ -2630,7 +2629,7 @@
         if (!mTransitionController.canAssignLayers(this)) return;
         final boolean changed = layer != mLastLayer || mLastRelativeToLayer != null;
         if (mSurfaceControl != null && changed) {
-            if (Flags.useSelfSyncTransactionForLayer() && mSyncState != SYNC_STATE_NONE) {
+            if (mSyncState != SYNC_STATE_NONE) {
                 // When this container needs to be synced, assign layer with its own sync
                 // transaction to avoid out of ordering when merge.
                 // Still use the passed-in transaction for non-sync case, such as building finish
@@ -2647,7 +2646,7 @@
             boolean forceUpdate) {
         final boolean changed = layer != mLastLayer || mLastRelativeToLayer != relativeTo;
         if (mSurfaceControl != null && (changed || forceUpdate)) {
-            if (Flags.useSelfSyncTransactionForLayer() && mSyncState != SYNC_STATE_NONE) {
+            if (mSyncState != SYNC_STATE_NONE) {
                 // When this container needs to be synced, assign layer with its own sync
                 // transaction to avoid out of ordering when merge.
                 // Still use the passed-in transaction for non-sync case, such as building finish
@@ -3067,7 +3066,6 @@
     @Override
     public void onAnimationLeashLost(Transaction t) {
         mLastLayer = -1;
-        mWmService.mSurfaceAnimationRunner.onAnimationLeashLost(mAnimationLeash, t);
         mAnimationLeash = null;
         mNeedsZBoost = false;
         reassignLayer(t);
diff --git a/services/core/java/com/android/server/wm/WindowManagerInternal.java b/services/core/java/com/android/server/wm/WindowManagerInternal.java
index 6e224f0..4b5a3a0 100644
--- a/services/core/java/com/android/server/wm/WindowManagerInternal.java
+++ b/services/core/java/com/android/server/wm/WindowManagerInternal.java
@@ -152,6 +152,30 @@
         }
     }
 
+    /** Interface for clients to receive callbacks related to window change. */
+    public interface WindowFocusChangeListener {
+        /**
+         * Notify on focus changed.
+         *
+         * @param focusedWindowToken the token of the newly focused window.
+         */
+        void focusChanged(@NonNull IBinder focusedWindowToken);
+    }
+
+    /**
+     * Registers a listener to be notified about window focus changes.
+     *
+     * @param listener the {@link WindowFocusChangeListener} to register.
+     */
+    public abstract void registerWindowFocusChangeListener(WindowFocusChangeListener listener);
+
+    /**
+     * Unregisters a listener that was registered via {@link #registerWindowFocusChangeListener}.
+     *
+     * @param listener the {@link WindowFocusChangeListener} to unregister.
+     */
+    public abstract void unregisterWindowFocusChangeListener(WindowFocusChangeListener listener);
+
     /**
      * Interface to receive a callback when the windows reported for
      * accessibility changed.
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 28f2825..9fc0339 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -17,7 +17,6 @@
 package com.android.server.wm;
 
 import static android.Manifest.permission.ACCESS_SURFACE_FLINGER;
-import static android.Manifest.permission.CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS;
 import static android.Manifest.permission.INPUT_CONSUMER;
 import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.Manifest.permission.MANAGE_APP_TOKENS;
@@ -88,7 +87,6 @@
 import static android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION;
 import static android.view.WindowManager.LayoutParams.TYPE_WALLPAPER;
 import static android.view.WindowManager.REMOVE_CONTENT_MODE_UNDEFINED;
-import static android.view.WindowManager.TRANSIT_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
 import static android.view.WindowManager.TRANSIT_TO_FRONT;
 import static android.view.WindowManager.fixScale;
@@ -147,6 +145,7 @@
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME;
 import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM;
 import static com.android.server.wm.WindowManagerInternal.OnWindowRemovedListener;
+import static com.android.server.wm.WindowManagerInternal.WindowFocusChangeListener;
 import static com.android.server.wm.WindowManagerServiceDumpProto.BACK_NAVIGATION;
 import static com.android.server.wm.WindowManagerServiceDumpProto.FOCUSED_APP;
 import static com.android.server.wm.WindowManagerServiceDumpProto.FOCUSED_DISPLAY_ID;
@@ -1080,14 +1079,12 @@
 
     private ViewServer mViewServer;
     final ArrayList<WindowChangeListener> mWindowChangeListeners = new ArrayList<>();
+    final ArrayList<WindowFocusChangeListener> mWindowFocusChangeListeners = new ArrayList<>();
     boolean mWindowsChanged = false;
 
-    public interface WindowChangeListener {
+    interface WindowChangeListener {
         /** Notify on windows changed */
         void windowsChanged();
-
-        /** Notify on focus changed */
-        void focusChanged();
     }
 
     final HighRefreshRateDenylist mHighRefreshRateDenylist;
@@ -3237,49 +3234,17 @@
         }
     }
 
-    // TODO(multi-display): remove when no default display use case.
-    void prepareAppTransitionNone() {
-        if (!checkCallingPermission(MANAGE_APP_TOKENS, "prepareAppTransition()")) {
-            throw new SecurityException("Requires MANAGE_APP_TOKENS permission");
-        }
-        getDefaultDisplayContentLocked().prepareAppTransition(TRANSIT_NONE);
-    }
-
     @Override
     public void overridePendingAppTransitionMultiThumbFuture(
             IAppTransitionAnimationSpecsFuture specsFuture, IRemoteCallback callback,
             boolean scaleUp, int displayId) {
-        synchronized (mGlobalLock) {
-            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
-            if (displayContent == null) {
-                Slog.w(TAG, "Attempted to call overridePendingAppTransitionMultiThumbFuture"
-                        + " for the display " + displayId + " that does not exist.");
-                return;
-            }
-            displayContent.mAppTransition.overridePendingAppTransitionMultiThumbFuture(specsFuture,
-                    callback, scaleUp);
-        }
+        // TODO(b/365884835): remove this method and callers.
     }
 
     @Override
     public void overridePendingAppTransitionRemote(RemoteAnimationAdapter remoteAnimationAdapter,
             int displayId) {
-        if (!checkCallingPermission(CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS,
-                "overridePendingAppTransitionRemote()")) {
-            throw new SecurityException(
-                    "Requires CONTROL_REMOTE_APP_TRANSITION_ANIMATIONS permission");
-        }
-        synchronized (mGlobalLock) {
-            final DisplayContent displayContent = mRoot.getDisplayContent(displayId);
-            if (displayContent == null) {
-                Slog.w(TAG, "Attempted to call overridePendingAppTransitionRemote"
-                        + " for the display " + displayId + " that does not exist.");
-                return;
-            }
-            remoteAnimationAdapter.setCallingPidUid(Binder.getCallingPid(), Binder.getCallingUid());
-            displayContent.mAppTransition.overridePendingAppTransitionRemote(
-                    remoteAnimationAdapter);
-        }
+        // TODO(b/365884835): remove this method and callers.
     }
 
     @Override
@@ -3396,11 +3361,6 @@
     }
 
     @Override
-    public boolean isAppTransitionStateIdle() {
-        return getDefaultDisplayContentLocked().mAppTransition.isIdle();
-    }
-
-    @Override
     public void disableKeyguard(IBinder token, String tag, int userId) {
         userId = mAmInternal.handleIncomingUser(Binder.getCallingPid(), Binder.getCallingUid(),
                 userId, false /* allowAll */, ALLOW_FULL_ONLY, "disableKeyguard", null);
@@ -5345,18 +5305,30 @@
         return success;
     }
 
-    public void addWindowChangeListener(WindowChangeListener listener) {
+    void addWindowChangeListener(WindowChangeListener listener) {
         synchronized (mGlobalLock) {
             mWindowChangeListeners.add(listener);
         }
     }
 
-    public void removeWindowChangeListener(WindowChangeListener listener) {
+    void removeWindowChangeListener(WindowChangeListener listener) {
         synchronized (mGlobalLock) {
             mWindowChangeListeners.remove(listener);
         }
     }
 
+    void addWindowFocusChangeListener(WindowFocusChangeListener listener) {
+        synchronized (mGlobalLock) {
+            mWindowFocusChangeListeners.add(listener);
+        }
+    }
+
+    void removeWindowFocusChangeListener(WindowFocusChangeListener listener) {
+        synchronized (mGlobalLock) {
+            mWindowFocusChangeListeners.remove(listener);
+        }
+    }
+
     private void notifyWindowRemovedListeners(IBinder client) {
         OnWindowRemovedListener[] windowRemovedListeners;
         synchronized (mGlobalLock) {
@@ -5389,18 +5361,19 @@
         }
     }
 
-    private void notifyFocusChanged() {
-        WindowChangeListener[] windowChangeListeners;
+    private void notifyFocusChanged(IBinder focusedWindowToken) {
+        WindowFocusChangeListener[] windowFocusChangeListeners;
         synchronized (mGlobalLock) {
-            if(mWindowChangeListeners.isEmpty()) {
+            if(mWindowFocusChangeListeners.isEmpty()) {
                 return;
             }
-            windowChangeListeners = new WindowChangeListener[mWindowChangeListeners.size()];
-            windowChangeListeners = mWindowChangeListeners.toArray(windowChangeListeners);
+            windowFocusChangeListeners =
+                    new WindowFocusChangeListener[mWindowFocusChangeListeners.size()];
+            mWindowFocusChangeListeners.toArray(windowFocusChangeListeners);
         }
-        int N = windowChangeListeners.length;
+        int N = windowFocusChangeListeners.length;
         for(int i = 0; i < N; i++) {
-            windowChangeListeners[i].focusChanged();
+            windowFocusChangeListeners[i].focusChanged(focusedWindowToken);
         }
     }
 
@@ -5675,7 +5648,7 @@
         if (newFocusedWindow != null && newFocusedWindow.mInputChannelToken == newToken) {
             mAnrController.onFocusChanged(newFocusedWindow);
             newFocusedWindow.reportFocusChangedSerialized(true);
-            notifyFocusChanged();
+            notifyFocusChanged(newTarget.getWindowToken());
         }
 
         WindowState lastFocusedWindow = lastTarget != null ? lastTarget.getWindowState() : null;
@@ -6863,7 +6836,7 @@
                 pw.print(' '); pw.println(imeControlTarget);
             }
             pw.print("  Minimum task size of display#"); pw.print(displayId);
-            pw.print(' '); pw.print(dc.mMinSizeOfResizeableTaskDp);
+            pw.print(' '); pw.println(dc.mMinSizeOfResizeableTaskDp);
         });
         pw.print("  mBlurEnabled="); pw.println(mBlurController.getBlurEnabled());
         pw.print("  mDisableSecureWindows="); pw.println(mDisableSecureWindows);
@@ -7968,7 +7941,6 @@
         @Override
         public void registerAppTransitionListener(AppTransitionListener listener) {
             synchronized (mGlobalLock) {
-                getDefaultDisplayContentLocked().mAppTransition.registerListenerLocked(listener);
                 mAtmService.getTransitionController().registerLegacyListener(listener);
             }
         }
@@ -8690,6 +8662,16 @@
         }
 
         @Override
+        public void registerWindowFocusChangeListener(WindowFocusChangeListener listener) {
+            WindowManagerService.this.addWindowFocusChangeListener(listener);
+        }
+
+        @Override
+        public void unregisterWindowFocusChangeListener(WindowFocusChangeListener listener) {
+            WindowManagerService.this.removeWindowFocusChangeListener(listener);
+        }
+
+        @Override
         public void registerOnWindowRemovedListener(OnWindowRemovedListener listener) {
             synchronized (mGlobalLock) {
                 mOnWindowRemovedListeners.add(listener);
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index 4b4736e..ea1f35a 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -472,6 +472,7 @@
         transition.setAllReady();
     }
 
+    // TODO(b/365884835): remove this method and callers.
     @Override
     public int startLegacyTransition(int type, @NonNull RemoteAnimationAdapter adapter,
             @NonNull IWindowContainerTransactionCallback callback,
@@ -489,16 +490,6 @@
                     throw new IllegalArgumentException("Can't use legacy transitions in"
                             + " when shell transitions are enabled.");
                 }
-                final DisplayContent dc =
-                        mService.mRootWindowContainer.getDisplayContent(DEFAULT_DISPLAY);
-                if (dc.mAppTransition.isTransitionSet()) {
-                    // a transition already exists, so the callback probably won't be called.
-                    return -1;
-                }
-                adapter.setCallingPidUid(caller.mPid, caller.mUid);
-                dc.prepareAppTransition(type);
-                dc.mAppTransition.overridePendingAppTransitionRemote(adapter, true /* sync */,
-                        false /* isActivityEmbedding */);
                 syncId = startSyncWithOrganizer(callback);
                 applyTransaction(t, syncId, mService.mChainTracker.startLegacy("legacyTransit"),
                         caller);
diff --git a/services/core/java/com/android/server/wm/WindowProcessController.java b/services/core/java/com/android/server/wm/WindowProcessController.java
index 270de01..bdd1372 100644
--- a/services/core/java/com/android/server/wm/WindowProcessController.java
+++ b/services/core/java/com/android/server/wm/WindowProcessController.java
@@ -36,8 +36,8 @@
 import static com.android.server.wm.ActivityRecord.State.PAUSING;
 import static com.android.server.wm.ActivityRecord.State.RESUMED;
 import static com.android.server.wm.ActivityRecord.State.STARTED;
-import static com.android.server.wm.ActivityRecord.State.STOPPING;
 import static com.android.server.wm.ActivityRecord.State.STOPPED;
+import static com.android.server.wm.ActivityRecord.State.STOPPING;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.DEBUG_RELEASE;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_CONFIGURATION;
 import static com.android.server.wm.ActivityTaskManagerDebugConfig.POSTFIX_RELEASE;
@@ -69,7 +69,6 @@
 import android.content.res.Configuration;
 import android.os.Binder;
 import android.os.Build;
-import android.os.DeadObjectException;
 import android.os.FactoryTest;
 import android.os.LocaleList;
 import android.os.Message;
@@ -458,6 +457,7 @@
                 mAtm.getLifecycleManager().scheduleTransactionItemNow(
                         thread, configurationChangeItem);
             } catch (Exception e) {
+                // TODO(b/323801078): remove Exception when cleanup
                 Slog.e(TAG_CONFIGURATION, "Failed to schedule ConfigurationChangeItem="
                         + configurationChangeItem + " owner=" + mOwner, e);
             }
@@ -1793,13 +1793,11 @@
                 // Non-UI process can handle the change directly.
                 mAtm.getLifecycleManager().scheduleTransactionItemNow(thread, transactionItem);
             }
-        } catch (DeadObjectException e) {
+        } catch (RemoteException e) {
+            // TODO(b/323801078): remove Exception when cleanup
             // Expected if the process has been killed.
             Slog.w(TAG_CONFIGURATION, "Failed for dead process. ClientTransactionItem="
                     + transactionItem + " owner=" + mOwner);
-        } catch (Exception e) {
-            Slog.e(TAG_CONFIGURATION, "Failed to schedule ClientTransactionItem="
-                    + transactionItem + " owner=" + mOwner, e);
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowProcessControllerMap.java b/services/core/java/com/android/server/wm/WindowProcessControllerMap.java
index 424b043..ac675b8 100644
--- a/services/core/java/com/android/server/wm/WindowProcessControllerMap.java
+++ b/services/core/java/com/android/server/wm/WindowProcessControllerMap.java
@@ -72,9 +72,6 @@
     }
 
     private void removeProcessFromUidMap(WindowProcessController proc) {
-        if (proc == null) {
-            return;
-        }
         final int uid = proc.mUid;
         ArraySet<WindowProcessController> procSet = mUidMap.get(uid);
         if (procSet != null) {
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 3b7d312..1022d18 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -5447,7 +5447,7 @@
     @Override
     void assignLayer(Transaction t, int layer) {
         if (mStartingData != null) {
-            if (Flags.useSelfSyncTransactionForLayer() && mSyncState != SYNC_STATE_NONE) {
+            if (mSyncState != SYNC_STATE_NONE) {
                 // When this container needs to be synced, assign layer with its own sync
                 // transaction to avoid out of ordering when merge.
                 // Still use the passed-in transaction for non-sync case, such as building finish
diff --git a/services/core/java/com/android/server/wm/WindowStateAnimator.java b/services/core/java/com/android/server/wm/WindowStateAnimator.java
index 1d8d867..0d434f5 100644
--- a/services/core/java/com/android/server/wm/WindowStateAnimator.java
+++ b/services/core/java/com/android/server/wm/WindowStateAnimator.java
@@ -561,7 +561,7 @@
                         break;
                 }
                 if (attr >= 0) {
-                    a = mWin.getDisplayContent().mAppTransition.loadAnimationAttr(
+                    a = mWin.mDisplayContent.mTransitionAnimation.loadAnimationAttr(
                             mWin.mAttrs, attr, TRANSIT_OLD_NONE);
                 }
             }
diff --git a/services/core/jni/stats/OWNERS b/services/core/jni/stats/OWNERS
index 8d87925..03086b3 100644
--- a/services/core/jni/stats/OWNERS
+++ b/services/core/jni/stats/OWNERS
@@ -1,6 +1,5 @@
 jeffreyhuang@google.com
 muhammadq@google.com
-sharaieko@google.com
 singhtejinder@google.com
 tsaichristine@google.com
 yaochen@google.com
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index 014f0a2..42e457c 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -31,6 +31,7 @@
 import android.content.Context;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
+import android.content.res.Resources;
 import android.credentials.ClearCredentialStateRequest;
 import android.credentials.CreateCredentialException;
 import android.credentials.CreateCredentialRequest;
@@ -50,6 +51,7 @@
 import android.credentials.PrepareGetCredentialResponseInternal;
 import android.credentials.RegisterCredentialDescriptionRequest;
 import android.credentials.UnregisterCredentialDescriptionRequest;
+import android.credentials.flags.Flags;
 import android.os.Binder;
 import android.os.CancellationSignal;
 import android.os.IBinder;
@@ -79,6 +81,7 @@
 import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.function.Consumer;
 import java.util.stream.Collectors;
@@ -535,6 +538,33 @@
 
             final int userId = UserHandle.getCallingUserId();
             final int callingUid = Binder.getCallingUid();
+            if (Flags.safeguardCandidateCredentialsApiCaller()) {
+                try {
+                    String credentialManagerAutofillCompName = mContext.getResources().getString(
+                            R.string.config_defaultCredentialManagerAutofillService);
+                    ComponentName componentName = ComponentName.unflattenFromString(
+                            credentialManagerAutofillCompName);
+                    if (componentName == null) {
+                        throw new SecurityException(
+                                "Credential Autofill service does not exist on this device.");
+                    }
+                    PackageManager pm = mContext.createContextAsUser(
+                            UserHandle.getUserHandleForUid(callingUid), 0).getPackageManager();
+                    String callingProcessPackage = pm.getNameForUid(callingUid);
+                    if (callingProcessPackage == null) {
+                        throw new SecurityException(
+                                "Couldn't determine the identity of the caller.");
+                    }
+                    if (!Objects.equals(componentName.getPackageName(), callingProcessPackage)) {
+                        throw new SecurityException(callingProcessPackage
+                                + " is not the device's credential autofill package.");
+                    }
+                } catch (Resources.NotFoundException e) {
+                    throw new SecurityException(
+                            "Credential Autofill service does not exist on this device.");
+                }
+            }
+
 
             // New request session, scoped for this request only.
             final GetCandidateRequestSession session =
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index a81a0b3..4b98a72 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -50,6 +50,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.IndentingPrintWriter;
+import android.util.PrintWriterPrinter;
 
 import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
@@ -1484,5 +1485,12 @@
             pw.print("mProvisioningContext=");
             pw.println(mProvisioningContext);
         }
+
+        if (info != null) {
+            pw.println("DeviceAdminInfo:");
+            pw.increaseIndent();
+            info.dump(new PrintWriterPrinter(pw), "");
+            pw.decreaseIndent();
+        }
     }
 }
diff --git a/services/proguard.flags b/services/proguard.flags
index 8d8b418..dd3757c 100644
--- a/services/proguard.flags
+++ b/services/proguard.flags
@@ -59,6 +59,7 @@
 
 # Referenced in wear-service
 -keep public class com.android.server.wm.WindowManagerInternal { *; }
+-keep public class com.android.server.wm.WindowManagerInternal$WindowFocusChangeListener { *; }
 
 # JNI keep rules
 # The global keep rule for native methods allows stripping of such methods if they're unreferenced
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml
index d6a6853..ea01fc4 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/AndroidTest.xml
@@ -18,9 +18,6 @@
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-instrumentation" />
 
-    <!-- Needed for reading the app files for the test artifacts -->
-    <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
-
     <target_preparer class="com.android.tradefed.targetprep.suite.SuiteApkInstaller">
         <option name="cleanup-apks" value="true" />
         <option name="install-arg" value="-t" />
@@ -44,7 +41,7 @@
 
     <!-- Collect output of DumpOnFailure -->
     <metrics_collector class="com.android.tradefed.device.metric.FilePullerLogCollector">
-        <option name="directory-keys" value="/data/user/0/com.android.apps.inputmethod.simpleime/files" />
+        <option name="directory-keys" value="/sdcard/DumpOnFailure" />
         <option name="collect-on-run-ended-only" value="true" />
         <option name="clean-up" value="true" />
     </metrics_collector>
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
index 2cd860a..e263e85 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/inputmethodservice/InputMethodServiceTest.java
@@ -77,6 +77,8 @@
 import org.junit.rules.TestName;
 import org.junit.runner.RunWith;
 
+import java.io.ByteArrayOutputStream;
+import java.nio.charset.StandardCharsets;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CountDownLatch;
@@ -1294,6 +1296,14 @@
         mInstrumentation.waitForIdleSync();
         final var postScreenshot = mInstrumentation.getUiAutomation().takeScreenshot();
         mDumpOnFailure.dumpOnFailure("post-getUiObject", postScreenshot);
+        try {
+            final var outputStream = new ByteArrayOutputStream();
+            mUiDevice.dumpWindowHierarchy(outputStream);
+            final String windowHierarchy = outputStream.toString(StandardCharsets.UTF_8);
+            mDumpOnFailure.dumpOnFailure("post-getUiObject", windowHierarchy);
+        } catch (Exception e) {
+            Log.i(TAG, "Failed to dump windowHierarchy", e);
+        }
         assertWithMessage("UiObject with " + bySelector + " was found").that(uiObject).isNotNull();
         return uiObject;
     }
diff --git a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml
index 00873de..b6965a4 100644
--- a/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml
+++ b/services/tests/InputMethodSystemServerTests/test-apps/SimpleTestIme/AndroidManifest.xml
@@ -20,6 +20,9 @@
 
     <uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS" />
 
+    <!-- Enable writing output of DumpOnFailure to external storage -->
+    <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
+
     <application android:debuggable="true"
                  android:label="@string/app_name">
         <service
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
index c151732..1f8ccde 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayManagerServiceTest.java
@@ -332,6 +332,10 @@
                         @Override
                         public void destroyDisplay(IBinder displayToken) {
                         }
+
+                        @Override
+                        public void setDisplayPowerMode(IBinder displayToken, int mode) {
+                        }
                     }, flags);
         }
 
@@ -3910,6 +3914,7 @@
         DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
         DisplayManagerService.BinderService displayManagerBinderService =
                 displayManager.new BinderService();
+        DisplayManagerInternal localService = displayManager.new LocalService();
         Handler handler = displayManager.getDisplayHandler();
         waitForIdleHandler(handler);
 
@@ -3918,8 +3923,8 @@
                 INTERNAL_EVENT_FLAG_TOPOLOGY_UPDATED);
         waitForIdleHandler(handler);
 
-        var topology = initDisplayTopology(displayManager, displayManagerBinderService, callback,
-                handler, /*shouldEmitTopologyChangeEvent=*/ true);
+        var topology = initDisplayTopology(displayManager, displayManagerBinderService,
+                localService, callback, handler, /*shouldEmitTopologyChangeEvent=*/ true);
         callback.clear();
         callback.expectsEvent(TOPOLOGY_CHANGED_EVENT);
         displayManagerBinderService.setDisplayTopology(topology);
@@ -3934,6 +3939,7 @@
         DisplayManagerService displayManager = new DisplayManagerService(mContext, mBasicInjector);
         DisplayManagerService.BinderService displayManagerBinderService =
                 displayManager.new BinderService();
+        DisplayManagerInternal localService = displayManager.new LocalService();
         Handler handler = displayManager.getDisplayHandler();
         waitForIdleHandler(handler);
 
@@ -3943,8 +3949,8 @@
                 STANDARD_DISPLAY_EVENTS);
         waitForIdleHandler(handler);
 
-        var topology = initDisplayTopology(displayManager, displayManagerBinderService, callback,
-                handler, /*shouldEmitTopologyChangeEvent=*/ false);
+        var topology = initDisplayTopology(displayManager, displayManagerBinderService,
+                localService, callback, handler, /*shouldEmitTopologyChangeEvent=*/ false);
         callback.clear();
         callback.expectsEvent(TOPOLOGY_CHANGED_EVENT); // should not happen
         displayManagerBinderService.setDisplayTopology(topology);
@@ -4702,15 +4708,16 @@
 
     private DisplayTopology initDisplayTopology(DisplayManagerService displayManager,
             DisplayManagerService.BinderService displayManagerBinderService,
-            FakeDisplayManagerCallback callback,
+            DisplayManagerInternal localService, FakeDisplayManagerCallback callback,
             Handler handler, boolean shouldEmitTopologyChangeEvent) {
         Settings.Global.putInt(mContext.getContentResolver(),
                 DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERNAL_DISPLAYS, 1);
         callback.expectsEvent(TOPOLOGY_CHANGED_EVENT);
         FakeDisplayDevice displayDevice0 =
-                createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_INTERNAL);
+                createFakeDisplayDevice(displayManager, new float[]{60f}, Display.TYPE_EXTERNAL);
         int displayId0 = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
                 displayDevice0);
+        waitForIdleHandler(handler);
         if (shouldEmitTopologyChangeEvent) {
             callback.waitForExpectedEvent();
         } else {
@@ -4724,6 +4731,11 @@
         int displayId1 = getDisplayIdForDisplayDevice(displayManager, displayManagerBinderService,
                 displayDevice1);
         waitForIdleHandler(handler);
+        // Non-default display should not be added until onDisplayBelongToTopologyChanged is called
+        // with true
+        callback.waitForNonExpectedEvent();
+        localService.onDisplayBelongToTopologyChanged(displayId1, true);
+        waitForIdleHandler(handler);
         if (shouldEmitTopologyChangeEvent) {
             callback.waitForExpectedEvent();
         } else {
diff --git a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt
index 3c134b5d..206c90d 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/DisplayTopologyCoordinatorTest.kt
@@ -220,17 +220,6 @@
     }
 
     @Test
-    fun addDisplay_notInDefaultDisplayGroup() {
-        displayInfos[0].displayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1
-
-        coordinator.onDisplayAdded(displayInfos[0])
-
-        verify(mockTopology, never()).addDisplay(anyInt(), anyFloat(), anyFloat())
-        verify(mockTopologyChangedCallback, never()).invoke(any())
-        verify(mockTopologyStore, never()).restoreTopology(any())
-    }
-
-    @Test
     fun updateDisplay() {
         whenever(mockTopology.updateDisplay(eq(displayInfos[0].displayId), anyFloat(), anyFloat()))
             .thenReturn(true)
@@ -349,17 +338,6 @@
     }
 
     @Test
-    fun updateDisplay_notInDefaultDisplayGroup() {
-        displayInfos[0].displayGroupId = Display.DEFAULT_DISPLAY_GROUP + 1
-
-        coordinator.onDisplayChanged(displayInfos[0])
-
-        verify(mockTopology, never()).updateDisplay(anyInt(), anyFloat(), anyFloat())
-        verify(mockTopologyCopy, never()).getGraph(any())
-        verify(mockTopologyChangedCallback, never()).invoke(any())
-    }
-
-    @Test
     fun removeDisplay() {
         addDisplay()
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
index 9287b30..0bef3b89 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/VirtualDisplayAdapterTest.java
@@ -21,19 +21,29 @@
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.ArgumentMatchers.anyBoolean;
+import static org.mockito.ArgumentMatchers.anyFloat;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.hardware.display.DisplayManager;
 import android.hardware.display.IVirtualDisplayCallback;
 import android.hardware.display.VirtualDisplayConfig;
 import android.media.projection.IMediaProjection;
+import android.os.Binder;
 import android.os.IBinder;
 import android.os.PowerManager;
 import android.os.Process;
+import android.platform.test.annotations.EnableFlags;
 import android.platform.test.flag.junit.CheckFlagsRule;
 import android.platform.test.flag.junit.DeviceFlagsValueProvider;
+import android.platform.test.flag.junit.SetFlagsRule;
 import android.testing.TestableContext;
 import android.view.Display;
 import android.view.Surface;
+import android.view.SurfaceControl;
 
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.filters.SmallTest;
@@ -67,6 +77,9 @@
     public final TestableContext mContext = new TestableContext(
             InstrumentationRegistry.getInstrumentation().getContext());
 
+    @Rule
+    public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
+
     @Mock
     private VirtualDisplayAdapter.SurfaceControlDisplayFactory mMockSufaceControlDisplayFactory;
 
@@ -380,6 +393,69 @@
         }
     }
 
+    @EnableFlags(
+            android.companion.virtualdevice.flags.Flags.FLAG_CORRECT_VIRTUAL_DISPLAY_POWER_STATE)
+    @Test
+    public void neverBlankDisplay_alwaysOn() {
+        // A non-public non-mirror display is considered never blank.
+        DisplayDevice device = mAdapter.createVirtualDisplayLocked(mMockCallback,
+                /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
+                "uniqueId", /* surface= */ mSurfaceMock, /* flags= */ 0,
+                mVirtualDisplayConfigMock);
+
+        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+        assertThat(info.state).isEqualTo(Display.STATE_ON);
+        assertThat(info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK)
+                .isEqualTo(DisplayDeviceInfo.FLAG_NEVER_BLANK);
+    }
+
+    @EnableFlags(
+            android.companion.virtualdevice.flags.Flags.FLAG_CORRECT_VIRTUAL_DISPLAY_POWER_STATE)
+    @Test
+    public void virtualDisplayStateChange_propagatesToSurfaceControl() throws Exception {
+        final String uniqueId = "uniqueId";
+        final IBinder displayToken = new Binder();
+        when(mMockSufaceControlDisplayFactory.createDisplay(
+                any(), anyBoolean(), eq(uniqueId), anyFloat()))
+                .thenReturn(displayToken);
+
+        // The display needs to be public, otherwise it will be considered never blank.
+        DisplayDevice device = mAdapter.createVirtualDisplayLocked(mMockCallback,
+                /* projection= */ null, /* ownerUid= */ 10, /* packageName= */ "testpackage",
+                uniqueId, /* surface= */ mSurfaceMock, DisplayManager.VIRTUAL_DISPLAY_FLAG_PUBLIC,
+                mVirtualDisplayConfigMock);
+
+        DisplayDeviceInfo info = device.getDisplayDeviceInfoLocked();
+        assertThat(info.state).isEqualTo(Display.STATE_UNKNOWN);
+        assertThat(info.flags & DisplayDeviceInfo.FLAG_NEVER_BLANK).isEqualTo(0);
+
+        // Any initial state change is processed because the display state is initially UNKNOWN
+        Runnable stateOnRunnable = device.requestDisplayStateLocked(
+                Display.STATE_ON, /* brightnessState= */ 1.0f, /* sdrBrightnessState= */ 1.0f,
+                /* displayOffloadSession= */ null);
+        assertThat(stateOnRunnable).isNotNull();
+        stateOnRunnable.run();
+        verify(mMockSufaceControlDisplayFactory)
+                .setDisplayPowerMode(displayToken, SurfaceControl.POWER_MODE_NORMAL);
+        verify(mMockCallback).onResumed();
+
+        // Requesting the same display state is a no-op
+        Runnable stateOnSecondRunnable = device.requestDisplayStateLocked(
+                Display.STATE_ON, /* brightnessState= */ 1.0f, /* sdrBrightnessState= */ 1.0f,
+                /* displayOffloadSession= */ null);
+        assertThat(stateOnSecondRunnable).isNull();
+
+        // A change to the display state is processed
+        Runnable stateOffRunnable = device.requestDisplayStateLocked(
+                Display.STATE_OFF, /* brightnessState= */ 1.0f, /* sdrBrightnessState= */ 1.0f,
+                /* displayOffloadSession= */ null);
+        assertThat(stateOffRunnable).isNotNull();
+        stateOffRunnable.run();
+        verify(mMockSufaceControlDisplayFactory)
+                .setDisplayPowerMode(displayToken, SurfaceControl.POWER_MODE_OFF);
+        verify(mMockCallback).onPaused();
+    }
+
     private IVirtualDisplayCallback createCallback() {
         return new IVirtualDisplayCallback.Stub() {
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt
index 6929690..d7c0477 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt
+++ b/services/tests/displayservicetests/src/com/android/server/display/brightness/clamper/BrightnessLowLuxModifierTest.kt
@@ -17,7 +17,6 @@
 
 import android.os.UserHandle
 import android.platform.test.annotations.RequiresFlagsEnabled
-import android.provider.Settings
 import android.testing.TestableContext
 import androidx.test.platform.app.InstrumentationRegistry
 import com.android.server.display.DisplayDeviceConfig
@@ -46,8 +45,6 @@
     private var mockDisplayDeviceConfig = mock<DisplayDeviceConfig>()
 
     private val LOW_LUX_BRIGHTNESS = 0.1f
-    private val TRANSITION_POINT = 0.25f
-    private val NORMAL_RANGE_BRIGHTNESS = 0.3f
 
     @Before
     fun setUp() {
@@ -73,48 +70,17 @@
         whenever(mockDisplayDeviceConfig.getBrightnessFromBacklight(/* backlight = */ 0.15f))
                 .thenReturn(0.24f)
 
-        // values above transition point (normal range)
-        // nits: 10 -> backlight 0.2 -> brightness -> 0.3
-        whenever(mockDisplayDeviceConfig.getBacklightFromNits(/* nits= */ 10f))
-                .thenReturn(0.2f)
-        whenever(mockDisplayDeviceConfig.getBrightnessFromBacklight(/* backlight = */ 0.2f))
-                .thenReturn(NORMAL_RANGE_BRIGHTNESS)
-
         // min nits when lux of 400
         whenever(mockDisplayDeviceConfig.getMinNitsFromLux(/* lux= */ 400f))
                 .thenReturn(1.0f)
 
-
-        whenever(mockDisplayDeviceConfig.evenDimmerTransitionPoint).thenReturn(TRANSITION_POINT)
-
         testHandler.flush()
     }
 
     @Test
-    fun testSettingOffDisablesModifier() {
-        // test transition point ensures brightness doesn't drop when setting is off.
-        Settings.Secure.putIntForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, USER_ID)
-        modifier.recalculateLowerBound()
-        testHandler.flush()
-        assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
-        assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off
-        modifier.setAmbientLux(3000f)
-
-        testHandler.flush()
-        assertThat(modifier.isActive).isFalse()
-        assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
-        assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off
-    }
-
-    @Test
     @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
     fun testLuxRestrictsBrightnessRange() {
         // test that high lux prevents low brightness range.
-        Settings.Secure.putIntForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, USER_ID)
-        Settings.Secure.putFloatForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_MIN_NITS, 0.1f, USER_ID)
         modifier.setAmbientLux(400f)
 
         testHandler.flush()
@@ -127,88 +93,8 @@
 
     @Test
     @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
-    fun testUserRestrictsBrightnessRange() {
-        // test that user minimum nits setting prevents low brightness range.
-        Settings.Secure.putIntForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, USER_ID)
-        Settings.Secure.putFloatForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_MIN_NITS, 10.0f, USER_ID)
-        modifier.recalculateLowerBound()
-        testHandler.flush()
-
-        // Test restriction from user setting
-        assertThat(modifier.isActive).isTrue()
-        assertThat(modifier.brightnessReason)
-                .isEqualTo(BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND)
-        assertThat(modifier.brightnessLowerBound).isEqualTo(NORMAL_RANGE_BRIGHTNESS)
-    }
-
-    @Test
-    @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
-    fun testOnToOff() {
-        // test that high lux prevents low brightness range.
-        Settings.Secure.putIntForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, USER_ID) // on
-        Settings.Secure.putFloatForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, USER_ID)
-        modifier.setAmbientLux(400f)
-
-        testHandler.flush()
-
-        assertThat(modifier.isActive).isTrue()
-        // Test restriction from lux setting
-        assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
-        assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS)
-
-        Settings.Secure.putIntForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, USER_ID) // off
-
-        modifier.recalculateLowerBound()
-        testHandler.flush()
-
-        assertThat(modifier.isActive).isFalse()
-        assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
-        assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off
-    }
-
-    @Test
-    @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
-    fun testOffToOn() {
-        // test that high lux prevents low brightness range.
-        Settings.Secure.putIntForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, USER_ID) // off
-        Settings.Secure.putFloatForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, USER_ID)
-        modifier.setAmbientLux(400f)
-
-        testHandler.flush()
-
-        assertThat(modifier.isActive).isFalse()
-        assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
-        assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - ie off
-
-
-
-        Settings.Secure.putIntForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, USER_ID) // on
-        modifier.recalculateLowerBound()
-        testHandler.flush()
-
-        assertThat(modifier.isActive).isTrue()
-        // Test restriction from lux setting
-        assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
-        assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS)
-    }
-
-    @Test
-    @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
     fun testEnabledEvenWhenAutobrightnessIsOff() {
         // test that high lux prevents low brightness range.
-        Settings.Secure.putIntForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, USER_ID) // on
-        Settings.Secure.putFloatForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, USER_ID)
-
         modifier.setAmbientLux(400f)
         testHandler.flush()
 
@@ -225,37 +111,5 @@
         assertThat(modifier.brightnessReason).isEqualTo(BrightnessReason.MODIFIER_MIN_LUX)
         assertThat(modifier.brightnessLowerBound).isEqualTo(LOW_LUX_BRIGHTNESS)
     }
-
-    @Test
-    @RequiresFlagsEnabled(Flags.FLAG_EVEN_DIMMER)
-    fun testUserSwitch() {
-        // nits: 0.5 -> backlight 0.01 -> brightness -> 0.05
-        whenever(mockDisplayDeviceConfig.getBacklightFromNits(/* nits= */ 0.5f))
-            .thenReturn(0.01f)
-        whenever(mockDisplayDeviceConfig.getBrightnessFromBacklight(/* backlight = */ 0.01f))
-            .thenReturn(0.05f)
-
-        Settings.Secure.putIntForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_ACTIVATED, 0, USER_ID) // off
-        Settings.Secure.putFloatForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_MIN_NITS, 1.0f, USER_ID)
-
-        modifier.recalculateLowerBound()
-
-        assertThat(modifier.isActive).isFalse()
-        assertThat(modifier.brightnessLowerBound).isEqualTo(TRANSITION_POINT)
-        assertThat(modifier.brightnessReason).isEqualTo(0) // no reason - i.e. off
-
-        Settings.Secure.putIntForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_ACTIVATED, 1, USER_ID) // on
-        Settings.Secure.putFloatForUser(context.contentResolver,
-            Settings.Secure.EVEN_DIMMER_MIN_NITS, 0.5f, USER_ID)
-        modifier.onSwitchUser()
-
-        assertThat(modifier.isActive).isTrue()
-        assertThat(modifier.brightnessReason).isEqualTo(
-            BrightnessReason.MODIFIER_MIN_USER_SET_LOWER_BOUND)
-        assertThat(modifier.brightnessLowerBound).isEqualTo(0.05f)
-    }
 }
 
diff --git a/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java b/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java
index 22c10f9..067230a 100644
--- a/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java
+++ b/services/tests/displayservicetests/src/com/android/server/display/color/ColorDisplayServiceTest.java
@@ -29,7 +29,6 @@
 import static org.mockito.Mockito.reset;
 import static org.mockito.Mockito.times;
 import static org.mockito.Mockito.verify;
-import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
@@ -113,10 +112,10 @@
         doReturn(mContext).when(mContext).getApplicationContext();
 
         final Resources res = Mockito.spy(mContext.getResources());
+        doReturn(res).when(mContext).getResources();
         doReturn(MINIMAL_COLOR_MODES).when(res).getIntArray(R.array.config_availableColorModes);
         doReturn(true).when(res).getBoolean(R.bool.config_nightDisplayAvailable);
         doReturn(true).when(res).getBoolean(R.bool.config_displayWhiteBalanceAvailable);
-        when(mContext.getResources()).thenReturn(res);
         mResourcesSpy = res;
 
         mUserId = ActivityManager.getCurrentUser();
@@ -1105,10 +1104,11 @@
 
     @Test
     public void compositionColorSpaces_noResources() {
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
-            .thenReturn(new int[] {});
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
-            .thenReturn(new int[] {});
+        doReturn(new int[] {}).when(mResourcesSpy)
+                .getIntArray(R.array.config_displayCompositionColorModes);
+        doReturn(new int[] {}).when(mResourcesSpy)
+                .getIntArray(R.array.config_displayCompositionColorSpaces);
+
         setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
         startService();
         verify(mDisplayTransformManager).setColorMode(
@@ -1118,16 +1118,15 @@
 
     @Test
     public void compositionColorSpaces_invalidResources() {
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
-                .thenReturn(new int[] {
-                        ColorDisplayManager.COLOR_MODE_NATURAL,
-                        // Missing second color mode
-                });
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
-                .thenReturn(new int[] {
-                        Display.COLOR_MODE_SRGB,
-                        Display.COLOR_MODE_DISPLAY_P3
-                });
+        doReturn(new int[] {
+                ColorDisplayManager.COLOR_MODE_NATURAL,
+                // Missing second color mode
+        }).when(mResourcesSpy).getIntArray(R.array.config_displayCompositionColorModes);
+        doReturn(new int[] {
+                Display.COLOR_MODE_SRGB,
+                Display.COLOR_MODE_DISPLAY_P3
+        }).when(mResourcesSpy).getIntArray(R.array.config_displayCompositionColorSpaces);
+
         setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
         startService();
         verify(mDisplayTransformManager).setColorMode(
@@ -1137,14 +1136,13 @@
 
     @Test
     public void compositionColorSpaces_validResources_validColorMode() {
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
-                .thenReturn(new int[] {
-                        ColorDisplayManager.COLOR_MODE_NATURAL
-                });
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
-                .thenReturn(new int[] {
-                        Display.COLOR_MODE_SRGB,
-                });
+        doReturn(new int[] {
+                ColorDisplayManager.COLOR_MODE_NATURAL
+        }).when(mResourcesSpy).getIntArray(R.array.config_displayCompositionColorModes);
+        doReturn(new int[] {
+                Display.COLOR_MODE_SRGB,
+        }).when(mResourcesSpy).getIntArray(R.array.config_displayCompositionColorSpaces);
+
         setColorMode(ColorDisplayManager.COLOR_MODE_NATURAL);
         startService();
         verify(mDisplayTransformManager).setColorMode(
@@ -1154,14 +1152,13 @@
 
     @Test
     public void compositionColorSpaces_validResources_invalidColorMode() {
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorModes))
-                .thenReturn(new int[] {
-                        ColorDisplayManager.COLOR_MODE_NATURAL
-                });
-        when(mResourcesSpy.getIntArray(R.array.config_displayCompositionColorSpaces))
-                .thenReturn(new int[] {
-                        Display.COLOR_MODE_SRGB,
-                });
+        doReturn(new int[] {
+                ColorDisplayManager.COLOR_MODE_NATURAL
+        }).when(mResourcesSpy).getIntArray(R.array.config_displayCompositionColorModes);
+        doReturn(new int[] {
+                Display.COLOR_MODE_SRGB,
+        }).when(mResourcesSpy).getIntArray(R.array.config_displayCompositionColorSpaces);
+
         setColorMode(ColorDisplayManager.COLOR_MODE_BOOSTED);
         startService();
         verify(mDisplayTransformManager).setColorMode(
@@ -1171,8 +1168,7 @@
 
     @Test
     public void getColorMode_noAvailableModes_returnsNotSet() {
-        when(mResourcesSpy.getIntArray(R.array.config_availableColorModes))
-                    .thenReturn(new int[] {});
+        doReturn(new int[] {}).when(mResourcesSpy).getIntArray(R.array.config_availableColorModes);
         startService();
         verify(mDisplayTransformManager, never()).setColorMode(anyInt(), any(), any(), anyInt());
         assertThat(mBinderService.getColorMode()).isEqualTo(-1);
@@ -1197,16 +1193,17 @@
 
     @Test
     public void sliderScalesWithinRange() {
+        doReturn(true).when(mRbcSpy).isAvailable(mContext);
+
+        doReturn(85).when(mResourcesSpy).getInteger(
+                R.integer.config_reduceBrightColorsStrengthMax);
+        doReturn(10).when(mResourcesSpy).getInteger(
+                R.integer.config_reduceBrightColorsStrengthMin);
+        doReturn(44).when(mResourcesSpy).getInteger(
+                R.integer.config_reduceBrightColorsStrengthDefault);
+
         // setup
         startService();
-        reset(mRbcSpy);
-        doReturn(true).when(mRbcSpy).isAvailable(mContext);
-        when(mContext.getResources().getInteger(
-                R.integer.config_reduceBrightColorsStrengthMax)).thenReturn(85);
-        when(mContext.getResources().getInteger(
-                R.integer.config_reduceBrightColorsStrengthMin)).thenReturn(10);
-        when(mContext.getResources().getInteger(
-                R.integer.config_reduceBrightColorsStrengthDefault)).thenReturn(44);
 
         // Valid value test //
         // set on, and to 90% of range
diff --git a/services/tests/media/mediarouterservicetest/Android.bp b/services/tests/media/mediarouterservicetest/Android.bp
index aed3af6..f149f2e 100644
--- a/services/tests/media/mediarouterservicetest/Android.bp
+++ b/services/tests/media/mediarouterservicetest/Android.bp
@@ -9,6 +9,10 @@
 
 android_test {
     name: "MediaRouterServiceTests",
+    defaults: [
+        // For ExtendedMockito dependencies.
+        "modules-utils-testable-device-config-defaults",
+    ],
     srcs: [
         "src/**/*.java",
     ],
@@ -23,12 +27,17 @@
         "services.core",
         "truth",
     ],
+    libs: [
+        "android.test.base.stubs",
+        "android.test.runner.stubs",
+    ],
 
     platform_apis: true,
 
     test_suites: [
         // "device-tests",
         "general-tests",
+        "mts-statsd",
     ],
 
     certificate: "platform",
@@ -36,4 +45,5 @@
     optimize: {
         enabled: false,
     },
+    min_sdk_version: "30",
 }
diff --git a/services/tests/media/mediarouterservicetest/AndroidTest.xml b/services/tests/media/mediarouterservicetest/AndroidTest.xml
index b065681..646812b 100644
--- a/services/tests/media/mediarouterservicetest/AndroidTest.xml
+++ b/services/tests/media/mediarouterservicetest/AndroidTest.xml
@@ -17,6 +17,7 @@
     <option name="test-tag" value="MediaRouterServiceTests" />
     <option name="test-suite-tag" value="apct" />
     <option name="test-suite-tag" value="apct-instrumentation" />
+    <option name="test-suite-tag" value="mts" />
 
     <target_preparer class="com.android.tradefed.targetprep.RootTargetPreparer"/>
 
@@ -26,7 +27,7 @@
         <option name="install-arg" value="-t" />
     </target_preparer>
 
-    <test class="com.android.tradefed.testtype.InstrumentationTest" >
+    <test class="com.android.tradefed.testtype.AndroidJUnitTest" >
         <option name="package" value="com.android.server.media.tests" />
         <option name="runner" value="androidx.test.runner.AndroidJUnitRunner" />
         <option name="hidden-api-checks" value="false"/>
diff --git a/services/tests/media/mediarouterservicetest/src/com/android/server/media/MediaRouterMetricLoggerTest.java b/services/tests/media/mediarouterservicetest/src/com/android/server/media/MediaRouterMetricLoggerTest.java
new file mode 100644
index 0000000..5e401ae
--- /dev/null
+++ b/services/tests/media/mediarouterservicetest/src/com/android/server/media/MediaRouterMetricLoggerTest.java
@@ -0,0 +1,140 @@
+/*
+ * Copyright 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.media;
+
+import static android.media.MediaRoute2ProviderService.REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA;
+import static android.media.MediaRoute2ProviderService.REASON_INVALID_COMMAND;
+import static android.media.MediaRoute2ProviderService.REASON_NETWORK_ERROR;
+import static android.media.MediaRoute2ProviderService.REASON_REJECTED;
+import static android.media.MediaRoute2ProviderService.REASON_ROUTE_NOT_AVAILABLE;
+import static android.media.MediaRoute2ProviderService.REASON_UNIMPLEMENTED;
+import static android.media.MediaRoute2ProviderService.REASON_UNKNOWN_ERROR;
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_FAILED_TO_REROUTE_SYSTEM_MEDIA;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_NETWORK_ERROR;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_REJECTED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTE_NOT_AVAILABLE;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNIMPLEMENTED;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNKNOWN_ERROR;
+import static com.android.server.media.MediaRouterStatsLog.MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED;
+import static com.google.common.truth.Truth.assertThat;
+
+import androidx.test.runner.AndroidJUnit4;
+import com.android.modules.utils.testing.ExtendedMockitoRule;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class MediaRouterMetricLoggerTest {
+    @Rule
+    public final ExtendedMockitoRule mExtendedMockitoRule =
+            new ExtendedMockitoRule.Builder(this).mockStatic(MediaRouterStatsLog.class).build();
+
+    private MediaRouterMetricLogger mLogger;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mLogger = new MediaRouterMetricLogger();
+    }
+
+    @Test
+    public void addRequestInfo_addsRequestInfoToCache() {
+        long requestId = 123;
+        int eventType = MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
+
+        mLogger.addRequestInfo(requestId, eventType);
+
+        assertThat(mLogger.getRequestCacheSize()).isEqualTo(1);
+    }
+
+    @Test
+    public void removeRequestInfo_removesRequestInfoFromCache() {
+        long requestId = 123;
+        int eventType = MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
+        mLogger.addRequestInfo(requestId, eventType);
+
+        mLogger.removeRequestInfo(requestId);
+
+        assertThat(mLogger.getRequestCacheSize()).isEqualTo(0);
+    }
+
+    @Test
+    public void logOperationFailure_logsOperationFailure() {
+        int eventType = MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
+        int result = MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_REJECTED;
+        mLogger.logOperationFailure(eventType, result);
+        verify(
+                () ->
+                        MediaRouterStatsLog.write( // Use ExtendedMockito.verify and lambda
+                                MEDIA_ROUTER_EVENT_REPORTED, eventType, result));
+    }
+
+    @Test
+    public void logRequestResult_logsRequestResult() {
+        long requestId = 123;
+        int eventType = MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION;
+        int result = MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_SUCCESS;
+        mLogger.addRequestInfo(requestId, eventType);
+
+        mLogger.logRequestResult(requestId, result);
+
+        assertThat(mLogger.getRequestCacheSize()).isEqualTo(0);
+        verify(
+                () ->
+                        MediaRouterStatsLog.write( // Use ExtendedMockito.verify and lambda
+                                MEDIA_ROUTER_EVENT_REPORTED, eventType, result));
+    }
+
+    @Test
+    public void convertResultFromReason_returnsCorrectResult() {
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(REASON_UNKNOWN_ERROR))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNKNOWN_ERROR);
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(REASON_REJECTED))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_REJECTED);
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(REASON_NETWORK_ERROR))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_NETWORK_ERROR);
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(REASON_ROUTE_NOT_AVAILABLE))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_ROUTE_NOT_AVAILABLE);
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(REASON_INVALID_COMMAND))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_INVALID_COMMAND);
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(REASON_UNIMPLEMENTED))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNIMPLEMENTED);
+        assertThat(
+                        MediaRouterMetricLogger.convertResultFromReason(
+                                REASON_FAILED_TO_REROUTE_SYSTEM_MEDIA))
+                .isEqualTo(
+                        MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_FAILED_TO_REROUTE_SYSTEM_MEDIA);
+        assertThat(MediaRouterMetricLogger.convertResultFromReason(-1))
+                .isEqualTo(MEDIA_ROUTER_EVENT_REPORTED__RESULT__RESULT_UNSPECIFIED);
+    }
+
+    @Test
+    public void getRequestCacheSize_returnsCorrectSize() {
+        assertThat(mLogger.getRequestCacheSize()).isEqualTo(0);
+        mLogger.addRequestInfo(
+                123, MEDIA_ROUTER_EVENT_REPORTED__EVENT_TYPE__EVENT_TYPE_CREATE_SESSION);
+        assertThat(mLogger.getRequestCacheSize()).isEqualTo(1);
+    }
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastProcessedEventRecordTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastProcessedEventRecordTest.java
new file mode 100644
index 0000000..7d8d9a5
--- /dev/null
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastProcessedEventRecordTest.java
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.am;
+
+import static android.app.AppProtoEnums.BROADCAST_TYPE_FOREGROUND;
+import static android.app.AppProtoEnums.BROADCAST_TYPE_STICKY;
+import static android.os.Process.SYSTEM_UID;
+
+import static com.android.internal.util.FrameworkStatsLog.BROADCAST_PROCESSED;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.eq;
+
+import androidx.test.filters.SmallTest;
+
+import com.android.dx.mockito.inline.extended.ExtendedMockito;
+import com.android.internal.util.FrameworkStatsLog;
+import com.android.modules.utils.testing.ExtendedMockitoRule;
+
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+@SmallTest
+public class BroadcastProcessedEventRecordTest {
+
+    private static final String ACTION = "action";
+    private static final String PROCESS_NAME = "process";
+    private static final int[] BROADCAST_TYPES =
+            new int[]{BROADCAST_TYPE_FOREGROUND, BROADCAST_TYPE_STICKY};
+
+    private BroadcastProcessedEventRecord mBroadcastProcessedEventRecord;
+
+    @Rule
+    public final ExtendedMockitoRule mExtendedMockitoRule = new ExtendedMockitoRule.Builder(
+            this).mockStatic(FrameworkStatsLog.class).build();
+
+    @Before
+    public void setUp() {
+        mBroadcastProcessedEventRecord = createBroadcastProcessEventRecord();
+    }
+
+    @Test
+    public void addReceiverFinishDetails_withNewRecord_updatesBroadcastRecordEventTime() {
+        assertThat(mBroadcastProcessedEventRecord.getReceiverUidForTest()).isEqualTo(SYSTEM_UID);
+        assertThat(mBroadcastProcessedEventRecord.getSenderUidForTest()).isEqualTo(SYSTEM_UID);
+        assertThat(mBroadcastProcessedEventRecord.getIntentActionForTest()).isEqualTo(ACTION);
+        assertThat(mBroadcastProcessedEventRecord.getReceiverProcessNameForTest()).isEqualTo(
+                PROCESS_NAME);
+        assertThat(mBroadcastProcessedEventRecord.getBroadcastTypesForTest()).isEqualTo(
+                BROADCAST_TYPES);
+
+        mBroadcastProcessedEventRecord.addReceiverFinishTime(20);
+        verifyBroadcastProcessEventUpdateRecord(
+                /* numberOfReceivers= */ 1,
+                /* totalBroadcastFinishTimeMillis= */ 20,
+                /* maxReceiverFinishTimeMillis= */ 20);
+
+        mBroadcastProcessedEventRecord.addReceiverFinishTime(25);
+        verifyBroadcastProcessEventUpdateRecord(
+                /* numberOfReceivers= */ 2,
+                /* totalBroadcastFinishTimeMillis= */ 45,
+                /* maxReceiverFinishTimeMillis= */ 25);
+
+        mBroadcastProcessedEventRecord.addReceiverFinishTime(10);
+        verifyBroadcastProcessEventUpdateRecord(
+                /* numberOfReceivers= */ 3,
+                /* totalBroadcastFinishTimeMillis= */ 55,
+                /* maxReceiverFinishTimeMillis= */ 25);
+    }
+
+    @Test
+    public void logToStatsD_loggingSuccessful() {
+        mBroadcastProcessedEventRecord.addReceiverFinishTime(20);
+        mBroadcastProcessedEventRecord.logToStatsD();
+
+        ExtendedMockito.verify(() -> FrameworkStatsLog.write(eq(BROADCAST_PROCESSED),
+                eq(ACTION),
+                eq(SYSTEM_UID),
+                eq(SYSTEM_UID),
+                eq(1),
+                eq(PROCESS_NAME),
+                eq(20L),
+                eq(20L),
+                eq(BROADCAST_TYPES)));
+    }
+
+    @Test
+    public void logToStatsD_withTotalTimeLessThanTenMs_NoLogging() {
+        mBroadcastProcessedEventRecord.addReceiverFinishTime(8);
+        mBroadcastProcessedEventRecord.logToStatsD();
+
+        ExtendedMockito.verify(() -> FrameworkStatsLog.write(eq(BROADCAST_PROCESSED),
+                eq(ACTION),
+                eq(SYSTEM_UID),
+                eq(SYSTEM_UID),
+                eq(1),
+                eq(PROCESS_NAME),
+                eq(8L),
+                eq(8L),
+                eq(BROADCAST_TYPES)), Mockito.never());
+    }
+
+    private BroadcastProcessedEventRecord createBroadcastProcessEventRecord() {
+        return new BroadcastProcessedEventRecord()
+                .setBroadcastTypes(BROADCAST_TYPES)
+                .setIntentAction(ACTION)
+                .setReceiverProcessName(PROCESS_NAME)
+                .setReceiverUid(SYSTEM_UID)
+                .setSenderUid(SYSTEM_UID);
+    }
+
+    private void verifyBroadcastProcessEventUpdateRecord(
+            int numberOfReceivers,
+            long totalBroadcastFinishTimeMillis,
+            long maxReceiverFinishTimeMillis) {
+        assertThat(mBroadcastProcessedEventRecord.getNumberOfReceiversForTest())
+                .isEqualTo(numberOfReceivers);
+        assertThat(mBroadcastProcessedEventRecord.getTotalBroadcastFinishTimeMillisForTest())
+                .isEqualTo(totalBroadcastFinishTimeMillis);
+        assertThat(mBroadcastProcessedEventRecord.getMaxReceiverFinishTimeMillisForTest())
+                .isEqualTo(maxReceiverFinishTimeMillis);
+    }
+
+}
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueImplTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueImplTest.java
index b32ce49..6726088 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueImplTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastQueueImplTest.java
@@ -87,6 +87,7 @@
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 
 import java.io.PrintWriter;
 import java.io.Writer;
@@ -1769,6 +1770,33 @@
     }
 
     @Test
+    public void testBroadcastProcessedEventRecord_broadcastDelivered_processedEventLogged()
+            throws Exception {
+        testBroadcastProcessedEventRecordLogged(
+                /* isAssumedDelivered= */ false,
+                /* isDelivered= */ true,
+                /* numberOfInvocations= */ 1);
+    }
+
+    @Test
+    public void testBroadcastProcessedEventRecord_broadcastDeliveryFailed_eventNotLogged()
+            throws Exception {
+        testBroadcastProcessedEventRecordLogged(
+                /* isAssumedDelivered= */ false,
+                /* isDelivered= */ false,
+                /* numberOfInvocations= */ 0);
+    }
+
+    @Test
+    public void testBroadcastProcessedEventRecord_broadcastAssumedDelivered_eventNotLogged()
+            throws Exception {
+        testBroadcastProcessedEventRecordLogged(
+                /* isAssumedDelivered= */ true,
+                /* isDelivered= */ true,
+                /* numberOfInvocations= */ 0);
+    }
+
+    @Test
     public void testGetPreferredSchedulingGroup() throws Exception {
         final BroadcastProcessQueue queue = new BroadcastProcessQueue(mConstants,
                 PACKAGE_GREEN, getUidForPackage(PACKAGE_GREEN));
@@ -2310,6 +2338,28 @@
         assertFalse(mImpl.isProcessFreezable(greenProcess));
     }
 
+    @SuppressWarnings("GuardedBy")
+    private void testBroadcastProcessedEventRecordLogged(
+            boolean isAssumedDelivered,
+            boolean isDelivered,
+            int numberOfInvocations) throws Exception {
+        final Intent timeTick = new Intent(Intent.ACTION_TIME_TICK);
+        final BroadcastOptions optionsTimeTick = BroadcastOptions.makeBasic();
+        optionsTimeTick.setDeliveryGroupPolicy(BroadcastOptions.DELIVERY_GROUP_POLICY_MOST_RECENT);
+
+        final BroadcastRecord broadcastRecordSpy = Mockito.spy(
+                makeBroadcastRecord(timeTick, optionsTimeTick));
+        mImpl.enqueueBroadcastLocked(broadcastRecordSpy);
+
+        doReturn(isDelivered).when(broadcastRecordSpy).wasDelivered(anyInt());
+        doReturn(isAssumedDelivered).when(broadcastRecordSpy).isAssumedDelivered(anyInt());
+        waitForIdle();
+
+        verify(broadcastRecordSpy, times(numberOfInvocations)).updateBroadcastProcessedEventRecord(
+                any(), anyLong());
+        verify(broadcastRecordSpy).logBroadcastProcessedEventRecord();
+    }
+
     BroadcastFilter makeRegisteredReceiver(ProcessRecord app, int priority) {
         final IIntentReceiver receiver = mock(IIntentReceiver.class);
         final ReceiverList receiverList = new ReceiverList(mAms, app, app.getPid(), app.info.uid,
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
index 8482fd6..3ea83de 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/BroadcastRecordTest.java
@@ -30,14 +30,20 @@
 import static com.android.server.am.BroadcastRecord.calculateUrgent;
 import static com.android.server.am.BroadcastRecord.isReceiverEquals;
 
+import static com.google.common.truth.Truth.assertThat;
+
 import static org.junit.Assert.assertArrayEquals;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.argThat;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
 
 import android.app.BackgroundStartPrivileges;
 import android.app.BroadcastOptions;
@@ -66,6 +72,7 @@
 import org.junit.runner.RunWith;
 import org.mockito.ArgumentMatcher;
 import org.mockito.Mock;
+import org.mockito.Mockito;
 import org.mockito.MockitoAnnotations;
 import org.mockito.junit.MockitoJUnitRunner;
 
@@ -93,6 +100,9 @@
     private static final String PACKAGE2 = "pkg2";
     private static final String PACKAGE3 = "pkg3";
 
+    private static final String PROCESS1 = "process1";
+    private static final String PROCESS2 = "process2";
+
     private static final int SYSTEM_UID = android.os.Process.SYSTEM_UID;
     private static final int APP_UID = android.os.Process.FIRST_APPLICATION_UID;
 
@@ -1005,6 +1015,142 @@
                                 createResolveInfo(PACKAGE3, getAppId(3)))));
     }
 
+
+    @Test
+    @DisableFlags(Flags.FLAG_LOG_BROADCAST_PROCESSED_EVENT)
+    public void testUpdateBroadcastProcessedEventRecord_flagDisabled() {
+        final ResolveInfo receiver = createResolveInfo(PACKAGE1, getAppId(1));
+        final BroadcastRecord record = createBroadcastRecord(
+                new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
+                List.of(receiver));
+
+        record.updateBroadcastProcessedEventRecord(receiver, 10);
+
+        assertThat(record.getBroadcastProcessedRecordsForTest()).isEmpty();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_LOG_BROADCAST_PROCESSED_EVENT)
+    public void testUpdateBroadcastProcessedEventRecord_withNewReceiver_newBroadcastProcessedEventRecordCreated() {
+        final ResolveInfo receiver =
+                createResolveInfoWithProcessName(PACKAGE1, getAppId(1), PROCESS1);
+        final BroadcastRecord record = createBroadcastRecord(
+                new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
+                List.of(receiver));
+
+        record.updateBroadcastProcessedEventRecord(receiver, 10);
+
+        assertThat(record.getBroadcastProcessedRecordsForTest()).isNotEmpty();
+        final BroadcastProcessedEventRecord broadcastProcessedEventRecord =
+                record.getBroadcastProcessedRecordsForTest().get(
+                        BroadcastRecord.getReceiverProcessName(receiver));
+
+        assertBroadcastProcessedEvent(
+                broadcastProcessedEventRecord,
+                10001,
+                PROCESS1,
+                1,
+                2,
+                10,
+                10);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_LOG_BROADCAST_PROCESSED_EVENT)
+    public void testUpdateBroadcastProcessedEventRecord_withNewAndExistingReceiver_multipleBroadcastProcessedEventRecordCreated() {
+        final ResolveInfo receiver1 =
+                createResolveInfoWithProcessName(PACKAGE1, getAppId(1), PROCESS1);
+
+        final ResolveInfo receiver2 =
+                createResolveInfoWithProcessName(PACKAGE2, getAppId(2), PROCESS2);
+
+        final BroadcastRecord record = createBroadcastRecord(
+                new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
+                List.of(receiver1, receiver2));
+
+        record.updateBroadcastProcessedEventRecord(receiver1, 11);
+        record.updateBroadcastProcessedEventRecord(receiver2, 11);
+        record.updateBroadcastProcessedEventRecord(receiver1, 20);
+
+        assertThat(record.getBroadcastProcessedRecordsForTest().size()).isEqualTo(2);
+        final BroadcastProcessedEventRecord broadcastProcessedEventRecord1 =
+                record.getBroadcastProcessedRecordsForTest().get(
+                        BroadcastRecord.getReceiverProcessName(receiver1));
+        final BroadcastProcessedEventRecord broadcastProcessedEventRecord2 =
+                record.getBroadcastProcessedRecordsForTest().get(
+                        BroadcastRecord.getReceiverProcessName(receiver2));
+
+        assertBroadcastProcessedEvent(
+                broadcastProcessedEventRecord1,
+                10001,
+                PROCESS1,
+                2,
+                1,
+                31,
+                20);
+        assertBroadcastProcessedEvent(
+                broadcastProcessedEventRecord2,
+                10002,
+                PROCESS2,
+                1,
+                1,
+                11,
+                11);
+    }
+
+    @Test
+    @DisableFlags(Flags.FLAG_LOG_BROADCAST_PROCESSED_EVENT)
+    public void testLogBroadcastProcessedEventRecord_flagDisabled() {
+        testLogBroadcastProcessedEventRecord(0);
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_LOG_BROADCAST_PROCESSED_EVENT)
+    public void testLogBroadcastProcessedEventRecord_flagEnabled_allBroadcastProcessedEventLogged() {
+        testLogBroadcastProcessedEventRecord(1);
+    }
+
+    private void testLogBroadcastProcessedEventRecord(int times) {
+        final ResolveInfo receiver = createResolveInfo(PACKAGE1, getAppId(1));
+        final BroadcastRecord record = createBroadcastRecord(
+                new Intent(Intent.ACTION_AIRPLANE_MODE_CHANGED),
+                List.of(receiver));
+
+        final BroadcastProcessedEventRecord broadcastProcessedEventRecord = Mockito.mock(
+                BroadcastProcessedEventRecord.class);
+        record.getBroadcastProcessedRecordsForTest()
+                .put("process", broadcastProcessedEventRecord);
+        record.logBroadcastProcessedEventRecord();
+        doNothing().when(broadcastProcessedEventRecord).logToStatsD();
+
+        verify(broadcastProcessedEventRecord, times(times)).logToStatsD();
+    }
+
+    private void assertBroadcastProcessedEvent(
+            BroadcastProcessedEventRecord broadcastProcessedEventRecord,
+            int receiverUid,
+            String processName,
+            int numberOfReceivers,
+            int broadcastTypeLength,
+            long totalBroadcastFinishTimeMillis,
+            long maxReceiverFinishTimeMillis) {
+        assertNotNull(broadcastProcessedEventRecord);
+        assertThat(broadcastProcessedEventRecord.getReceiverUidForTest()).isEqualTo(receiverUid);
+        assertThat(broadcastProcessedEventRecord.getSenderUidForTest()).isEqualTo(0);
+        assertThat(broadcastProcessedEventRecord.getIntentActionForTest())
+                .isEqualTo(Intent.ACTION_AIRPLANE_MODE_CHANGED);
+        assertThat(broadcastProcessedEventRecord.getReceiverProcessNameForTest())
+                .isEqualTo(processName);
+        assertThat(broadcastProcessedEventRecord.getBroadcastTypesForTest().length)
+                .isEqualTo(broadcastTypeLength);
+        assertThat(broadcastProcessedEventRecord.getNumberOfReceiversForTest())
+                .isEqualTo(numberOfReceivers);
+        assertThat(broadcastProcessedEventRecord.getTotalBroadcastFinishTimeMillisForTest())
+                .isEqualTo(totalBroadcastFinishTimeMillis);
+        assertThat(broadcastProcessedEventRecord.getMaxReceiverFinishTimeMillisForTest())
+                .isEqualTo(maxReceiverFinishTimeMillis);
+    }
+
     private boolean[] calculateChangeState(List<Object> receivers) {
         return BroadcastRecord.calculateChangeStateForReceivers(receivers,
                 LIMIT_PRIORITY_SCOPE, mPlatformCompat);
@@ -1049,6 +1195,16 @@
         return createResolveInfo(PACKAGE1, getAppId(1), priority);
     }
 
+    private static ResolveInfo createResolveInfoWithProcessName(
+            String packageName,
+            int uid,
+            String processName) {
+        final ResolveInfo resolveInfo = createResolveInfo(packageName, uid);
+        resolveInfo.activityInfo.processName = processName;
+
+        return resolveInfo;
+    }
+
     private static ResolveInfo createResolveInfo(String packageName, int uid) {
         return createResolveInfo(packageName, uid, 0);
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
index 340115a..5d8f578 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/MockingOomAdjusterTests.java
@@ -43,6 +43,7 @@
 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_NONE;
 import static android.app.ActivityManagerInternal.OOM_ADJ_REASON_SHORT_FGS_TIMEOUT;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SHORT_SERVICE;
+import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_SPECIAL_USE;
 
 import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
 
@@ -107,6 +108,7 @@
 import android.os.Process;
 import android.os.SystemClock;
 import android.os.UserHandle;
+import android.platform.test.annotations.DisableFlags;
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.platform.test.flag.junit.SetFlagsRule;
@@ -698,7 +700,7 @@
 
     @SuppressWarnings("GuardedBy")
     @Test
-    @EnableFlags(Flags.FLAG_USE_CPU_TIME_CAPABILITY)
+    @EnableFlags({Flags.FLAG_USE_CPU_TIME_CAPABILITY, Flags.FLAG_PROTOTYPE_AGGRESSIVE_FREEZING})
     public void testUpdateOomAdjFreezeState_bindingFromShortFgs() {
         // Setting up a started short FGS within app1.
         final ServiceRecord s = ServiceRecord.newEmptyInstanceForTest(mService);
@@ -744,6 +746,44 @@
     @SuppressWarnings("GuardedBy")
     @Test
     @EnableFlags(Flags.FLAG_USE_CPU_TIME_CAPABILITY)
+    @DisableFlags(Flags.FLAG_PROTOTYPE_AGGRESSIVE_FREEZING)
+    public void testUpdateOomAdjFreezeState_bindingFromFgs() {
+        final ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        mProcessStateController.setHasForegroundServices(app.mServices, true,
+                FOREGROUND_SERVICE_TYPE_SPECIAL_USE, false);
+
+        final ProcessRecord app2 = spy(makeDefaultProcessRecord(MOCKAPP2_PID, MOCKAPP2_UID,
+                MOCKAPP2_PROCESSNAME, MOCKAPP2_PACKAGENAME, false));
+        // App with a foreground service binds to app2
+        bindService(app2, app, null, null, 0, mock(IBinder.class));
+
+        setProcessesToLru(app, app2);
+        updateOomAdj(app);
+
+        assertCpuTime(app);
+        assertCpuTime(app2);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    @EnableFlags(Flags.FLAG_USE_CPU_TIME_CAPABILITY)
+    @DisableFlags(Flags.FLAG_PROTOTYPE_AGGRESSIVE_FREEZING)
+    public void testUpdateOomAdjFreezeState_soloFgs() {
+        final ProcessRecord app = spy(makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
+                MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true));
+        mProcessStateController.setHasForegroundServices(app.mServices, true,
+                FOREGROUND_SERVICE_TYPE_SPECIAL_USE, false);
+
+        setProcessesToLru(app);
+        updateOomAdj(app);
+
+        assertCpuTime(app);
+    }
+
+    @SuppressWarnings("GuardedBy")
+    @Test
+    @EnableFlags(Flags.FLAG_USE_CPU_TIME_CAPABILITY)
     public void testUpdateOomAdjFreezeState_receivers() {
         final ProcessRecord app = makeDefaultProcessRecord(MOCKAPP_PID, MOCKAPP_UID,
                 MOCKAPP_PROCESSNAME, MOCKAPP_PACKAGENAME, true);
diff --git a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
index d6349fc..ab3784b 100644
--- a/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/am/PendingIntentControllerTest.java
@@ -32,7 +32,6 @@
 import static com.android.server.am.PendingIntentRecord.CANCEL_REASON_USER_STOPPED;
 import static com.android.server.am.PendingIntentRecord.FLAG_ACTIVITY_SENDER;
 import static com.android.server.am.PendingIntentRecord.cancelReasonToString;
-import static com.android.window.flags.Flags.balClearAllowlistDuration;
 
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
@@ -216,9 +215,7 @@
                 pir.getAllowlistDurationLocked(token);
         assertNotNull(allowlistDurationLockedAfterClear);
         assertEquals(1000, allowlistDurationLockedAfterClear.duration);
-        assertEquals(balClearAllowlistDuration()
-                        ? TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED
-                        : TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+        assertEquals(TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_NOT_ALLOWED,
                 allowlistDurationLocked.type);
     }
 
diff --git a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
index e030b3f..16adf8f 100644
--- a/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
+++ b/services/tests/mockingservicestests/src/com/android/server/crashrecovery/Android.bp
@@ -60,4 +60,8 @@
         "mts-crashrecovery",
     ],
     min_sdk_version: "36",
+
+    // Test coverage system runs on different devices. Need to
+    // compile for all architecture.
+    compile_multilib: "both",
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp b/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp
index 36b064b..7c02370 100644
--- a/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp
+++ b/services/tests/mockingservicestests/src/com/android/server/rollback/Android.bp
@@ -58,6 +58,10 @@
         "mts-crashrecovery",
     ],
     min_sdk_version: "36",
+
+    // Test coverage system runs on different devices. Need to
+    // compile for all architecture.
+    compile_multilib: "both",
 }
 
 test_module_config {
diff --git a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/Android.bp b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/Android.bp
index ca5952b..e438100 100644
--- a/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/Android.bp
+++ b/services/tests/security/intrusiondetection/src/com/android/server/security/intrusiondetection/TestApp/src/com/android/coretests/apps/testapp/Android.bp
@@ -34,7 +34,6 @@
     srcs: ["**/*.java"],
 
     platform_apis: true,
-    certificate: "platform",
     dxflags: ["--multi-dex"],
     optimize: {
         enabled: false,
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java
index f7b16c8..dd089fc 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/autoclick/AutoclickTypePanelTest.java
@@ -201,11 +201,11 @@
     public void moveToNextCorner_positionButton_rotatesThroughAllPositions() {
         // Define all positions in sequence
         int[][] expectedPositions = {
-                {0, Gravity.END | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90},
-                {1, Gravity.START | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90},
-                {2, Gravity.START | Gravity.TOP, /*x=*/ 15, /*y=*/ 30},
-                {3, Gravity.END | Gravity.TOP, /*x=*/ 15, /*y=*/ 30},
-                {0, Gravity.END | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90}
+                {CORNER_BOTTOM_RIGHT, Gravity.END | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90},
+                {CORNER_BOTTOM_LEFT, Gravity.START | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90},
+                {CORNER_TOP_LEFT, Gravity.START | Gravity.TOP, /*x=*/ 15, /*y=*/ 30},
+                {CORNER_TOP_RIGHT, Gravity.END | Gravity.TOP, /*x=*/ 15, /*y=*/ 30},
+                {CORNER_BOTTOM_RIGHT, Gravity.END | Gravity.BOTTOM, /*x=*/ 15, /*y=*/ 90}
         };
 
         // Check initial position
@@ -270,7 +270,7 @@
         int screenWidth = mTestableContext.getResources().getDisplayMetrics().widthPixels;
 
         // Verify initial corner is bottom-right.
-        assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting())
+        assertThat(mAutoclickTypePanel.getCurrentCornerForTesting())
                 .isEqualTo(CORNER_BOTTOM_RIGHT);
 
         dispatchDragSequence(contentView,
@@ -279,7 +279,7 @@
 
         // Verify snapping to the right.
         assertThat(params.gravity).isEqualTo(Gravity.END | Gravity.TOP);
-        assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting())
+        assertThat(mAutoclickTypePanel.getCurrentCornerForTesting())
                 .isEqualTo(CORNER_TOP_RIGHT);
     }
 
@@ -293,7 +293,7 @@
         int screenWidth = mTestableContext.getResources().getDisplayMetrics().widthPixels;
 
         // Verify initial corner is bottom-right.
-        assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting())
+        assertThat(mAutoclickTypePanel.getCurrentCornerForTesting())
                 .isEqualTo(CORNER_BOTTOM_RIGHT);
 
         dispatchDragSequence(contentView,
@@ -302,7 +302,7 @@
 
         // Verify snapping to the left.
         assertThat(params.gravity).isEqualTo(Gravity.START | Gravity.TOP);
-        assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting())
+        assertThat(mAutoclickTypePanel.getCurrentCornerForTesting())
                 .isEqualTo(CORNER_BOTTOM_LEFT);
     }
 
@@ -319,7 +319,7 @@
 
         // Verify panel is positioned at default bottom-right corner.
         WindowManager.LayoutParams params = panel.getLayoutParamsForTesting();
-        assertThat(panel.getCurrentCornerIndexForTesting()).isEqualTo(CORNER_BOTTOM_RIGHT);
+        assertThat(panel.getCurrentCornerForTesting()).isEqualTo(CORNER_BOTTOM_RIGHT);
         assertThat(params.gravity).isEqualTo(Gravity.END | Gravity.BOTTOM);
         assertThat(params.x).isEqualTo(15);  // Default edge margin.
         assertThat(params.y).isEqualTo(90);  // Default bottom offset.
@@ -353,7 +353,7 @@
         assertThat(params.gravity).isEqualTo(Gravity.START | Gravity.TOP);
         assertThat(params.x).isEqualTo(15);
         assertThat(params.y).isEqualTo(30);
-        assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()).isEqualTo(
+        assertThat(mAutoclickTypePanel.getCurrentCornerForTesting()).isEqualTo(
                 CORNER_TOP_LEFT);
     }
 
@@ -392,7 +392,7 @@
         assertThat(params.gravity).isEqualTo(Gravity.START | Gravity.TOP);
         assertThat(params.x).isEqualTo(15); // PANEL_EDGE_MARGIN
         assertThat(params.y).isEqualTo(panelLocation[1] + 10);
-        assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()).isEqualTo(
+        assertThat(mAutoclickTypePanel.getCurrentCornerForTesting()).isEqualTo(
                 CORNER_BOTTOM_LEFT);
     }
 
@@ -453,7 +453,7 @@
 
     private void verifyPanelPosition(int[] expectedPosition) {
         WindowManager.LayoutParams params = mAutoclickTypePanel.getLayoutParamsForTesting();
-        assertThat(mAutoclickTypePanel.getCurrentCornerIndexForTesting()).isEqualTo(
+        assertThat(mAutoclickTypePanel.getCurrentCornerForTesting()).isEqualTo(
                 expectedPosition[0]);
         assertThat(params.gravity).isEqualTo(expectedPosition[1]);
         assertThat(params.x).isEqualTo(expectedPosition[2]);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
index ac27a97..9ec99c6 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationControllerTest.java
@@ -30,7 +30,10 @@
 import static org.mockito.ArgumentMatchers.anyFloat;
 import static org.mockito.ArgumentMatchers.anyInt;
 import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.ArgumentMatchers.isNull;
+import static org.mockito.ArgumentMatchers.nullable;
 import static org.mockito.Mockito.atLeastOnce;
+import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
 import static org.mockito.Mockito.mock;
@@ -248,6 +251,40 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
+    public void testRegister_RegistersPointerMotionFilter() {
+        register(DISPLAY_0);
+
+        verify(mMockInputManager).registerAccessibilityPointerMotionFilter(
+                any(InputManagerInternal.AccessibilityPointerMotionFilter.class));
+
+        // If a filter is already registered, adding a display won't invoke another filter
+        // registration.
+        clearInvocations(mMockInputManager);
+        register(DISPLAY_1);
+        register(INVALID_DISPLAY);
+
+        verify(mMockInputManager, times(0)).registerAccessibilityPointerMotionFilter(
+                any(InputManagerInternal.AccessibilityPointerMotionFilter.class));
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
+    public void testUnregister_UnregistersPointerMotionFilter() {
+        register(DISPLAY_0);
+        register(DISPLAY_1);
+        clearInvocations(mMockInputManager);
+
+        mFullScreenMagnificationController.unregister(DISPLAY_1);
+        // There's still an active display. Don't unregister yet.
+        verify(mMockInputManager, times(0)).registerAccessibilityPointerMotionFilter(
+                nullable(InputManagerInternal.AccessibilityPointerMotionFilter.class));
+
+        mFullScreenMagnificationController.unregister(DISPLAY_0);
+        verify(mMockInputManager, times(1)).registerAccessibilityPointerMotionFilter(isNull());
+    }
+
+    @Test
     public void testInitialState_noMagnificationAndMagnificationRegionReadFromWindowManager() {
         for (int i = 0; i < DISPLAY_COUNT; i++) {
             initialState_noMagnificationAndMagnificationRegionReadFromWindowManager(i);
@@ -699,6 +736,63 @@
     }
 
     @Test
+    public void testSetOffset_whileMagnifying_offsetsMove() {
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            setOffset_whileMagnifying_offsetsMove(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void setOffset_whileMagnifying_offsetsMove(int displayId) {
+        register(displayId);
+        PointF startCenter = INITIAL_MAGNIFICATION_BOUNDS_CENTER;
+        for (final float scale : new float[]{2.0f, 2.5f, 3.0f}) {
+            assertTrue(mFullScreenMagnificationController
+                    .setScaleAndCenter(displayId, scale, startCenter.x, startCenter.y, true, false,
+                            SERVICE_ID_1));
+            mMessageCapturingHandler.sendAllMessages();
+
+            for (final PointF center : new PointF[]{
+                    INITIAL_BOUNDS_LOWER_RIGHT_2X_CENTER,
+                    INITIAL_BOUNDS_UPPER_LEFT_2X_CENTER}) {
+                Mockito.clearInvocations(mMockWindowManager);
+                PointF newOffsets = computeOffsets(INITIAL_MAGNIFICATION_BOUNDS, center, scale);
+                mFullScreenMagnificationController.setOffset(displayId, newOffsets.x, newOffsets.y,
+                        SERVICE_ID_1);
+                mMessageCapturingHandler.sendAllMessages();
+
+                MagnificationSpec expectedSpec = getMagnificationSpec(scale, newOffsets);
+                verify(mMockWindowManager)
+                        .setMagnificationSpec(eq(displayId), argThat(closeTo(expectedSpec)));
+                assertEquals(center.x, mFullScreenMagnificationController.getCenterX(displayId),
+                        0.0);
+                assertEquals(center.y, mFullScreenMagnificationController.getCenterY(displayId),
+                        0.0);
+                verify(mMockValueAnimator, times(0)).start();
+            }
+        }
+    }
+
+    @Test
+    public void testSetOffset_whileNotMagnifying_hasNoEffect() {
+        for (int i = 0; i < DISPLAY_COUNT; i++) {
+            setOffset_whileNotMagnifying_hasNoEffect(i);
+            resetMockWindowManager();
+        }
+    }
+
+    private void setOffset_whileNotMagnifying_hasNoEffect(int displayId) {
+        register(displayId);
+        Mockito.reset(mMockWindowManager);
+        MagnificationSpec startSpec = getCurrentMagnificationSpec(displayId);
+        mFullScreenMagnificationController.setOffset(displayId, 100, 100, SERVICE_ID_1);
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(startSpec));
+        mFullScreenMagnificationController.setOffset(displayId, 200, 200, SERVICE_ID_1);
+        assertThat(getCurrentMagnificationSpec(displayId), closeTo(startSpec));
+        verifyNoMoreInteractions(mMockWindowManager);
+    }
+
+    @Test
     @RequiresFlagsEnabled(Flags.FLAG_FULLSCREEN_FLING_GESTURE)
     public void testStartFling_whileMagnifying_flings() throws InterruptedException {
         for (int i = 0; i < DISPLAY_COUNT; i++) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index 5c126d1..4ea5fcf 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -1419,6 +1419,12 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
+    public void testMouseMoveEventsDoNotMoveMagnifierViewport() {
+        runMoveEventsDoNotMoveMagnifierViewport(InputDevice.SOURCE_MOUSE);
+    }
+
+    @Test
     public void testStylusMoveEventsDoNotMoveMagnifierViewport() {
         runMoveEventsDoNotMoveMagnifierViewport(InputDevice.SOURCE_STYLUS);
     }
@@ -1467,11 +1473,28 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
+    public void testMouseHoverMoveEventsDoNotMoveMagnifierViewport() {
+        // Note that this means mouse hover shouldn't be handled here.
+        // FullScreenMagnificationPointerMotionEventFilter handles mouse input events.
+        runHoverMoveEventsDoNotMoveMagnifierViewport(InputDevice.SOURCE_MOUSE);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
+    public void testStylusHoverMoveEventsDoNotMoveMagnifierViewport() {
+        // TODO(b/398984690): We will revisit the behavior.
+        runHoverMoveEventsDoNotMoveMagnifierViewport(InputDevice.SOURCE_STYLUS);
+    }
+
+    @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
     public void testMouseHoverMoveEventsMoveMagnifierViewport() {
         runHoverMovesViewportTest(InputDevice.SOURCE_MOUSE);
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
     public void testStylusHoverMoveEventsMoveMagnifierViewport() {
         runHoverMovesViewportTest(InputDevice.SOURCE_STYLUS);
     }
@@ -1497,6 +1520,7 @@
     }
 
     @Test
+    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE_WITH_POINTER_MOTION_FILTER)
     public void testMouseMoveEventsMoveMagnifierViewport() {
         final EventCaptor eventCaptor = new EventCaptor();
         mMgh.setNext(eventCaptor);
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilterTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilterTest.java
new file mode 100644
index 0000000..a8315d4
--- /dev/null
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationPointerMotionEventFilterTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2025 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT 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.accessibility.magnification;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.ArgumentMatchers.anyInt;
+import static org.mockito.ArgumentMatchers.eq;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import androidx.test.runner.AndroidJUnit4;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+
+@RunWith(AndroidJUnit4.class)
+public class FullScreenMagnificationPointerMotionEventFilterTest {
+    @Mock
+    private FullScreenMagnificationController mMockFullScreenMagnificationController;
+
+    private FullScreenMagnificationPointerMotionEventFilter mFilter;
+
+    @Before
+    public void setUp() throws Exception {
+        MockitoAnnotations.initMocks(this);
+
+        mFilter = new FullScreenMagnificationPointerMotionEventFilter(
+                mMockFullScreenMagnificationController);
+    }
+
+    @Test
+    public void inactiveDisplay_doNothing() {
+        when(mMockFullScreenMagnificationController.isActivated(anyInt())).thenReturn(false);
+
+        float[] delta = new float[]{1.f, 2.f};
+        float[] result = mFilter.filterPointerMotionEvent(delta[0], delta[1], 3.0f, 4.0f, 0);
+        assertThat(result).isEqualTo(delta);
+    }
+
+    @Test
+    public void testContinuousMove() {
+        when(mMockFullScreenMagnificationController.isActivated(anyInt())).thenReturn(true);
+        when(mMockFullScreenMagnificationController.getScale(anyInt())).thenReturn(3.f);
+
+        float[] delta = new float[]{5.f, 10.f};
+        float[] result = mFilter.filterPointerMotionEvent(delta[0], delta[1], 20.f, 30.f, 0);
+        assertThat(result).isEqualTo(delta);
+        // At the first cursor move, it goes to (20, 30) + (5, 10) = (25, 40). The scale is 3.0.
+        // The expected offset is (-25 * (3-1), -40 * (3-1)) = (-50, -80).
+        verify(mMockFullScreenMagnificationController)
+                .setOffset(eq(0), eq(-50.f), eq(-80.f), anyInt());
+
+        float[] delta2 = new float[]{10.f, 5.f};
+        float[] result2 = mFilter.filterPointerMotionEvent(delta2[0], delta2[1], 25.f, 40.f, 0);
+        assertThat(result2).isEqualTo(delta2);
+        // At the second cursor move, it goes to (25, 40) + (10, 5) = (35, 40). The scale is 3.0.
+        // The expected offset is (-35 * (3-1), -45 * (3-1)) = (-70, -90).
+        verify(mMockFullScreenMagnificationController)
+                .setOffset(eq(0), eq(-70.f), eq(-90.f), anyInt());
+    }
+}
diff --git a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java
index 50cfa75..57e9cf4 100644
--- a/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java
+++ b/services/tests/servicestests/src/com/android/server/locales/LocaleManagerBackupRestoreTest.java
@@ -95,8 +95,8 @@
     private static final String TEST_LOCALES_XML_TAG = "locales";
     private static final int DEFAULT_USER_ID = 0;
     private static final int WORK_PROFILE_USER_ID = 10;
-    private static final int DEFAULT_UID = Binder.getCallingUid() + 100;
-    private static final int WORK_PROFILE_UID = Binder.getCallingUid() + 1000100;
+    private static final int DEFAULT_UID = 100;
+    private static final int WORK_PROFILE_UID = 1000100;
     private static final long DEFAULT_CREATION_TIME_MILLIS = 1000;
     private static final Duration RETENTION_PERIOD = Duration.ofDays(3);
     private static final LocaleList DEFAULT_LOCALES =
diff --git a/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java b/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java
index 1de864c..565a9b6 100644
--- a/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java
+++ b/services/tests/servicestests/src/com/android/server/location/contexthub/ContextHubEndpointTest.java
@@ -17,6 +17,7 @@
 package com.android.server.location.contexthub;
 
 import static com.google.common.truth.Truth.assertThat;
+
 import static org.mockito.ArgumentMatchers.any;
 import static org.mockito.ArgumentMatchers.eq;
 import static org.mockito.Mockito.timeout;
@@ -42,12 +43,10 @@
 import android.os.RemoteException;
 import android.platform.test.annotations.Presubmit;
 import android.util.Log;
+
 import androidx.test.ext.junit.runners.AndroidJUnit4;
 import androidx.test.platform.app.InstrumentationRegistry;
 
-import java.util.Collections;
-import java.util.List;
-
 import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
@@ -57,6 +56,9 @@
 import org.mockito.junit.MockitoJUnit;
 import org.mockito.junit.MockitoRule;
 
+import java.util.Collections;
+import java.util.List;
+
 @RunWith(AndroidJUnit4.class)
 @Presubmit
 public class ContextHubEndpointTest {
@@ -73,6 +75,12 @@
     private static final String TARGET_ENDPOINT_NAME = "Example target endpoint";
     private static final int TARGET_ENDPOINT_ID = 1;
 
+    private static final int SAMPLE_MESSAGE_TYPE = 1234;
+    private static final HubMessage SAMPLE_MESSAGE =
+            new HubMessage.Builder(SAMPLE_MESSAGE_TYPE, new byte[] {1, 2, 3, 4, 5})
+                    .setResponseRequired(true)
+                    .build();
+
     private ContextHubClientManager mClientManager;
     private ContextHubEndpointManager mEndpointManager;
     private HubInfoRegistry mHubInfoRegistry;
@@ -229,23 +237,34 @@
         assertThat(mTransactionManager.numReliableMessageTransactionPending()).isEqualTo(0);
     }
 
+    @Test
+    public void testDuplicateMessageRejected() throws RemoteException {
+        IContextHubEndpoint endpoint = registerExampleEndpoint();
+        int sessionId = openTestSession(endpoint);
+
+        mEndpointManager.onMessageReceived(sessionId, SAMPLE_MESSAGE);
+        ArgumentCaptor<HubMessage> messageCaptor = ArgumentCaptor.forClass(HubMessage.class);
+        verify(mMockCallback).onMessageReceived(eq(sessionId), messageCaptor.capture());
+        assertThat(messageCaptor.getValue()).isEqualTo(SAMPLE_MESSAGE);
+
+        // Send a duplicate message and confirm it can be rejected
+        mEndpointManager.onMessageReceived(sessionId, SAMPLE_MESSAGE);
+        ArgumentCaptor<MessageDeliveryStatus> statusCaptor =
+                ArgumentCaptor.forClass(MessageDeliveryStatus.class);
+        verify(mMockEndpointCommunications)
+                .sendMessageDeliveryStatusToEndpoint(eq(sessionId), statusCaptor.capture());
+        assertThat(statusCaptor.getValue().messageSequenceNumber)
+                .isEqualTo(SAMPLE_MESSAGE.getMessageSequenceNumber());
+        assertThat(statusCaptor.getValue().errorCode).isEqualTo(ErrorCode.TRANSIENT_ERROR);
+
+        unregisterExampleEndpoint(endpoint);
+    }
+
     /** A helper method to create a session and validates reliable message sending. */
     private void testMessageTransactionInternal(
             IContextHubEndpoint endpoint, boolean deliverMessageStatus) throws RemoteException {
-        HubEndpointInfo targetInfo =
-                new HubEndpointInfo(
-                        TARGET_ENDPOINT_NAME,
-                        TARGET_ENDPOINT_ID,
-                        ENDPOINT_PACKAGE_NAME,
-                        Collections.emptyList());
-        int sessionId = endpoint.openSession(targetInfo, /* serviceDescriptor= */ null);
-        mEndpointManager.onEndpointSessionOpenComplete(sessionId);
+        int sessionId = openTestSession(endpoint);
 
-        final int messageType = 1234;
-        HubMessage message =
-                new HubMessage.Builder(messageType, new byte[] {1, 2, 3, 4, 5})
-                        .setResponseRequired(true)
-                        .build();
         IContextHubTransactionCallback callback =
                 new IContextHubTransactionCallback.Stub() {
                     @Override
@@ -258,13 +277,13 @@
                         Log.i(TAG, "Received onTransactionComplete callback, result=" + result);
                     }
                 };
-        endpoint.sendMessage(sessionId, message, callback);
+        endpoint.sendMessage(sessionId, SAMPLE_MESSAGE, callback);
         ArgumentCaptor<Message> messageCaptor = ArgumentCaptor.forClass(Message.class);
         verify(mMockEndpointCommunications, timeout(1000))
                 .sendMessageToEndpoint(eq(sessionId), messageCaptor.capture());
         Message halMessage = messageCaptor.getValue();
-        assertThat(halMessage.type).isEqualTo(message.getMessageType());
-        assertThat(halMessage.content).isEqualTo(message.getMessageBody());
+        assertThat(halMessage.type).isEqualTo(SAMPLE_MESSAGE.getMessageType());
+        assertThat(halMessage.content).isEqualTo(SAMPLE_MESSAGE.getMessageBody());
         assertThat(mTransactionManager.numReliableMessageTransactionPending()).isEqualTo(1);
 
         if (deliverMessageStatus) {
@@ -308,4 +327,16 @@
                 .isEqualTo(expectedInfo.getIdentifier().getHub());
         assertThat(mEndpointManager.getNumRegisteredClients()).isEqualTo(0);
     }
+
+    private int openTestSession(IContextHubEndpoint endpoint) throws RemoteException {
+        HubEndpointInfo targetInfo =
+                new HubEndpointInfo(
+                        TARGET_ENDPOINT_NAME,
+                        TARGET_ENDPOINT_ID,
+                        ENDPOINT_PACKAGE_NAME,
+                        Collections.emptyList());
+        int sessionId = endpoint.openSession(targetInfo, /* serviceDescriptor= */ null);
+        mEndpointManager.onEndpointSessionOpenComplete(sessionId);
+        return sessionId;
+    }
 }
diff --git a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS
index bb487fb..c8b8e48 100644
--- a/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS
+++ b/services/tests/servicestests/src/com/android/server/locksettings/recoverablekeystore/OWNERS
@@ -1,4 +1,3 @@
 aseemk@google.com
-bozhu@google.com
 dementyev@google.com
 robertberry@google.com
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
index 3727bbe..dd5c601 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -5211,41 +5211,6 @@
     }
 
     @Test
-    public void
-        updateNotificationChannelFromPrivilegedListener_oldSoundNoUriPerm_newSoundHasUriPerm()
-            throws Exception {
-        mService.setPreferencesHelper(mPreferencesHelper);
-        when(mCompanionMgr.getAssociations(mPkg, mUserId))
-                .thenReturn(singletonList(mock(AssociationInfo.class)));
-        when(mPreferencesHelper.getNotificationChannel(eq(mPkg), anyInt(),
-                eq(mTestNotificationChannel.getId()), anyBoolean()))
-                .thenReturn(mTestNotificationChannel);
-
-        // Missing Uri permissions for the old channel sound
-        final Uri oldSoundUri = Settings.System.DEFAULT_NOTIFICATION_URI;
-        doThrow(new SecurityException("no access")).when(mUgmInternal)
-                .checkGrantUriPermission(eq(Process.myUid()), any(), eq(oldSoundUri),
-                anyInt(), eq(Process.myUserHandle().getIdentifier()));
-
-        // Has Uri permissions for the old channel sound
-        final Uri newSoundUri = Uri.parse("content://media/test/sound/uri");
-        final NotificationChannel updatedNotificationChannel = new NotificationChannel(
-                TEST_CHANNEL_ID, TEST_CHANNEL_ID, IMPORTANCE_DEFAULT);
-        updatedNotificationChannel.setSound(newSoundUri,
-                updatedNotificationChannel.getAudioAttributes());
-
-        mBinderService.updateNotificationChannelFromPrivilegedListener(
-                null, mPkg, Process.myUserHandle(), updatedNotificationChannel);
-
-        verify(mPreferencesHelper, times(1)).updateNotificationChannel(
-                anyString(), anyInt(), any(), anyBoolean(),  anyInt(), anyBoolean());
-
-        verify(mListeners, never()).notifyNotificationChannelChanged(eq(mPkg),
-                eq(Process.myUserHandle()), eq(mTestNotificationChannel),
-                eq(NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED));
-    }
-
-    @Test
     public void testGetNotificationChannelFromPrivilegedListener_cdm_success() throws Exception {
         mService.setPreferencesHelper(mPreferencesHelper);
         when(mCompanionMgr.getAssociations(mPkg, mUserId))
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
index 4391152..e9cf036 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/NotificationRecordTest.java
@@ -1009,6 +1009,65 @@
     }
 
     @Test
+    @EnableFlags(Flags.FLAG_NM_SUMMARIZATION)
+    public void testSummarization_null() {
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, groupId /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertThat(record.getSummarization()).isNull();
+
+        Bundle signals = new Bundle();
+        signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, null);
+        record.addAdjustment(new Adjustment(mPkg, record.getKey(), signals, null, sbn.getUserId()));
+
+        record.applyAdjustments();
+
+        assertThat(record.getSummarization()).isNull();
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_NM_SUMMARIZATION)
+    public void testSummarization_charSequence() {
+        CharSequence summary = "hello";
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, groupId /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertThat(record.getSummarization()).isNull();
+
+        Bundle signals = new Bundle();
+        signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, summary);
+        record.addAdjustment(new Adjustment(mPkg, record.getKey(), signals, null, sbn.getUserId()));
+
+        record.applyAdjustments();
+
+        assertThat(record.getSummarization()).isEqualTo(summary.toString());
+    }
+
+    @Test
+    @EnableFlags(Flags.FLAG_NM_SUMMARIZATION)
+    public void testSummarization_string() {
+        String summary = "hello";
+        StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
+                true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
+                false /* lights */, false /* defaultLights */, groupId /* group */);
+        NotificationRecord record = new NotificationRecord(mMockContext, sbn, channel);
+
+        assertThat(record.getSummarization()).isNull();
+
+        Bundle signals = new Bundle();
+        signals.putCharSequence(Adjustment.KEY_SUMMARIZATION, summary);
+        record.addAdjustment(new Adjustment(mPkg, record.getKey(), signals, null, sbn.getUserId()));
+
+        record.applyAdjustments();
+
+        assertThat(record.getSummarization()).isEqualTo(summary);
+    }
+
+    @Test
     public void testSensitiveContent() {
         StatusBarNotification sbn = getNotification(PKG_O, true /* noisy */,
                 true /* defaultSound */, false /* buzzy */, false /* defaultBuzz */,
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
index 752910d..a02f628 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/PreferencesHelperTest.java
@@ -46,13 +46,11 @@
 import static android.app.NotificationManager.IMPORTANCE_NONE;
 import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
 import static android.app.NotificationManager.VISIBILITY_NO_OVERRIDE;
-import static android.content.ContentResolver.SCHEME_ANDROID_RESOURCE;
-import static android.content.ContentResolver.SCHEME_CONTENT;
-import static android.content.ContentResolver.SCHEME_FILE;
 import static android.media.AudioAttributes.CONTENT_TYPE_SONIFICATION;
 import static android.media.AudioAttributes.USAGE_NOTIFICATION;
 import static android.os.UserHandle.USER_ALL;
 import static android.os.UserHandle.USER_SYSTEM;
+
 import static android.platform.test.flag.junit.SetFlagsRule.DefaultInitValueType.DEVICE_DEFAULT;
 import static android.service.notification.Adjustment.TYPE_CONTENT_RECOMMENDATION;
 import static android.service.notification.Adjustment.TYPE_NEWS;
@@ -66,6 +64,7 @@
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__DENIED;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__GRANTED;
 import static com.android.internal.util.FrameworkStatsLog.PACKAGE_NOTIFICATION_PREFERENCES__FSI_STATE__NOT_REQUESTED;
+import static com.android.server.notification.Flags.FLAG_ALL_NOTIFS_NEED_TTL;
 import static com.android.server.notification.Flags.FLAG_PERSIST_INCOMPLETE_RESTORE_DATA;
 import static com.android.server.notification.NotificationChannelLogger.NotificationChannelEvent.NOTIFICATION_CHANNEL_UPDATED_BY_USER;
 import static com.android.server.notification.PreferencesHelper.DEFAULT_BUBBLE_PREFERENCE;
@@ -92,7 +91,6 @@
 import static org.mockito.Mockito.clearInvocations;
 import static org.mockito.Mockito.doAnswer;
 import static org.mockito.Mockito.doReturn;
-import static org.mockito.Mockito.doThrow;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.never;
 import static org.mockito.Mockito.reset;
@@ -385,10 +383,10 @@
 
         mHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mUgmInternal, false, mClock);
+                false, mClock);
         mXmlHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mUgmInternal, false, mClock);
+                false, mClock);
         resetZenModeHelper();
 
         mAudioAttributes = new AudioAttributes.Builder()
@@ -803,7 +801,7 @@
     public void testReadXml_oldXml_migrates() throws Exception {
         mXmlHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mUgmInternal, /* showReviewPermissionsNotification= */ true, mClock);
+                /* showReviewPermissionsNotification= */ true, mClock);
 
         String xml = "<ranking version=\"2\">\n"
                 + "<package name=\"" + PKG_N_MR1 + "\" uid=\"" + UID_N_MR1
@@ -939,7 +937,7 @@
     public void testReadXml_newXml_noMigration_showPermissionNotification() throws Exception {
         mXmlHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mUgmInternal, /* showReviewPermissionsNotification= */ true, mClock);
+                /* showReviewPermissionsNotification= */ true, mClock);
 
         String xml = "<ranking version=\"3\">\n"
                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -998,7 +996,7 @@
     public void testReadXml_newXml_permissionNotificationOff() throws Exception {
         mHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mUgmInternal, /* showReviewPermissionsNotification= */ false, mClock);
+                /* showReviewPermissionsNotification= */ false, mClock);
 
         String xml = "<ranking version=\"3\">\n"
                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -1057,7 +1055,7 @@
     public void testReadXml_newXml_noMigration_noPermissionNotification() throws Exception {
         mHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mUgmInternal, /* showReviewPermissionsNotification= */ true, mClock);
+                /* showReviewPermissionsNotification= */ true, mClock);
 
         String xml = "<ranking version=\"4\">\n"
                 + "<package name=\"" + PKG_N_MR1 + "\" show_badge=\"true\">\n"
@@ -1655,7 +1653,7 @@
         // simulate load after reboot
         mXmlHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mUgmInternal, false, mClock);
+                false, mClock);
         loadByteArrayXml(baos.toByteArray(), false, USER_ALL);
 
         // Trigger 2nd restore pass
@@ -1710,7 +1708,7 @@
         // simulate load after reboot
         mXmlHelper = new TestPreferencesHelper(getContext(), mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mUgmInternal, false, mClock);
+                false, mClock);
         loadByteArrayXml(xml.getBytes(), false, USER_ALL);
 
         // Trigger 2nd restore pass
@@ -1788,10 +1786,10 @@
 
         mHelper = new TestPreferencesHelper(mContext, mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mUgmInternal, false, mClock);
+                false, mClock);
         mXmlHelper = new TestPreferencesHelper(mContext, mPm, mHandler, mMockZenModeHelper,
                 mPermissionHelper, mPermissionManager, mLogger, mAppOpsManager, mUserProfiles,
-                mUgmInternal, false, mClock);
+                false, mClock);
 
         NotificationChannel channel =
                 new NotificationChannel("id", "name", IMPORTANCE_LOW);
@@ -3263,61 +3261,6 @@
     }
 
     @Test
-    public void testCreateChannel_noSoundUriPermission_contentSchemeVerified() {
-        final Uri sound = Uri.parse(SCHEME_CONTENT + "://media/test/sound/uri");
-
-        doThrow(new SecurityException("no access")).when(mUgmInternal)
-                .checkGrantUriPermission(eq(UID_N_MR1), any(), eq(sound),
-                    anyInt(), eq(UserHandle.getUserId(UID_N_MR1)));
-
-        final NotificationChannel channel = new NotificationChannel("id2", "name2",
-                NotificationManager.IMPORTANCE_DEFAULT);
-        channel.setSound(sound, mAudioAttributes);
-
-        assertThrows(SecurityException.class,
-                () -> mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel,
-                    true, false, UID_N_MR1, false));
-        assertThat(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true))
-                .isNull();
-    }
-
-    @Test
-    public void testCreateChannel_noSoundUriPermission_fileSchemaIgnored() {
-        final Uri sound = Uri.parse(SCHEME_FILE + "://path/sound");
-
-        doThrow(new SecurityException("no access")).when(mUgmInternal)
-                .checkGrantUriPermission(eq(UID_N_MR1), any(), any(),
-                    anyInt(), eq(UserHandle.getUserId(UID_N_MR1)));
-
-        final NotificationChannel channel = new NotificationChannel("id2", "name2",
-                NotificationManager.IMPORTANCE_DEFAULT);
-        channel.setSound(sound, mAudioAttributes);
-
-        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, UID_N_MR1,
-                false);
-        assertThat(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true)
-                .getSound()).isEqualTo(sound);
-    }
-
-    @Test
-    public void testCreateChannel_noSoundUriPermission_resourceSchemaIgnored() {
-        final Uri sound = Uri.parse(SCHEME_ANDROID_RESOURCE + "://resId/sound");
-
-        doThrow(new SecurityException("no access")).when(mUgmInternal)
-                .checkGrantUriPermission(eq(UID_N_MR1), any(), any(),
-                    anyInt(), eq(UserHandle.getUserId(UID_N_MR1)));
-
-        final NotificationChannel channel = new NotificationChannel("id2", "name2",
-                NotificationManager.IMPORTANCE_DEFAULT);
-        channel.setSound(sound, mAudioAttributes);
-
-        mHelper.createNotificationChannel(PKG_N_MR1, UID_N_MR1, channel, true, false, UID_N_MR1,
-                false);
-        assertThat(mHelper.getNotificationChannel(PKG_N_MR1, UID_N_MR1, channel.getId(), true)
-                .getSound()).isEqualTo(sound);
-    }
-
-    @Test
     public void testPermanentlyDeleteChannels() throws Exception {
         NotificationChannel channel1 =
                 new NotificationChannel("id1", "name1", NotificationManager.IMPORTANCE_HIGH);
@@ -7086,10 +7029,9 @@
                 ZenModeHelper zenHelper, PermissionHelper permHelper, PermissionManager permManager,
                 NotificationChannelLogger notificationChannelLogger,
                 AppOpsManager appOpsManager, ManagedServices.UserProfiles userProfiles,
-                UriGrantsManagerInternal ugmInternal,
                 boolean showReviewPermissionsNotification, Clock clock) {
             super(context, pm, rankingHandler, zenHelper, permHelper, permManager,
-                    notificationChannelLogger, appOpsManager, userProfiles, ugmInternal,
+                    notificationChannelLogger, appOpsManager, userProfiles,
                     showReviewPermissionsNotification, clock);
         }
 
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 51891ef..5377102 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -203,6 +203,7 @@
 import com.google.protobuf.InvalidProtocolBufferException;
 
 import org.junit.Before;
+import org.junit.Ignore;
 import org.junit.Rule;
 import org.junit.Test;
 import org.junit.runner.RunWith;
@@ -2478,6 +2479,8 @@
     }
 
     @Test
+    @Ignore("TODO: b/398023814 - disabled due to taking a long time; restore when we have a "
+            + "better approach to not timing out")
     public void testAddAutomaticZenRule_claimedSystemOwner() {
         // Make sure anything that claims to have a "system" owner but not actually part of the
         // system package still gets limited on number of rules
diff --git a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
index 6d8a487..3ca0197 100644
--- a/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
+++ b/services/tests/wmtests/src/com/android/server/policy/KeyGestureEventTests.java
@@ -150,8 +150,6 @@
                 {"Meta + Left arrow -> Go back", new int[]{META_KEY, KeyEvent.KEYCODE_DPAD_LEFT},
                         KeyGestureEvent.KEY_GESTURE_TYPE_BACK, KeyEvent.KEYCODE_DPAD_LEFT,
                         META_ON},
-                {"Meta + Del -> Go back", new int[]{META_KEY, KeyEvent.KEYCODE_DEL},
-                        KeyGestureEvent.KEY_GESTURE_TYPE_BACK, KeyEvent.KEYCODE_DEL, META_ON},
                 {"APP_SWITCH key -> Open App switcher", new int[]{KeyEvent.KEYCODE_APP_SWITCH},
                         KeyGestureEvent.KEY_GESTURE_TYPE_APP_SWITCH,
                         KeyEvent.KEYCODE_APP_SWITCH, 0},
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index 39a849a..8992c2e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -724,6 +724,7 @@
 
     @Test
     @EnableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING)
+    @DisableFlags(Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING_OPT_OUT)
     @EnableCompatChanges({OVERRIDE_CAMERA_COMPAT_ENABLE_FREEFORM_WINDOWING_TREATMENT})
     public void testOrientation_allowFixedOrientationForCameraCompatInFreeformWindowing() {
         final ActivityRecord activity = setupDisplayAndActivityForCameraCompat(
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
index d016e735..8fe0855 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatActivityRobot.java
@@ -251,10 +251,6 @@
         doReturn(mTaskStack.top()).when(mActivityStack.top()).getOrganizedTask();
     }
 
-    void setIsInLetterboxAnimation(boolean inAnimation) {
-        doReturn(inAnimation).when(mActivityStack.top()).isInLetterboxAnimation();
-    }
-
     void setTopTaskInMultiWindowMode(boolean inMultiWindowMode) {
         doReturn(inMultiWindowMode).when(mTaskStack.top()).inMultiWindowMode();
     }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java
index d38f3b0..7bcf4ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxPolicyTest.java
@@ -66,7 +66,6 @@
         runTestScenario((robot) -> {
             robot.configureWindowStateWithTaskBar(/* hasTaskBarInsetsRoundedCorners */ true);
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -87,7 +86,6 @@
         runTestScenario((robot) -> {
             robot.configureWindowStateWithTaskBar(/* hasTaskBarInsetsRoundedCorners */ false);
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -109,7 +107,6 @@
         runTestScenario((robot) -> {
             robot.configureWindowStateWithTaskBar(/* hasTaskBarInsetsRoundedCorners */ true);
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -131,7 +128,6 @@
         runTestScenario((robot) -> {
             robot.configureWindowStateWithTaskBar(/* hasTaskBarInsetsRoundedCorners */ true);
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -157,7 +153,6 @@
             robot.conf().setLetterboxActivityCornersRadius(-1);
             robot.configureWindowState();
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -184,25 +179,17 @@
             robot.conf().setLetterboxActivityCornersRadius(15);
             robot.configureWindowState();
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
             robot.resources().configureGetDimensionPixelSize(R.dimen.taskbar_frame_height, 20);
             robot.setInvCompatState(/* scale */ 0.5f);
 
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ true);
-            robot.checkWindowStateRoundedCornersRadius(/* expected */ 7);
-
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.checkWindowStateRoundedCornersRadius(/* expected */ 7);
 
             robot.activity().setTopActivityVisibleRequested(/* isVisibleRequested */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ false);
             robot.checkWindowStateRoundedCornersRadius(/* expected */ 0);
-
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ true);
-            robot.checkWindowStateRoundedCornersRadius(/* expected */ 7);
         });
     }
 
@@ -212,7 +199,6 @@
             robot.conf().setLetterboxActivityCornersRadius(15);
             robot.configureWindowState();
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -236,7 +222,6 @@
             robot.conf().setLetterboxActivityCornersRadius(15);
             robot.configureWindowState();
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -260,7 +245,6 @@
             robot.conf().setLetterboxActivityCornersRadius(15);
             robot.configureWindowState();
             robot.activity().createActivityWithComponent();
-            robot.setTopActivityInLetterboxAnimation(/* inLetterboxAnimation */ false);
             robot.activity().setTopActivityVisible(/* isVisible */ true);
             robot.setIsLetterboxedForFixedOrientationAndAspectRatio(/* inLetterbox */ true);
             robot.conf().setLetterboxActivityCornersRounded(/* rounded */ true);
@@ -362,10 +346,6 @@
             mWindowState.mInvGlobalScale = scale;
         }
 
-        void setTopActivityInLetterboxAnimation(boolean inLetterboxAnimation) {
-            doReturn(inLetterboxAnimation).when(activity().top()).isInLetterboxAnimation();
-        }
-
         void setTopActivityTransparentPolicyRunning(boolean running) {
             doReturn(running).when(getTransparentPolicy()).isRunning();
         }
diff --git a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxUtilsTest.java b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxUtilsTest.java
index a4a63d2..ac707d2 100644
--- a/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxUtilsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/AppCompatLetterboxUtilsTest.java
@@ -63,25 +63,10 @@
     }
 
     @Test
-    public void positionIsFromTaskWhenLetterboxAnimationIsRunning() {
+    public void positionIsFromActivity() {
         runTestScenario((robot) -> {
             robot.activity().createActivityWithComponent();
             robot.setTopActivityLetterboxPolicyRunning(true);
-            robot.activity().setIsInLetterboxAnimation(true);
-            robot.activity().configureTaskBounds(
-                    new Rect(/* left */ 100, /* top */ 200, /* right */ 300, /* bottom */ 400));
-            robot.getLetterboxPosition();
-
-            robot.assertPosition(/* x */ 100, /* y */ 200);
-        });
-    }
-
-    @Test
-    public void positionIsFromActivityWhenLetterboxAnimationIsNotRunning() {
-        runTestScenario((robot) -> {
-            robot.activity().createActivityWithComponent();
-            robot.setTopActivityLetterboxPolicyRunning(true);
-            robot.activity().setIsInLetterboxAnimation(false);
             robot.activity().configureTopActivityBounds(
                     new Rect(/* left */ 200, /* top */ 400, /* right */ 300, /* bottom */ 400));
             robot.getLetterboxPosition();
diff --git a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
index e081971..bdee3c3 100644
--- a/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/BackNavigationControllerTests.java
@@ -225,10 +225,10 @@
         CrossActivityTestCase testCase = createTopTaskWithTwoActivities();
         IOnBackInvokedCallback callback = withSystemCallback(testCase.task);
         testCase.windowFront.mAttrs.windowAnimations = 0x10;
-        spyOn(mDisplayContent.mAppTransition.mTransitionAnimation);
-        doReturn(0xffff00AB).when(mDisplayContent.mAppTransition.mTransitionAnimation)
+        spyOn(mDisplayContent.mTransitionAnimation);
+        doReturn(0xffff00AB).when(mDisplayContent.mTransitionAnimation)
                 .getAnimationResId(any(), anyInt(), anyInt());
-        doReturn(0xffff00CD).when(mDisplayContent.mAppTransition.mTransitionAnimation)
+        doReturn(0xffff00CD).when(mDisplayContent.mTransitionAnimation)
                 .getDefaultAnimationResId(anyInt(), anyInt());
 
         BackNavigationInfo backNavigationInfo = startBackNavigation();
diff --git a/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java b/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java
index 1e91bed..43755ea 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DesktopModeHelperTest.java
@@ -181,6 +181,7 @@
         assertThat(DesktopModeHelper.isDeviceEligibleForDesktopMode(mMockContext)).isTrue();
     }
 
+    @DisableFlags(Flags.FLAG_ENABLE_PROJECTED_DISPLAY_DESKTOP_MODE)
     @Test
     public void isDeviceEligibleForDesktopMode_configDEModeOffAndIntDispHostsDesktop_returnsFalse() {
         doReturn(true).when(mMockResources).getBoolean(eq(R.bool.config_isDesktopModeSupported));
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
index 61ed0b5..4c81f73 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java
@@ -87,7 +87,7 @@
 import static com.android.window.flags.Flags.FLAG_ENABLE_CAMERA_COMPAT_FOR_DESKTOP_WINDOWING;
 import static com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE;
 import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT;
-import static com.android.window.flags.Flags.FLAG_ENABLE_PERSISTING_DENSITY_SCALE_FOR_CONNECTED_DISPLAYS;
+import static com.android.window.flags.Flags.FLAG_ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -2631,10 +2631,19 @@
         final BooleanSupplier keyguardGoingAway = () -> keyguard.isKeyguardGoingAway(displayId);
         final BooleanSupplier appVisible = activity::isVisibleRequested;
 
-        // Begin locked and in AOD
+        // Begin unlocked.
+        keyguard.setKeyguardShown(displayId, false /* keyguard */, false /* aod */);
+        transitions.flush();
+
+        // Lock and go to AOD.
         keyguard.setKeyguardShown(displayId, true /* keyguard */, true /* aod */);
         assertFalse(keyguardGoingAway.getAsBoolean());
         assertFalse(appVisible.getAsBoolean());
+        if (Flags.aodTransition()) {
+            assertThat(transitions.mLastTransit).flags().contains(TRANSIT_FLAG_AOD_APPEARING);
+        } else {
+            assertThat(transitions.mLastTransit).flags().doesNotContain(TRANSIT_FLAG_AOD_APPEARING);
+        }
         transitions.flush();
 
         // Start unlocking from AOD.
@@ -2654,14 +2663,7 @@
         keyguard.setKeyguardShown(displayId, true /* keyguard */, false /* aod */);
         assertTrue(keyguardGoingAway.getAsBoolean());
         assertTrue(appVisible.getAsBoolean());
-
-        if (Flags.aodTransition()) {
-            assertThat(transitions.mLastTransit).flags()
-                    .containsExactly(TRANSIT_FLAG_AOD_APPEARING);
-        } else {
-            assertThat(transitions.mLastTransit).isNull();
-        }
-        transitions.flush();
+        assertThat(transitions.mLastTransit).isNull();
 
         // Finish unlock
         keyguard.setKeyguardShown(displayId, false /* keyguard */, false /* aod */);
@@ -2684,10 +2686,19 @@
         final BooleanSupplier keyguardGoingAway = () -> keyguard.isKeyguardGoingAway(displayId);
         final BooleanSupplier appVisible = activity::isVisibleRequested;
 
-        // Begin locked and in AOD
+        // Begin unlocked.
+        keyguard.setKeyguardShown(displayId, false /* keyguard */, false /* aod */);
+        transitions.flush();
+
+        // Lock and go to AOD.
         keyguard.setKeyguardShown(displayId, true /* keyguard */, true /* aod */);
         assertFalse(keyguardGoingAway.getAsBoolean());
         assertFalse(appVisible.getAsBoolean());
+        if (Flags.aodTransition()) {
+            assertThat(transitions.mLastTransit).flags().contains(TRANSIT_FLAG_AOD_APPEARING);
+        } else {
+            assertThat(transitions.mLastTransit).flags().doesNotContain(TRANSIT_FLAG_AOD_APPEARING);
+        }
         transitions.flush();
 
         // Start unlocking from AOD.
@@ -2705,14 +2716,7 @@
         keyguard.setKeyguardShown(displayId, true /* keyguard */, false /* aod */);
         assertTrue(keyguardGoingAway.getAsBoolean());
         assertTrue(appVisible.getAsBoolean());
-
-        if (Flags.aodTransition()) {
-            assertThat(transitions.mLastTransit).flags()
-                    .containsExactly(TRANSIT_FLAG_AOD_APPEARING);
-        } else {
-            assertThat(transitions.mLastTransit).isNull();
-        }
-        transitions.flush();
+        assertThat(transitions.mLastTransit).isNull();
 
         // Same API call a second time cancels the unlock, because AOD isn't changing.
         keyguard.setKeyguardShown(displayId, true /* keyguard */, false /* aod */);
@@ -2921,7 +2925,7 @@
         assertFalse(dc.mWmService.mDisplayWindowSettings.shouldShowSystemDecorsLocked(dc));
     }
 
-    @EnableFlags(FLAG_ENABLE_PERSISTING_DENSITY_SCALE_FOR_CONNECTED_DISPLAYS)
+    @EnableFlags(FLAG_ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS)
     @Test
     public void testForcedDensityRatioSetForExternalDisplays_persistDensityScaleFlagEnabled() {
         final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo);
@@ -2951,7 +2955,7 @@
                 displayContent.mExternalDisplayForcedDensityRatio, 0.01);
     }
 
-    @EnableFlags(FLAG_ENABLE_PERSISTING_DENSITY_SCALE_FOR_CONNECTED_DISPLAYS)
+    @EnableFlags(FLAG_ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS)
     @Test
     public void testForcedDensityUpdateForExternalDisplays_persistDensityScaleFlagEnabled() {
         final DisplayInfo displayInfo = new DisplayInfo(mDisplayInfo);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
index 4854f0d..862158e 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayPolicyTests.java
@@ -362,7 +362,19 @@
 
     @Test
     public void testSwitchDecorInsets() {
-        createNavBarWithProvidedInsets(mDisplayContent);
+        final WindowState win = createApplicationWindow();
+        final WindowState bar = createNavBarWithProvidedInsets(mDisplayContent);
+        bar.getFrame().set(0, mDisplayContent.mDisplayFrames.mHeight - NAV_BAR_HEIGHT,
+                mDisplayContent.mDisplayFrames.mWidth, mDisplayContent.mDisplayFrames.mHeight);
+        final int insetsId = bar.mAttrs.providedInsets[0].getId();
+        final InsetsSourceProvider provider = mDisplayContent.getInsetsStateController()
+                .getOrCreateSourceProvider(insetsId, bar.mAttrs.providedInsets[0].getType());
+        provider.setServerVisible(true);
+        provider.updateSourceFrame(bar.getFrame());
+
+        final InsetsState prevInsetsState = new InsetsState();
+        prevInsetsState.addSource(new InsetsSource(provider.getSource()));
+
         final DisplayPolicy displayPolicy = mDisplayContent.getDisplayPolicy();
         final DisplayInfo info = mDisplayContent.getDisplayInfo();
         final int w = info.logicalWidth;
@@ -385,6 +397,18 @@
         // The current insets are restored from cache directly.
         assertEquals(prevConfigFrame, displayPolicy.getDecorInsetsInfo(info.rotation,
                 info.logicalWidth, info.logicalHeight).mConfigFrame);
+        // Assume that the InsetsSource in current InsetsState is not updated yet. And it will be
+        // replaced by the one in cache.
+        InsetsState currentInsetsState = new InsetsState();
+        final InsetsSource prevSource = new InsetsSource(provider.getSource());
+        prevSource.getFrame().scale(0.5f);
+        currentInsetsState.addSource(prevSource);
+        currentInsetsState = mDisplayContent.getInsetsPolicy().adjustInsetsForWindow(
+                win, currentInsetsState);
+        if (com.android.window.flags.Flags.useCachedInsetsForDisplaySwitch()) {
+            assertEquals(prevInsetsState.peekSource(insetsId),
+                    currentInsetsState.peekSource(insetsId));
+        }
 
         // If screen is not fully turned on, then the cache should be preserved.
         displayPolicy.screenTurnedOff(false /* acquireSleepToken */);
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
index a57577a96..81e487a 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayWindowSettingsTests.java
@@ -274,7 +274,7 @@
                 mSecondaryDisplay.mBaseDisplayDensity);
     }
 
-    @EnableFlags(Flags.FLAG_ENABLE_PERSISTING_DENSITY_SCALE_FOR_CONNECTED_DISPLAYS)
+    @EnableFlags(Flags.FLAG_ENABLE_PERSISTING_DISPLAY_SIZE_FOR_CONNECTED_DISPLAYS)
     @Test
     public void testSetForcedDensityRatio() {
         mDisplayWindowSettings.setForcedDensity(mSecondaryDisplay.getDisplayInfo(),
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java
index 51e0240..8ee5999 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxAttachInputTest.java
@@ -38,7 +38,6 @@
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.view.InputWindowHandle;
-import android.view.SurfaceControl;
 import android.view.WindowManager;
 
 import com.android.server.testutils.StubTransaction;
@@ -76,8 +75,7 @@
         doReturn(0.5f).when(letterboxOverrides).getLetterboxWallpaperDarkScrimAlpha();
         mWindowState = createWindowState();
         mLetterbox = new Letterbox(mSurfaces, StubTransaction::new,
-                mock(AppCompatReachabilityPolicy.class), letterboxOverrides,
-                () -> mock(SurfaceControl.class));
+                mock(AppCompatReachabilityPolicy.class), letterboxOverrides);
         mTransaction = spy(StubTransaction.class);
     }
 
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
index a51a44f..e5533b6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxTest.java
@@ -68,7 +68,6 @@
     private SurfaceControlMocker mSurfaces;
     private SurfaceControl.Transaction mTransaction;
 
-    private SurfaceControl mParentSurface = mock(SurfaceControl.class);
     private AppCompatLetterboxOverrides mLetterboxOverrides;
     private WindowState mWindowState;
 
@@ -84,7 +83,7 @@
         doReturn(0.5f).when(mLetterboxOverrides).getLetterboxWallpaperDarkScrimAlpha();
         mWindowState = mock(WindowState.class);
         mLetterbox = new Letterbox(mSurfaces, StubTransaction::new,
-                mock(AppCompatReachabilityPolicy.class), mLetterboxOverrides, () -> mParentSurface);
+                mock(AppCompatReachabilityPolicy.class), mLetterboxOverrides);
         mTransaction = spy(StubTransaction.class);
     }
 
@@ -259,22 +258,6 @@
     }
 
     @Test
-    public void testNeedsApplySurfaceChanges_setParentSurface() {
-        mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
-        applySurfaceChanges();
-
-        verify(mTransaction).reparent(mSurfaces.top, mParentSurface);
-        assertFalse(mLetterbox.needsApplySurfaceChanges());
-
-        mParentSurface = mock(SurfaceControl.class);
-
-        assertTrue(mLetterbox.needsApplySurfaceChanges());
-
-        applySurfaceChanges();
-        verify(mTransaction).reparent(mSurfaces.top, mParentSurface);
-    }
-
-    @Test
     public void testApplySurfaceChanges_cornersNotRounded_surfaceFullWindowSurfaceNotCreated() {
         mLetterbox.layout(new Rect(0, 0, 10, 10), new Rect(0, 1, 10, 10), new Point(1000, 2000));
         applySurfaceChanges();
diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
index e4a1bf6..34e9bed 100644
--- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java
@@ -31,6 +31,7 @@
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doNothing;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
 import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
+import static com.android.server.display.feature.flags.Flags.FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT;
 import static com.android.server.wm.ActivityRecord.State.FINISHING;
 import static com.android.server.wm.ActivityRecord.State.PAUSED;
 import static com.android.server.wm.ActivityRecord.State.PAUSING;
@@ -82,6 +83,7 @@
 import android.platform.test.annotations.EnableFlags;
 import android.platform.test.annotations.Presubmit;
 import android.util.Pair;
+import android.view.DisplayInfo;
 
 import androidx.test.filters.MediumTest;
 
@@ -1379,6 +1381,23 @@
         verify(controller, never()).notifyTaskProfileLocked(any(), anyInt());
     }
 
+    @EnableFlags(FLAG_ENABLE_DISPLAY_CONTENT_MODE_MANAGEMENT)
+    @Test
+    public void testOnDisplayBelongToTopologyChanged() {
+        final DisplayInfo displayInfo = new DisplayInfo();
+        displayInfo.copyFrom(mDisplayInfo);
+        displayInfo.displayId = DEFAULT_DISPLAY + 1;
+        final DisplayContent dc = createNewDisplay(displayInfo);
+        final int displayId = dc.getDisplayId();
+
+        doReturn(dc).when(mRootWindowContainer).getDisplayContentOrCreate(displayId);
+        doReturn(true).when(mWm.mDisplayWindowSettings).shouldShowSystemDecorsLocked(dc);
+
+        mRootWindowContainer.onDisplayAdded(displayId);
+        verify(mWm.mDisplayManagerInternal, times(1)).onDisplayBelongToTopologyChanged(anyInt(),
+                anyBoolean());
+    }
+
     /**
      * Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
      * info for test cases.
diff --git a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
index 4e09d6a..33a48aa 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SizeCompatTests.java
@@ -67,6 +67,7 @@
 import static com.android.server.wm.AppCompatUtils.computeAspectRatio;
 import static com.android.server.wm.DisplayContent.IME_TARGET_LAYERING;
 import static com.android.server.wm.WindowContainer.POSITION_TOP;
+import static com.android.window.flags.Flags.FLAG_ENABLE_SIZE_COMPAT_MODE_IMPROVEMENTS_FOR_CONNECTED_DISPLAYS;
 
 import static com.google.common.truth.Truth.assertThat;
 
@@ -109,6 +110,7 @@
 import android.provider.DeviceConfig.Properties;
 import android.view.DisplayCutout;
 import android.view.DisplayInfo;
+import android.view.InputDevice;
 import android.view.InsetsFrameProvider;
 import android.view.InsetsSource;
 import android.view.InsetsState;
@@ -561,6 +563,41 @@
         assertDownScaled();
     }
 
+    @EnableFlags(FLAG_ENABLE_SIZE_COMPAT_MODE_IMPROVEMENTS_FOR_CONNECTED_DISPLAYS)
+    @Test
+    public void testFixedMiscConfigurationWhenMovingToDisplay() {
+        setUpDisplaySizeWithApp(1000, 2500);
+
+        final DisplayContent newDisplay =
+                new TestDisplayContent.Builder(mAtm, 1000, 2000).build();
+        final InputDevice device = new InputDevice.Builder()
+                .setAssociatedDisplayId(newDisplay.mDisplayId)
+                .setSources(InputDevice.SOURCE_TOUCHSCREEN | InputDevice.SOURCE_TRACKBALL
+                        | InputDevice.KEYBOARD_TYPE_ALPHABETIC)
+                .build();
+        final InputDevice[] devices = {device};
+        doReturn(true).when(newDisplay.mWmService.mInputManager)
+                .canDispatchToDisplay(device.getId(), newDisplay.mDisplayId);
+        doReturn(devices).when(newDisplay.mWmService.mInputManager).getInputDevices();
+        mTask.mWmService.mIsTouchDevice = true;
+        mTask.mWmService.displayReady();
+
+        prepareUnresizable(mActivity, 1.5f /* maxAspect */, SCREEN_ORIENTATION_UNSPECIFIED);
+
+        final Configuration originalConfiguration = mActivity.getConfiguration();
+        final int originalTouchscreen = originalConfiguration.touchscreen;
+        final int originalNavigation = originalConfiguration.navigation;
+        final int originalKeyboard = originalConfiguration.keyboard;
+
+        // Move the non-resizable activity to the new display.
+        mTask.reparent(newDisplay.getDefaultTaskDisplayArea(), true /* onTop */);
+
+        final Configuration newConfiguration = mActivity.getConfiguration();
+        assertEquals(originalTouchscreen, newConfiguration.touchscreen);
+        assertEquals(originalNavigation, newConfiguration.navigation);
+        assertEquals(originalKeyboard, newConfiguration.keyboard);
+    }
+
     @Test
     public void testFixedScreenBoundsWhenDisplaySizeChanged() {
         setUpDisplaySizeWithApp(1000, 2500);
diff --git a/services/usb/java/com/android/server/usb/UsbManagerInternal.java b/services/usb/java/com/android/server/usb/UsbManagerInternal.java
deleted file mode 100644
index 31c5986..0000000
--- a/services/usb/java/com/android/server/usb/UsbManagerInternal.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright (C) 2024 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package com.android.server.usb;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.hardware.usb.IUsbOperationInternal;
-import android.hardware.usb.UsbPort;
-import android.util.ArraySet;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * UsbManagerInternal provides internal APIs for the UsbService to
- * reduce IPC overhead costs and support internal USB data signal stakers.
- *
- * @hide Only for use within the system server.
- */
-public abstract class UsbManagerInternal {
-
-  public static final int OS_USB_DISABLE_REASON_AAPM = 0;
-  public static final int OS_USB_DISABLE_REASON_LOCKDOWN_MODE = 1;
-
-  @Retention(RetentionPolicy.SOURCE)
-  @IntDef(value = {OS_USB_DISABLE_REASON_AAPM,
-    OS_USB_DISABLE_REASON_LOCKDOWN_MODE})
-  public @interface OsUsbDisableReason {
-  }
-
-  public abstract boolean enableUsbData(String portId, boolean enable,
-      int operationId, IUsbOperationInternal callback, @OsUsbDisableReason int disableReason);
-
-  public abstract UsbPort[] getPorts();
-
-}
\ No newline at end of file
diff --git a/services/usb/java/com/android/server/usb/UsbService.java b/services/usb/java/com/android/server/usb/UsbService.java
index 4395b76..7808b2e 100644
--- a/services/usb/java/com/android/server/usb/UsbService.java
+++ b/services/usb/java/com/android/server/usb/UsbService.java
@@ -27,7 +27,10 @@
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SINK;
 import static android.hardware.usb.UsbPortStatus.POWER_ROLE_SOURCE;
 
+import android.hardware.usb.IUsbManagerInternal;
+
 import android.annotation.NonNull;
+import android.annotation.IntDef;
 import android.annotation.UserIdInt;
 import android.app.PendingIntent;
 import android.app.admin.DevicePolicyManager;
@@ -80,12 +83,16 @@
 import java.io.File;
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
 import java.util.Objects;
 import java.util.concurrent.CompletableFuture;
 
+import java.util.concurrent.atomic.AtomicInteger;
+
 /**
  * UsbService manages all USB related state, including both host and device support.
  * Host related events and calls are delegated to UsbHostManager, and device related
@@ -93,6 +100,15 @@
  */
 public class UsbService extends IUsbManager.Stub {
 
+    public static final int OS_USB_DISABLE_REASON_AAPM = 0;
+    public static final int OS_USB_DISABLE_REASON_LOCKDOWN_MODE = 1;
+
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef(value = {OS_USB_DISABLE_REASON_AAPM,
+        OS_USB_DISABLE_REASON_LOCKDOWN_MODE})
+    public @interface OsUsbDisableReason {
+    }
+
     public static class Lifecycle extends SystemService {
         private UsbService mUsbService;
         private final CompletableFuture<Void> mOnStartFinished = new CompletableFuture<>();
@@ -227,7 +243,7 @@
         filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
         mContext.registerReceiverAsUser(receiver, UserHandle.ALL, filter, null, null);
         if(android.hardware.usb.flags.Flags.enableUsbDataSignalStakingInternal()) {
-            LocalServices.addService(UsbManagerInternal.class, new UsbManagerInternalImpl());
+            LocalServices.addService(IUsbManagerInternal.class, new UsbManagerInternalImpl());
         }
     }
 
@@ -246,7 +262,7 @@
         mPermissionManager = new UsbPermissionManager(context, this);
 
         if(android.hardware.usb.flags.Flags.enableUsbDataSignalStakingInternal()) {
-            LocalServices.addService(UsbManagerInternal.class, new UsbManagerInternalImpl());
+            LocalServices.addService(IUsbManagerInternal.class, new UsbManagerInternalImpl());
         }
     }
 
@@ -1536,24 +1552,30 @@
                 enableUsbDataInternal(port.getId(), !lockDownTriggeredByUser,
                     STRONG_AUTH_OPERATION_ID,
                     new IUsbOperationInternal.Default(),
-                    UsbManagerInternal.OS_USB_DISABLE_REASON_LOCKDOWN_MODE,
+                    OS_USB_DISABLE_REASON_LOCKDOWN_MODE,
                     true);
             }
         }
     }
 
-    private class UsbManagerInternalImpl extends UsbManagerInternal {
-        @Override
-        public boolean enableUsbData(String portId, boolean enable,
-                int operationId, IUsbOperationInternal callback,
-            @OsUsbDisableReason int disableReason) {
-            return enableUsbDataInternal(portId, enable, operationId, callback,
-                disableReason, true);
-        }
+    private class UsbManagerInternalImpl extends IUsbManagerInternal.Stub {
+        private static final AtomicInteger sUsbOperationCount = new AtomicInteger();
 
         @Override
-        public UsbPort[] getPorts() {
-            return mPortManager.getPorts();
+        public boolean enableUsbDataSignal(boolean enable,
+                @OsUsbDisableReason int disableReason) {
+                boolean result = true;
+                int operationId = sUsbOperationCount.incrementAndGet() + disableReason;
+                for (UsbPort port : mPortManager.getPorts()) {
+                    boolean success = enableUsbDataInternal(port.getId(), enable, operationId,
+                        new IUsbOperationInternal.Default(), disableReason, true);
+                    if(!success) {
+                        Slog.e(TAG, "enableUsbDataInternal failed to change USB port "
+                            + port.getId() + "state to " + enable);
+                    }
+                    result &= success;
+                }
+                return result;
         }
     }
 }
diff --git a/telecomm/java/android/telecom/Call.java b/telecomm/java/android/telecom/Call.java
index 531f516..9e57fd3 100644
--- a/telecomm/java/android/telecom/Call.java
+++ b/telecomm/java/android/telecom/Call.java
@@ -30,6 +30,7 @@
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.ParcelFileDescriptor;
+import android.os.UserHandle;
 
 import com.android.internal.telecom.IVideoProvider;
 import com.android.server.telecom.flags.Flags;
@@ -680,6 +681,7 @@
         private final @CallDirection int mCallDirection;
         private final @Connection.VerificationStatus int mCallerNumberVerificationStatus;
         private final Uri mContactPhotoUri;
+        private final UserHandle mAssociatedUser;
 
         /**
          * Whether the supplied capabilities  supports the specified capability.
@@ -1081,6 +1083,16 @@
             return mCallerNumberVerificationStatus;
         }
 
+        /**
+         * Gets the user that originated the call
+         * @return The user
+         *
+         * @hide
+         */
+        public UserHandle getAssociatedUser() {
+            return mAssociatedUser;
+        }
+
         @Override
         public boolean equals(Object o) {
             if (o instanceof Details) {
@@ -1107,7 +1119,8 @@
                         Objects.equals(mCallDirection, d.mCallDirection) &&
                         Objects.equals(mCallerNumberVerificationStatus,
                                 d.mCallerNumberVerificationStatus) &&
-                        Objects.equals(mContactPhotoUri, d.mContactPhotoUri);
+                        Objects.equals(mContactPhotoUri, d.mContactPhotoUri) &&
+                        Objects.equals(mAssociatedUser, d.mAssociatedUser);
             }
             return false;
         }
@@ -1133,7 +1146,8 @@
                             mContactDisplayName,
                             mCallDirection,
                             mCallerNumberVerificationStatus,
-                    mContactPhotoUri);
+                            mContactPhotoUri,
+                    mAssociatedUser);
         }
 
         /** {@hide} */
@@ -1158,7 +1172,8 @@
                 String contactDisplayName,
                 int callDirection,
                 int callerNumberVerificationStatus,
-                Uri contactPhotoUri) {
+                Uri contactPhotoUri,
+                UserHandle originatingUser) {
             mState = state;
             mTelecomCallId = telecomCallId;
             mHandle = handle;
@@ -1180,6 +1195,7 @@
             mCallDirection = callDirection;
             mCallerNumberVerificationStatus = callerNumberVerificationStatus;
             mContactPhotoUri = contactPhotoUri;
+            mAssociatedUser = originatingUser;
         }
 
         /** {@hide} */
@@ -1205,7 +1221,8 @@
                     parcelableCall.getContactDisplayName(),
                     parcelableCall.getCallDirection(),
                     parcelableCall.getCallerNumberVerificationStatus(),
-                    parcelableCall.getContactPhotoUri()
+                    parcelableCall.getContactPhotoUri(),
+                    parcelableCall.getAssociatedUser()
             );
         }
 
@@ -2631,7 +2648,8 @@
                         mDetails.getContactDisplayName(),
                         mDetails.getCallDirection(),
                         mDetails.getCallerNumberVerificationStatus(),
-                        mDetails.getContactPhotoUri()
+                        mDetails.getContactPhotoUri(),
+                        mDetails.getAssociatedUser()
                         );
                 fireDetailsChanged(mDetails);
             }
diff --git a/telecomm/java/android/telecom/ParcelableCall.java b/telecomm/java/android/telecom/ParcelableCall.java
index 6a13189..bd004e5 100644
--- a/telecomm/java/android/telecom/ParcelableCall.java
+++ b/telecomm/java/android/telecom/ParcelableCall.java
@@ -16,14 +16,17 @@
 
 package android.telecom;
 
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
+import android.content.Intent;
 import android.net.Uri;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.UserHandle;
 import android.telecom.Call.Details.CallDirection;
 
 import com.android.internal.telecom.IVideoProvider;
@@ -70,6 +73,7 @@
         private String mContactDisplayName;
         private String mActiveChildCallId;
         private Uri mContactPhotoUri;
+        private UserHandle mAssociatedUser;
 
         public ParcelableCallBuilder setId(String id) {
             mId = id;
@@ -230,6 +234,11 @@
             return this;
         }
 
+        public ParcelableCallBuilder setAssociatedUser(UserHandle user) {
+            mAssociatedUser = user;
+            return this;
+        }
+
         public ParcelableCall createParcelableCall() {
             return new ParcelableCall(
                     mId,
@@ -262,7 +271,8 @@
                     mCallerNumberVerificationStatus,
                     mContactDisplayName,
                     mActiveChildCallId,
-                    mContactPhotoUri);
+                    mContactPhotoUri,
+                    mAssociatedUser);
         }
 
         public static ParcelableCallBuilder fromParcelableCall(ParcelableCall parcelableCall) {
@@ -300,6 +310,7 @@
             newBuilder.mContactDisplayName = parcelableCall.mContactDisplayName;
             newBuilder.mActiveChildCallId = parcelableCall.mActiveChildCallId;
             newBuilder.mContactPhotoUri = parcelableCall.mContactPhotoUri;
+            newBuilder.mAssociatedUser = parcelableCall.mAssociatedUser;
             return newBuilder;
         }
     }
@@ -336,6 +347,7 @@
     private final String mContactDisplayName;
     private final String mActiveChildCallId; // Only valid for CDMA conferences
     private final Uri mContactPhotoUri;
+    private final UserHandle mAssociatedUser;
 
     public ParcelableCall(
             String id,
@@ -368,7 +380,8 @@
             int callerNumberVerificationStatus,
             String contactDisplayName,
             String activeChildCallId,
-            Uri contactPhotoUri
+            Uri contactPhotoUri,
+            UserHandle associatedUser
     ) {
         mId = id;
         mState = state;
@@ -401,6 +414,7 @@
         mContactDisplayName = contactDisplayName;
         mActiveChildCallId = activeChildCallId;
         mContactPhotoUri = contactPhotoUri;
+        mAssociatedUser = associatedUser;
     }
 
     /** The unique ID of the call. */
@@ -624,6 +638,13 @@
         return mContactPhotoUri;
     }
 
+    /**
+     * @return the originating user
+     */
+    public @NonNull UserHandle getAssociatedUser() {
+        return mAssociatedUser;
+    }
+
 
     /**
      * @return On a CDMA conference with two participants, returns the ID of the child call that's
@@ -666,6 +687,9 @@
             source.readList(conferenceableCallIds, classLoader, java.lang.String.class);
             Bundle intentExtras = source.readBundle(classLoader);
             Bundle extras = source.readBundle(classLoader);
+            if (extras == null) {
+                extras = new Bundle();
+            }
             int supportedAudioRoutes = source.readInt();
             boolean isRttCallChanged = source.readByte() == 1;
             ParcelableRttCall rttCall = source.readParcelable(classLoader, android.telecom.ParcelableRttCall.class);
@@ -675,6 +699,8 @@
             String contactDisplayName = source.readString();
             String activeChildCallId = source.readString();
             Uri contactPhotoUri = source.readParcelable(classLoader, Uri.class);
+            UserHandle associatedUser = source.readParcelable(classLoader, UserHandle.class);
+            extras.putParcelable(Intent.EXTRA_USER_HANDLE, associatedUser);
             return new ParcelableCallBuilder()
                     .setId(id)
                     .setState(state)
@@ -707,6 +733,7 @@
                     .setContactDisplayName(contactDisplayName)
                     .setActiveChildCallId(activeChildCallId)
                     .setContactPhotoUri(contactPhotoUri)
+                    .setAssociatedUser(associatedUser)
                     .createParcelableCall();
         }
 
@@ -757,6 +784,7 @@
         destination.writeString(mContactDisplayName);
         destination.writeString(mActiveChildCallId);
         destination.writeParcelable(mContactPhotoUri, 0);
+        destination.writeParcelable(mAssociatedUser, 0);
     }
 
     @Override
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index 58833e8..50c5a6b6 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -10962,7 +10962,7 @@
         sDefaults.putInt(KEY_MMS_SMS_TO_MMS_TEXT_THRESHOLD_INT, -1);
         sDefaults.putInt(KEY_MMS_SUBJECT_MAX_LENGTH_INT, 40);
         sDefaults.putInt(KEY_MMS_NETWORK_RELEASE_TIMEOUT_MILLIS_INT, 5 * 1000);
-        sDefaults.putInt(KEY_MMS_MAX_NTN_PAYLOAD_SIZE_BYTES_INT, 3 * 1000);
+        sDefaults.putInt(KEY_MMS_MAX_NTN_PAYLOAD_SIZE_BYTES_INT, -1);
         sDefaults.putString(KEY_MMS_EMAIL_GATEWAY_NUMBER_STRING, "");
         sDefaults.putString(KEY_MMS_HTTP_PARAMS_STRING, "");
         sDefaults.putString(KEY_MMS_NAI_SUFFIX_STRING, "");
diff --git a/telephony/java/android/telephony/SubscriptionManager.java b/telephony/java/android/telephony/SubscriptionManager.java
index d2741ac..e04d285 100644
--- a/telephony/java/android/telephony/SubscriptionManager.java
+++ b/telephony/java/android/telephony/SubscriptionManager.java
@@ -1187,6 +1187,61 @@
     public static final String IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM =
             SimInfo.COLUMN_IS_SATELLITE_PROVISIONED_FOR_NON_IP_DATAGRAM;
 
+    /**
+     * TelephonyProvider column name for satellite entitlement barred plmns. The value of this
+     * column is set based on entitlement query result for satellite configuration.
+     * By default, it's empty.
+     * <P>Type: TEXT </P>
+     *
+     * @hide
+     */
+    public static final String SATELLITE_ENTITLEMENT_BARRED_PLMNS =
+            SimInfo.COLUMN_SATELLITE_ENTITLEMENT_BARRED_PLMNS;
+
+    /**
+     * TelephonyProvider column name for satellite entitlement data plan for plmns. The value
+     * of this column is set based on entitlement query result for satellite configuration.
+     * By default, it's empty.
+     * <P>Type: TEXT </P>
+     *
+     * @hide
+     */
+    public static final String SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS =
+            SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_PLAN_PLMNS;
+
+    /**
+     * TelephonyProvider column name for satellite entitlement service type map. The value of
+     * this column is set based on entitlement query result for satellite configuration.
+     * By default, it's empty.
+     * <P>Type: TEXT </P>
+     *
+     * @hide
+     */
+    public static final String SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP =
+            SimInfo.COLUMN_SATELLITE_ENTITLEMENT_SERVICE_TYPE_MAP;
+
+    /**
+     * TelephonyProvider column name for satellite entitlement data service policy. The value
+     * of this column is set based on entitlement query result for satellite configuration.
+     * By default, it's empty.
+     * <P>Type: TEXT </P>
+     *
+     * @hide
+     */
+    public static final String SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY =
+            SimInfo.COLUMN_SATELLITE_ENTITLEMENT_DATA_SERVICE_POLICY;
+
+    /**
+     * TelephonyProvider column name for satellite entitlement voice service policy. The value
+     * of this column is set based on entitlement query result for satellite configuration.
+     * By default, it's empty.
+     * <P>Type: TEXT </P>
+     *
+     * @hide
+     */
+    public static final String SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY =
+            SimInfo.COLUMN_SATELLITE_ENTITLEMENT_VOICE_SERVICE_POLICY;
+
     /** @hide */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef(prefix = {"USAGE_SETTING_"},
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index 1c6652d..0dd0a42 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -3203,6 +3203,31 @@
             in List<String> satelliteCountryCodes, String satelliteAccessConfigurationFile);
 
     /**
+     * This API can be used by only CTS to override the satellite access allowed state for
+     * a list of subscription IDs.
+     *
+     * @param subIdListStr The string representation of the list of subscription IDs,
+     *                     which are numbers separated by comma.
+     * @return {@code true} if the satellite access allowed state is set successfully,
+     * {@code false} otherwise.
+     */
+    boolean setSatelliteAccessAllowedForSubscriptions(in String subIdListStr);
+
+    /**
+     * This API can be used by only CTS to override satellite TN scanning support.
+     *
+     * @param reset {@code true} mean the overridden configs should not be used, {@code false}
+     *              otherwise.
+     * @param concurrentTnScanningSupported Whether concurrent TN scanning is supported.
+     * @param tnScanningDuringSatelliteSessionAllowed Whether TN scanning is allowed during
+     * a satellite session.
+     * @return {@code true} if the TN scanning support is set successfully,
+     * {@code false} otherwise.
+     */
+    boolean setTnScanningSupport(in boolean reset, in boolean concurrentTnScanningSupported,
+        in boolean tnScanningDuringSatelliteSessionAllowed);
+
+    /**
      * This API can be used in only testing to override oem-enabled satellite provision status.
      *
      * @param reset {@code true} mean the overriding status should not be used, {@code false}
diff --git a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java
index 3498974..229c7bf 100644
--- a/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java
+++ b/tests/AppJankTest/src/android/app/jank/tests/IntegrationTests.java
@@ -103,6 +103,10 @@
     @RequiresFlagsEnabled(Flags.FLAG_DETAILED_APP_JANK_METRICS_API)
     public void reportJankStats_confirmPendingStatsIncreases() {
         Activity jankTrackerActivity = mJankTrackerActivityRule.launchActivity(null);
+        mDevice.wait(Until.findObject(
+                By.text(jankTrackerActivity.getString(R.string.continue_test))),
+                WAIT_FOR_TIMEOUT_MS);
+
         EditText editText = jankTrackerActivity.findViewById(R.id.edit_text);
         JankTracker jankTracker = editText.getJankTracker();
 
@@ -135,6 +139,10 @@
     public void simulateWidgetStateChanges_confirmStateChangesAreTracked() {
         JankTrackerActivity jankTrackerActivity =
                 mJankTrackerActivityRule.launchActivity(null);
+        mDevice.wait(Until.findObject(
+                        By.text(jankTrackerActivity.getString(R.string.continue_test))),
+                WAIT_FOR_TIMEOUT_MS);
+
         TestWidget testWidget = jankTrackerActivity.findViewById(R.id.jank_tracker_widget);
         JankTracker jankTracker = testWidget.getJankTracker();
         jankTracker.forceListenerRegistration();
diff --git a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
index d7f91e0..2093ccc 100644
--- a/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
+++ b/tests/FlickerTests/Rotation/src/com/android/server/wm/flicker/rotation/SeamlessAppRotationTest.kt
@@ -156,19 +156,6 @@
         flicker.assertLayers { isVisible(testApp) }
     }
 
-    /** Checks that [testApp] layer covers the entire screen during the whole transition */
-    @Presubmit
-    @Test
-    fun appLayerRotates() {
-        flicker.assertLayers {
-            this.invoke("entireScreenCovered") { entry ->
-                entry.entry.displays.map { display ->
-                    entry.visibleRegion(testApp).coversExactly(display.layerStackSpace)
-                }
-            }
-        }
-    }
-
     /** {@inheritDoc} */
     @Test
     @Ignore("Not applicable to this CUJ. App is full screen")
@@ -225,7 +212,6 @@
         visibleLayersShownMoreThanOneConsecutiveEntry()
         visibleWindowsShownMoreThanOneConsecutiveEntry()
 
-        runAndIgnoreAssumptionViolation { appLayerRotates() }
         runAndIgnoreAssumptionViolation { appLayerAlwaysVisible() }
         runAndIgnoreAssumptionViolation { navBarLayerIsVisibleAtStartAndEnd() }
         runAndIgnoreAssumptionViolation { navBarWindowIsAlwaysVisible() }
diff --git a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
index 55d6fd9..6d8ea40 100644
--- a/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
+++ b/tests/FlickerTests/test-apps/app-helpers/src/com/android/server/wm/flicker/helpers/DesktopModeAppHelper.kt
@@ -28,10 +28,13 @@
 import android.tools.helpers.SYSTEMUI_PACKAGE
 import android.tools.traces.parsers.WindowManagerStateHelper
 import android.tools.traces.wm.WindowingMode
+import android.view.KeyEvent.KEYCODE_DPAD_DOWN
+import android.view.KeyEvent.KEYCODE_DPAD_UP
 import android.view.KeyEvent.KEYCODE_EQUALS
 import android.view.KeyEvent.KEYCODE_LEFT_BRACKET
 import android.view.KeyEvent.KEYCODE_MINUS
 import android.view.KeyEvent.KEYCODE_RIGHT_BRACKET
+import android.view.KeyEvent.META_CTRL_ON
 import android.view.KeyEvent.META_META_ON
 import android.view.WindowInsets
 import android.view.WindowManager
@@ -151,19 +154,42 @@
             ?: error("Unable to find resource $MAXIMIZE_BUTTON_VIEW\n")
     }
 
-    /** Click maximise button on the app header for the given app. */
+    /** Maximize a given app to fill the stable bounds. */
     fun maximiseDesktopApp(
         wmHelper: WindowManagerStateHelper,
         device: UiDevice,
-        usingKeyboard: Boolean = false
+        trigger: MaximizeDesktopAppTrigger = MaximizeDesktopAppTrigger.MAXIMIZE_MENU,
     ) {
-        if (usingKeyboard) {
-            val keyEventHelper = KeyEventHelper(getInstrumentation())
-            keyEventHelper.press(KEYCODE_EQUALS, META_META_ON)
-        } else {
-            val caption = getCaptionForTheApp(wmHelper, device)
-            val maximizeButton = getMaximizeButtonForTheApp(caption)
-            maximizeButton.click()
+        val caption = getCaptionForTheApp(wmHelper, device)!!
+        val maximizeButton = getMaximizeButtonForTheApp(caption)
+
+        when (trigger) {
+            MaximizeDesktopAppTrigger.MAXIMIZE_MENU -> maximizeButton.click()
+            MaximizeDesktopAppTrigger.DOUBLE_TAP_APP_HEADER -> {
+                caption.click()
+                Thread.sleep(50)
+                caption.click()
+            }
+
+            MaximizeDesktopAppTrigger.KEYBOARD_SHORTCUT -> {
+                val keyEventHelper = KeyEventHelper(getInstrumentation())
+                keyEventHelper.press(KEYCODE_EQUALS, META_META_ON)
+            }
+
+            MaximizeDesktopAppTrigger.MAXIMIZE_BUTTON_IN_MENU -> {
+                maximizeButton.longClick()
+                wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
+                val buttonResId = MAXIMIZE_BUTTON_IN_MENU
+                val maximizeMenu = getDesktopAppViewByRes(MAXIMIZE_MENU)
+                val maximizeButtonInMenu =
+                    maximizeMenu
+                        ?.wait(
+                            Until.findObject(By.res(SYSTEMUI_PACKAGE, buttonResId)),
+                            TIMEOUT.toMillis()
+                        )
+                        ?: error("Unable to find object with resource id $buttonResId")
+                maximizeButtonInMenu.click()
+            }
         }
         wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
     }
@@ -472,6 +498,22 @@
         device.drag(startX, startY, endX, endY, 100)
     }
 
+    fun enterDesktopModeViaKeyboard(
+        wmHelper: WindowManagerStateHelper,
+    ) {
+        val keyEventHelper = KeyEventHelper(getInstrumentation())
+        keyEventHelper.press(KEYCODE_DPAD_DOWN, META_META_ON or META_CTRL_ON)
+        wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
+    }
+
+    fun exitDesktopModeToFullScreenViaKeyboard(
+        wmHelper: WindowManagerStateHelper,
+    ) {
+        val keyEventHelper = KeyEventHelper(getInstrumentation())
+        keyEventHelper.press(KEYCODE_DPAD_UP, META_META_ON or META_CTRL_ON)
+        wmHelper.StateSyncBuilder().withAppTransitionIdle().waitForAndVerify()
+    }
+
     fun enterDesktopModeFromAppHandleMenu(
         wmHelper: WindowManagerStateHelper,
         device: UiDevice
@@ -550,6 +592,13 @@
                 rightSideMatching
     }
 
+    enum class MaximizeDesktopAppTrigger {
+        MAXIMIZE_MENU,
+        DOUBLE_TAP_APP_HEADER,
+        KEYBOARD_SHORTCUT,
+        MAXIMIZE_BUTTON_IN_MENU
+    }
+
     private companion object {
         val TIMEOUT: Duration = Duration.ofSeconds(3)
         const val SNAP_RESIZE_DRAG_INSET: Int = 5 // inset to avoid dragging to display edge
@@ -561,6 +610,7 @@
         const val DESKTOP_MODE_BUTTON: String = "desktop_button"
         const val SNAP_LEFT_BUTTON: String = "maximize_menu_snap_left_button"
         const val SNAP_RIGHT_BUTTON: String = "maximize_menu_snap_right_button"
+        const val MAXIMIZE_BUTTON_IN_MENU: String = "maximize_menu_size_toggle_button"
         const val MINIMIZE_BUTTON_VIEW: String = "minimize_window"
         const val HEADER_EMPTY_VIEW: String = "caption_handle"
         val caption: BySelector
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 7c24a4a..98af8b2 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -39,7 +39,6 @@
             android:value="true" />
         <activity android:name=".SimpleActivity"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.SimpleActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:label="SimpleActivity"
                   android:exported="true">
             <intent-filter>
@@ -49,7 +48,6 @@
         </activity>
         <activity android:name=".ImeActivity"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:label="ImeActivity"
                   android:exported="true">
             <intent-filter>
@@ -58,7 +56,6 @@
             </intent-filter>
         </activity>
         <activity android:name=".ImeActivityAutoFocus"
-                  android:theme="@style/CutoutShortEdges"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.ImeActivityAutoFocus"
                   android:windowSoftInputMode="stateVisible"
                   android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
@@ -81,7 +78,6 @@
         </activity>
         <activity android:name=".SeamlessRotationActivity"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.SeamlessRotationActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:configChanges="orientation|screenSize|screenLayout|smallestScreenSize"
                   android:showWhenLocked="true"
                   android:label="SeamlessActivity"
@@ -92,7 +88,6 @@
             </intent-filter>
         </activity>
         <activity android:name=".NonResizeableActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:resizeableActivity="false"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.NonResizeableActivity"
                   android:label="NonResizeableActivity"
@@ -174,7 +169,6 @@
         </activity>
         <activity android:name=".LaunchNewActivity"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchNewActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:configChanges="orientation|screenSize"
                   android:label="LaunchNewActivity"
                   android:exported="true">
@@ -185,7 +179,6 @@
         </activity>
         <activity android:name=".LaunchNewTaskActivity"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.LaunchNewTaskActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:configChanges="orientation|screenSize"
                   android:label="LaunchNewTaskActivity"
                   android:exported="true">
@@ -207,7 +200,6 @@
         </activity>
         <activity android:name=".PortraitOnlyActivity"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.PortraitOnlyActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:screenOrientation="portrait"
                   android:configChanges="orientation|screenSize"
                   android:exported="true">
@@ -219,7 +211,6 @@
         <activity android:name=".ImeEditorPopupDialogActivity"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.ImeEditorPopupDialogActivity"
                   android:configChanges="orientation|screenSize"
-                  android:theme="@style/CutoutShortEdges"
                   android:label="ImeEditorPopupDialogActivity"
                   android:exported="true">
             <intent-filter>
@@ -229,7 +220,6 @@
         </activity>
         <activity android:name=".ShowWhenLockedActivity"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.ShowWhenLockedActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:configChanges="orientation|screenSize"
                   android:label="ShowWhenLockedActivity"
                   android:showWhenLocked="true"
@@ -241,7 +231,6 @@
         </activity>
         <activity android:name=".NotificationActivity"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.NotificationActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:configChanges="orientation|screenSize"
                   android:label="NotificationActivity"
                   android:exported="true">
@@ -254,7 +243,6 @@
             android:name=".ActivityEmbeddingMainActivity"
             android:label="ActivityEmbedding Main"
             android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
-            android:theme="@style/CutoutShortEdges"
             android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
             android:exported="true">
             <intent-filter>
@@ -266,7 +254,6 @@
             android:name=".ActivityEmbeddingTrampolineActivity"
             android:label="ActivityEmbedding Trampoline"
             android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
-            android:theme="@style/CutoutShortEdges"
             android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
             android:exported="false">
         </activity>
@@ -274,7 +261,6 @@
             android:name=".ActivityEmbeddingSecondaryActivity"
             android:label="ActivityEmbedding Secondary"
             android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
-            android:theme="@style/CutoutShortEdges"
             android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
             android:supportsPictureInPicture="true"
             android:exported="false"/>
@@ -282,21 +268,18 @@
             android:name=".ActivityEmbeddingThirdActivity"
             android:label="ActivityEmbedding Third"
             android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
-            android:theme="@style/CutoutShortEdges"
             android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
             android:exported="false"/>
         <activity
             android:name=".ActivityEmbeddingAlwaysExpandActivity"
             android:label="ActivityEmbedding AlwaysExpand"
             android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
-            android:theme="@style/CutoutShortEdges"
             android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
             android:exported="false"/>
         <activity
             android:name=".ActivityEmbeddingPlaceholderPrimaryActivity"
             android:label="ActivityEmbedding Placeholder Primary"
             android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
-            android:theme="@style/CutoutShortEdges"
             android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
             android:exported="false">
         </activity>
@@ -304,7 +287,6 @@
             android:name=".ActivityEmbeddingPlaceholderSecondaryActivity"
             android:label="ActivityEmbedding Placeholder Secondary"
             android:taskAffinity="com.android.server.wm.flicker.testapp.ActivityEmbedding"
-            android:theme="@style/CutoutShortEdges"
             android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
             android:exported="false"/>
         <activity android:name=".MailActivity"
@@ -334,7 +316,6 @@
                   android:supportsPictureInPicture="true"
                   android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.PipActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:launchMode="singleTop"
                   android:label="PipActivity"
                   android:exported="true">
@@ -350,7 +331,6 @@
         <activity android:name=".BottomHalfPipLaunchingActivity"
             android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
             android:taskAffinity="com.android.server.wm.flicker.testapp.BottomHalfPipLaunchingActivity"
-            android:theme="@style/CutoutShortEdges"
             android:label="BottomHalfPipLaunchingActivity"
             android:exported="true">
             <intent-filter>
@@ -371,7 +351,6 @@
         <activity android:name=".SplitScreenActivity"
                   android:resizeableActivity="true"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.SplitScreenActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:label="SplitScreenPrimaryActivity"
                   android:exported="true"
                   android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
@@ -383,7 +362,6 @@
         <activity android:name=".SplitScreenSecondaryActivity"
                   android:resizeableActivity="true"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.SplitScreenSecondaryActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:label="SplitScreenSecondaryActivity"
                   android:exported="true"
                   android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
@@ -396,7 +374,6 @@
         </activity>
         <activity android:name=".SendNotificationActivity"
                   android:taskAffinity="com.android.server.wm.flicker.testapp.SendNotificationActivity"
-                  android:theme="@style/CutoutShortEdges"
                   android:label="SendNotificationActivity"
                   android:exported="true">
             <intent-filter>
@@ -408,7 +385,6 @@
             android:name=".LaunchBubbleActivity"
             android:label="LaunchBubbleActivity"
             android:exported="true"
-            android:theme="@style/CutoutShortEdges"
             android:launchMode="singleTop">
             <intent-filter>
                 <action android:name="android.intent.action.MAIN"/>
@@ -420,7 +396,6 @@
             android:name=".BubbleActivity"
             android:label="BubbleActivity"
             android:exported="false"
-            android:theme="@style/CutoutShortEdges"
             android:resizeableActivity="true"/>
         <activity
             android:name=".TransferSplashscreenActivity"
@@ -468,4 +443,4 @@
         </service>
     </application>
     <uses-permission android:name="android.permission.ACTIVITY_RECOGNITION"/>
-</manifest>
+</manifest>
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bottom_half_pip.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bottom_half_pip.xml
index 2f9c3aa..15e2a79 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bottom_half_pip.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bottom_half_pip.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical"
     android:background="@android:color/holo_blue_bright">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml
index 7c7b2ca..4bc7099 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_bubble.xml
@@ -16,6 +16,7 @@
   -->
 <LinearLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fitsSystemWindows="true"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <Button
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
index f0dfdfc..e98ffd0 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_base_layout.xml
@@ -19,5 +19,6 @@
     android:id="@+id/root_activity_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical">
 </LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
index 939ba81..16c906d 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_main_layout.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:background="@android:color/holo_orange_light">
 
     <LinearLayout
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml
index 6d4de99..eedb910 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_embedding_secondary_activity_layout.xml
@@ -19,6 +19,7 @@
     android:id="@+id/secondary_activity_layout"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical">
 
   <Button
@@ -49,4 +50,4 @@
       android:layout_height="48dp"
       android:text="Enter pip" />
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
index 507c1b6..5e5203c 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_ime.xml
@@ -17,6 +17,7 @@
     android:layout_width="match_parent"
     android:layout_height="match_parent"
     android:background="@android:color/holo_green_light"
+    android:fitsSystemWindows="true"
     android:focusableInTouchMode="true"
     android:orientation="vertical">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml
index fe7bced..2ab5fe7 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_launch_new.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:background="@android:color/holo_orange_light">
     <Button
         android:id="@+id/launch_second_activity"
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml
index 8a97433..fcef791 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_mail.xml
@@ -19,6 +19,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:app="http://schemas.android.com/apk/res-auto"
     xmlns:tools="http://schemas.android.com/tools"
+    android:fitsSystemWindows="true"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
     <fragment
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml
index 6d5a9dd..aeb8423 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_non_resizeable.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical"
     android:background="@android:color/holo_orange_light">
 
@@ -29,4 +30,4 @@
       android:text="NonResizeableActivity"
       android:textAppearance="?android:attr/textAppearanceLarge"/>
 
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml
index 365a0ea..d66b3d7 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_pip.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical"
     android:background="@android:color/holo_blue_bright">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_simple.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_simple.xml
index 5d94e51..42213d6 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_simple.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_simple.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:background="@android:color/holo_orange_light">
 
 </LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml
index 79e88e4..16c3bc0 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical"
     android:background="@android:color/holo_green_light">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml
index ed9feaf..7643cf5 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_splitscreen_secondary.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical"
     android:background="@android:color/holo_blue_light">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
index c34d200..79e7bb5 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_start_media_projection.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:gravity="center"
     android:orientation="vertical"
     android:background="@android:color/holo_orange_light">
@@ -39,4 +40,4 @@
         android:gravity="center_vertical|center_horizontal"
         android:text="Start Media Projection with extra intent"
         android:textAppearance="?android:attr/textAppearanceLarge"/>
-</LinearLayout>
\ No newline at end of file
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml
index 0b4693d..4d12168 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml
@@ -19,6 +19,7 @@
     android:id="@+id/container"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:background="@android:color/holo_orange_light">
 
     <SurfaceView
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml
index 0730ded..32df5f0 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent.xml
@@ -15,6 +15,7 @@
   ~ limitations under the License.
   -->
 <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:fitsSystemWindows="true"
     android:layout_width="match_parent"
     android:layout_height="match_parent">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml
index ff4ead9..a0c87fd 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_transparent_launch.xml
@@ -17,6 +17,7 @@
 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:orientation="vertical"
     android:background="@android:color/black">
 
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/notification_button.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/notification_button.xml
index 7807200..da58b3f 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/notification_button.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/notification_button.xml
@@ -18,10 +18,12 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:background="@android:color/holo_orange_light">
     <Button
         android:id="@+id/post_notification"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
+        android:layout_gravity="center_horizontal|center_vertical"
         android:text="Post Notification" />
 </LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml
index 8f75d17..ec3135c 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/task_button.xml
@@ -18,6 +18,7 @@
     xmlns:android="http://schemas.android.com/apk/res/android"
     android:layout_width="match_parent"
     android:layout_height="match_parent"
+    android:fitsSystemWindows="true"
     android:background="@android:color/holo_orange_light">
     <Button
         android:id="@+id/launch_new_task"
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml b/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml
index 837d050..ca32448 100644
--- a/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/res/values/styles.xml
@@ -36,10 +36,6 @@
         <item name="android:windowLayoutInDisplayCutoutMode">default</item>
     </style>
 
-    <style name="CutoutShortEdges" parent="@style/DefaultTheme">
-        <item name="android:windowLayoutInDisplayCutoutMode">shortEdges</item>
-    </style>
-
     <style name="CutoutNever" parent="@style/DefaultTheme">
         <item name="android:windowLayoutInDisplayCutoutMode">never</item>
     </style>
@@ -78,4 +74,4 @@
         <!-- Here we want to match the duration of our AVD -->
         <item name="android:windowSplashScreenAnimationDuration">900</item>
     </style>
-</resources>
+</resources>
\ No newline at end of file
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java
index 4418b5a..30bf616 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeActivity.java
@@ -30,7 +30,6 @@
 import android.content.IntentFilter;
 import android.os.Bundle;
 import android.util.Log;
-import android.view.WindowManager;
 
 public class ImeActivity extends Activity {
 
@@ -64,10 +63,6 @@
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.activity_ime);
 
         final var filter = new IntentFilter();
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeEditorPopupDialogActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeEditorPopupDialogActivity.java
index 95f933f..887a15c 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeEditorPopupDialogActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ImeEditorPopupDialogActivity.java
@@ -30,8 +30,6 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
         p.softInputMode = SOFT_INPUT_STATE_ALWAYS_HIDDEN;
         getWindow().setAttributes(p);
         LinearLayout layout = new LinearLayout(this);
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java
index e5710c8..97d7a64 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewActivity.java
@@ -19,17 +19,12 @@
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
-import android.view.WindowManager;
 import android.widget.Button;
 
 public class LaunchNewActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.activity_launch_new);
 
         Button button = findViewById(R.id.launch_second_activity);
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java
index 1809781..402a393 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/LaunchNewTaskActivity.java
@@ -21,17 +21,12 @@
 import android.app.Activity;
 import android.content.Intent;
 import android.os.Bundle;
-import android.view.WindowManager;
 import android.widget.Button;
 
 public class LaunchNewTaskActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.task_button);
 
         Button button = findViewById(R.id.launch_new_task);
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NotificationActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NotificationActivity.java
index d6427ab..6125438 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NotificationActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/NotificationActivity.java
@@ -45,14 +45,10 @@
             requestPermissions(new String[] { POST_NOTIFICATIONS }, 0);
         }
 
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.notification_button);
 
-        Button button = findViewById(R.id.post_notification);
-        button.setOnClickListener(v -> postNotification());
+        ((Button) findViewById(R.id.post_notification))
+                .setOnClickListener(v -> postNotification());
 
         createNotificationChannel();
     }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
index ee25ab2..e030dcf 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PipActivity.java
@@ -47,8 +47,6 @@
 import android.util.Log;
 import android.util.Rational;
 import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
 import android.widget.CheckBox;
 import android.widget.RadioButton;
 
@@ -145,12 +143,6 @@
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
 
-        final Window window = getWindow();
-        final WindowManager.LayoutParams layoutParams = window.getAttributes();
-        layoutParams.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        window.setAttributes(layoutParams);
-
         setContentView(R.layout.activity_pip);
 
         findViewById(R.id.media_session_start)
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java
index b1876b5..552d843 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/PortraitOnlyActivity.java
@@ -18,16 +18,11 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.WindowManager;
 
 public class PortraitOnlyActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.activity_simple);
     }
 }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java
index ce7a005..e98c34d 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SeamlessRotationActivity.java
@@ -61,8 +61,6 @@
     private void enableSeamlessRotation() {
         WindowManager.LayoutParams p = getWindow().getAttributes();
         p.rotationAnimation = WindowManager.LayoutParams.ROTATION_ANIMATION_SEAMLESS;
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
         requestWindowFeature(Window.FEATURE_NO_TITLE);
         getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
                 WindowManager.LayoutParams.FLAG_FULLSCREEN);
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ShowWhenLockedActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ShowWhenLockedActivity.java
index 6f94b74..a533c90 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ShowWhenLockedActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ShowWhenLockedActivity.java
@@ -18,16 +18,11 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.WindowManager;
 
 public class ShowWhenLockedActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.activity_simple);
     }
 }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SimpleActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SimpleActivity.java
index 699abf8..c56eefe 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SimpleActivity.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/SimpleActivity.java
@@ -18,16 +18,11 @@
 
 import android.app.Activity;
 import android.os.Bundle;
-import android.view.WindowManager;
 
 public class SimpleActivity extends Activity {
     @Override
     public void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
-        WindowManager.LayoutParams p = getWindow().getAttributes();
-        p.layoutInDisplayCutoutMode = WindowManager.LayoutParams
-                .LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
-        getWindow().setAttributes(p);
         setContentView(R.layout.activity_simple);
     }
 }
diff --git a/tests/Input/Android.bp b/tests/Input/Android.bp
index 1f0bd61..544f94b 100644
--- a/tests/Input/Android.bp
+++ b/tests/Input/Android.bp
@@ -15,6 +15,7 @@
         "modules-utils-testable-device-config-defaults",
     ],
     srcs: [
+        "src/**/*.aidl",
         "src/**/*.java",
         "src/**/*.kt",
     ],
diff --git a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
index eac4267..7ec8f9c 100644
--- a/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
+++ b/tests/Input/src/com/android/server/input/InputManagerServiceTests.kt
@@ -76,7 +76,7 @@
 import org.mockito.Mockito.times
 import org.mockito.Mockito.verify
 import org.mockito.Mockito.verifyNoMoreInteractions
-import org.mockito.Mockito.verifyZeroInteractions
+import org.mockito.Mockito.verifyNoInteractions
 import org.mockito.Mockito.`when`
 import org.mockito.stubbing.OngoingStubbing
 
@@ -209,7 +209,7 @@
 
     @Test
     fun testStart() {
-        verifyZeroInteractions(native)
+        verifyNoInteractions(native)
 
         service.start()
         verify(native).start()
@@ -217,7 +217,7 @@
 
     @Test
     fun testInputSettingsUpdatedOnSystemRunning() {
-        verifyZeroInteractions(native)
+        verifyNoInteractions(native)
 
         runWithShellPermissionIdentity {
             service.systemRunning()
diff --git a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
index c666fb7..2799f6c 100644
--- a/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
+++ b/tests/Input/src/com/android/server/input/KeyGestureControllerTests.kt
@@ -382,14 +382,6 @@
                 intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
             ),
             TestData(
-                "META + DEL -> Back",
-                intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_DEL),
-                KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
-                intArrayOf(KeyEvent.KEYCODE_DEL),
-                KeyEvent.META_META_ON,
-                intArrayOf(KeyGestureEvent.ACTION_GESTURE_COMPLETE)
-            ),
-            TestData(
                 "META + ESC -> Back",
                 intArrayOf(KeyEvent.KEYCODE_META_LEFT, KeyEvent.KEYCODE_ESCAPE),
                 KeyGestureEvent.KEY_GESTURE_TYPE_BACK,
diff --git a/tests/Input/src/com/android/test/input/AnrTest.kt b/tests/Input/src/com/android/test/input/AnrTest.kt
index 73192ea..f8cb86b 100644
--- a/tests/Input/src/com/android/test/input/AnrTest.kt
+++ b/tests/Input/src/com/android/test/input/AnrTest.kt
@@ -15,32 +15,37 @@
  */
 package com.android.test.input
 
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import androidx.test.filters.MediumTest
-
 import android.app.ActivityManager
 import android.app.ApplicationExitInfo
-import android.content.Context
-import android.graphics.Rect
+import android.app.Instrumentation
+import android.content.Intent
 import android.hardware.display.DisplayManager
 import android.os.Build
+import android.os.Bundle
+import android.os.IBinder
 import android.os.IInputConstants.UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS
 import android.os.SystemClock
-import android.server.wm.CtsWindowInfoUtils.waitForStableWindowGeometry
+import android.server.wm.CtsWindowInfoUtils.getWindowCenter
+import android.server.wm.CtsWindowInfoUtils.waitForWindowOnTop
 import android.testing.PollingCheck
-
+import android.view.InputEvent
+import android.view.MotionEvent
+import android.view.MotionEvent.ACTION_DOWN
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.MediumTest
+import androidx.test.platform.app.InstrumentationRegistry
 import androidx.test.uiautomator.By
 import androidx.test.uiautomator.UiDevice
 import androidx.test.uiautomator.UiObject2
 import androidx.test.uiautomator.Until
-
+import com.android.cts.input.BlockingQueueEventVerifier
 import com.android.cts.input.DebugInputRule
 import com.android.cts.input.ShowErrorDialogsRule
 import com.android.cts.input.UinputTouchScreen
-
+import com.android.cts.input.inputeventmatchers.withMotionAction
 import java.time.Duration
-
+import java.util.concurrent.LinkedBlockingQueue
+import java.util.function.Supplier
 import org.junit.After
 import org.junit.Assert.assertEquals
 import org.junit.Assert.assertTrue
@@ -51,13 +56,34 @@
 import org.junit.runner.RunWith
 
 /**
+ * Click on the center of the window identified by the provided window token.
+ * The click is performed using "UinputTouchScreen" device.
+ * If the touchscreen device is closed too soon, it may cause the click to be dropped. Therefore,
+ * the provided runnable can ensure that the click is delivered before the device is closed, thus
+ * avoiding this race.
+ */
+private fun clickOnWindow(
+    token: IBinder,
+    displayId: Int,
+    instrumentation: Instrumentation,
+    waitForEvent: Runnable,
+) {
+    val displayManager = instrumentation.context.getSystemService(DisplayManager::class.java)
+    val display = displayManager.getDisplay(displayId)
+    val point = getWindowCenter({ token }, display.displayId)
+    UinputTouchScreen(instrumentation, display).use { touchScreen ->
+        touchScreen.touchDown(point.x, point.y).lift()
+        // If the device is allowed to close without waiting here, the injected click may be dropped
+        waitForEvent.run()
+    }
+}
+
+/**
  * This test makes sure that an unresponsive gesture monitor gets an ANR.
  *
  * The gesture monitor must be registered from a different process than the instrumented process.
- * Otherwise, when the test runs, you will get:
- * Test failed to run to completion.
- * Reason: 'Instrumentation run failed due to 'keyDispatchingTimedOut''.
- * Check device logcat for details
+ * Otherwise, when the test runs, you will get: Test failed to run to completion. Reason:
+ * 'Instrumentation run failed due to 'keyDispatchingTimedOut''. Check device logcat for details
  * RUNNER ERROR: Instrumentation run failed due to 'keyDispatchingTimedOut'
  */
 @MediumTest
@@ -65,30 +91,43 @@
 class AnrTest {
     companion object {
         private const val TAG = "AnrTest"
-        private const val ALL_PIDS = 0
         private const val NO_MAX = 0
     }
 
     private val instrumentation = InstrumentationRegistry.getInstrumentation()
-    private var hideErrorDialogs = 0
     private lateinit var PACKAGE_NAME: String
-    private val DISPATCHING_TIMEOUT = (UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS *
-            Build.HW_TIMEOUT_MULTIPLIER)
+    private val DISPATCHING_TIMEOUT =
+        (UNMULTIPLIED_DEFAULT_DISPATCHING_TIMEOUT_MILLIS * Build.HW_TIMEOUT_MULTIPLIER)
+    private var remoteWindowToken: IBinder? = null
+    private var remoteDisplayId: Int? = null
+    private var remotePid: Int? = null
+    private val remoteInputEvents = LinkedBlockingQueue<InputEvent>()
+    private val verifier = BlockingQueueEventVerifier(remoteInputEvents)
 
-    @get:Rule
-    val debugInputRule = DebugInputRule()
+    val binder =
+        object : IAnrTestService.Stub() {
+            override fun provideActivityInfo(token: IBinder, displayId: Int, pid: Int) {
+                remoteWindowToken = token
+                remoteDisplayId = displayId
+                remotePid = pid
+            }
 
-    @get:Rule
-    val showErrorDialogs = ShowErrorDialogsRule()
+            override fun notifyMotion(event: MotionEvent) {
+                remoteInputEvents.add(event)
+            }
+        }
+
+    @get:Rule val showErrorDialogs = ShowErrorDialogsRule()
+
+    @get:Rule val debugInputRule = DebugInputRule()
 
     @Before
     fun setUp() {
+        startUnresponsiveActivity()
         PACKAGE_NAME = UnresponsiveGestureMonitorActivity::class.java.getPackage()!!.getName()
     }
 
-    @After
-    fun tearDown() {
-    }
+    @After fun tearDown() {}
 
     @Test
     @DebugInputRule.DebugInput(bug = 339924248)
@@ -112,7 +151,7 @@
         val timestamp = System.currentTimeMillis()
         val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
         val closeAppButton: UiObject2? =
-                uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000)
+            uiDevice.wait(Until.findObject(By.res("android:id/aerr_close")), 20000)
         if (closeAppButton == null) {
             fail("Could not find anr dialog/close button")
             return
@@ -120,10 +159,10 @@
         closeAppButton.click()
         /**
          * We must wait for the app to be fully closed before exiting this test. This is because
-         * another test may again invoke 'am start' for the same activity.
-         * If the 1st process that got ANRd isn't killed by the time second 'am start' runs,
-         * the killing logic will apply to the newly launched 'am start' instance, and the second
-         * test will fail because the unresponsive activity will never be launched.
+         * another test may again invoke 'am start' for the same activity. If the 1st process that
+         * got ANRd isn't killed by the time second 'am start' runs, the killing logic will apply to
+         * the newly launched 'am start' instance, and the second test will fail because the
+         * unresponsive activity will never be launched.
          */
         waitForNewExitReasonAfter(timestamp)
     }
@@ -132,7 +171,7 @@
         // Find anr dialog and tap on wait
         val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
         val waitButton: UiObject2? =
-                uiDevice.wait(Until.findObject(By.res("android:id/aerr_wait")), 20000)
+            uiDevice.wait(Until.findObject(By.res("android:id/aerr_wait")), 20000)
         if (waitButton == null) {
             fail("Could not find anr dialog/wait button")
             return
@@ -144,7 +183,7 @@
         lateinit var infos: List<ApplicationExitInfo>
         instrumentation.runOnMainSync {
             val am = instrumentation.getContext().getSystemService(ActivityManager::class.java)!!
-            infos = am.getHistoricalProcessExitReasons(PACKAGE_NAME, ALL_PIDS, NO_MAX)
+            infos = am.getHistoricalProcessExitReasons(PACKAGE_NAME, remotePid!!, NO_MAX)
         }
         return infos
     }
@@ -159,37 +198,32 @@
         assertEquals(ApplicationExitInfo.REASON_ANR, reasons[0].reason)
     }
 
-    private fun clickOnObject(obj: UiObject2) {
-        val displayManager =
-            instrumentation.context.getSystemService(Context.DISPLAY_SERVICE) as DisplayManager
-        val display = displayManager.getDisplay(obj.getDisplayId())
-        val rect: Rect = obj.visibleBounds
-        UinputTouchScreen(instrumentation, display).use { touchScreen ->
-            touchScreen
-                .touchDown(rect.centerX(), rect.centerY())
-                .lift()
-        }
-    }
-
     private fun triggerAnr() {
-        startUnresponsiveActivity()
-        val uiDevice: UiDevice = UiDevice.getInstance(instrumentation)
-        val obj: UiObject2? = uiDevice.wait(Until.findObject(By.pkg(PACKAGE_NAME)), 10000)
-
-        if (obj == null) {
-            fail("Could not find unresponsive activity")
-            return
-        }
-
-        clickOnObject(obj)
+        clickOnWindow(
+            remoteWindowToken!!,
+            remoteDisplayId!!,
+            instrumentation,
+        ) { verifier.assertReceivedMotion(withMotionAction(ACTION_DOWN)) }
 
         SystemClock.sleep(DISPATCHING_TIMEOUT.toLong()) // default ANR timeout for gesture monitors
     }
 
     private fun startUnresponsiveActivity() {
-        val flags = " -W -n "
-        val startCmd = "am start $flags $PACKAGE_NAME/.UnresponsiveGestureMonitorActivity"
-        instrumentation.uiAutomation.executeShellCommand(startCmd)
-        waitForStableWindowGeometry(Duration.ofSeconds(5))
+        val intent =
+            Intent(instrumentation.targetContext, UnresponsiveGestureMonitorActivity::class.java)
+        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_NEW_DOCUMENT
+        val bundle = Bundle()
+        bundle.putBinder("serviceBinder", binder)
+        intent.putExtra("serviceBundle", bundle)
+        instrumentation.targetContext.startActivity(intent)
+        // first, wait for the token to become valid
+        PollingCheck.check(
+                "UnresponsiveGestureMonitorActivity failed to call 'provideActivityInfo'",
+                Duration.ofSeconds(5).toMillis()) { remoteWindowToken != null }
+        // next, wait for the window of the activity to get on top
+        // we could combine the two checks above, but the current setup makes it easier to detect
+        // errors
+        assertTrue("Remote activity window did not become visible",
+          waitForWindowOnTop(Duration.ofSeconds(5), Supplier { remoteWindowToken }))
     }
 }
diff --git a/tests/Input/src/com/android/test/input/IAnrTestService.aidl b/tests/Input/src/com/android/test/input/IAnrTestService.aidl
new file mode 100644
index 0000000..e3caf06
--- /dev/null
+++ b/tests/Input/src/com/android/test/input/IAnrTestService.aidl
@@ -0,0 +1,17 @@
+package com.android.test.input;
+
+import android.view.MotionEvent;
+
+interface IAnrTestService {
+    /**
+     * Provide the activity information. This includes:
+     * windowToken: the windowToken of the activity window
+     * displayId: the display id on which the activity is positioned
+     * pid: the pid of the activity
+     */
+    void provideActivityInfo(IBinder windowToken, int displayId, int pid);
+    /**
+     * Provide the MotionEvent received by the remote activity.
+     */
+    void notifyMotion(in MotionEvent event);
+}
diff --git a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
index 1842f0a..1e44617 100644
--- a/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
+++ b/tests/Input/src/com/android/test/input/UnresponsiveGestureMonitorActivity.kt
@@ -23,20 +23,24 @@
 import android.hardware.input.InputManager
 import android.os.Bundle
 import android.os.Looper
+import android.os.Process
 import android.util.Log
 import android.view.InputChannel
 import android.view.InputEvent
 import android.view.InputEventReceiver
 import android.view.InputMonitor
+import android.view.MotionEvent
 
-class UnresponsiveReceiver(channel: InputChannel, looper: Looper) :
-        InputEventReceiver(channel, looper) {
+class UnresponsiveReceiver(channel: InputChannel, looper: Looper, val service: IAnrTestService) :
+    InputEventReceiver(channel, looper) {
     companion object {
         const val TAG = "UnresponsiveReceiver"
     }
+
     override fun onInputEvent(event: InputEvent) {
         Log.i(TAG, "Received $event")
         // Not calling 'finishInputEvent' in order to trigger the ANR
+        service.notifyMotion(event as MotionEvent)
     }
 }
 
@@ -44,14 +48,27 @@
     companion object {
         const val MONITOR_NAME = "unresponsive gesture monitor"
     }
+
     private lateinit var mInputEventReceiver: InputEventReceiver
     private lateinit var mInputMonitor: InputMonitor
+    private lateinit var service: IAnrTestService
 
     override fun onCreate(savedInstanceState: Bundle?) {
         super.onCreate(savedInstanceState)
+        val bundle = intent.getBundleExtra("serviceBundle")!!
+        service = IAnrTestService.Stub.asInterface(bundle.getBinder("serviceBinder"))
         val inputManager = checkNotNull(getSystemService(InputManager::class.java))
         mInputMonitor = inputManager.monitorGestureInput(MONITOR_NAME, displayId)
-        mInputEventReceiver = UnresponsiveReceiver(
-                mInputMonitor.getInputChannel(), Looper.myLooper()!!)
+        mInputEventReceiver =
+            UnresponsiveReceiver(mInputMonitor.getInputChannel(), Looper.myLooper()!!, service)
+    }
+
+    override fun onAttachedToWindow() {
+        super.onAttachedToWindow()
+        service.provideActivityInfo(
+            window.decorView.windowToken,
+            display.displayId,
+            Process.myPid(),
+        )
     }
 }
diff --git a/tests/PackageWatchdog/Android.bp b/tests/PackageWatchdog/Android.bp
index 16c6e3b..46cb5b7 100644
--- a/tests/PackageWatchdog/Android.bp
+++ b/tests/PackageWatchdog/Android.bp
@@ -55,4 +55,8 @@
         "mts-crashrecovery",
     ],
     min_sdk_version: "36",
+
+    // Test coverage system runs on different devices. Need to
+    // compile for all architecture.
+    compile_multilib: "both",
 }
diff --git a/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java b/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java
index 51d57f0..f5d4b0c 100644
--- a/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java
+++ b/tests/UsbTests/src/com/android/server/usb/UsbServiceTest.java
@@ -24,15 +24,20 @@
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
+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.ArgumentMatchers.isNull;
 import static org.mockito.Mockito.clearInvocations;
+import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
+import android.hardware.usb.IUsbManagerInternal;
 import android.hardware.usb.IUsbOperationInternal;
 import android.hardware.usb.flags.Flags;
 import android.hardware.usb.UsbPort;
@@ -70,7 +75,9 @@
     @Mock
     private IUsbOperationInternal mCallback;
 
-    private static final String TEST_PORT_ID = "123";
+    private static final String TEST_PORT_ID = "1";
+
+    private static final String TEST_PORT_ID_2 = "2";
 
     private static final int TEST_TRANSACTION_ID = 1;
 
@@ -84,7 +91,7 @@
 
     private UsbService mUsbService;
 
-    private UsbManagerInternal mUsbManagerInternal;
+    private IUsbManagerInternal mIUsbManagerInternal;
 
     @Rule
     public final SetFlagsRule mSetFlagsRule = new SetFlagsRule();
@@ -101,9 +108,9 @@
 
         mUsbService = new UsbService(mContext, mUsbPortManager, mUsbAlsaManager,
                 mUserManager, mUsbSettingsManager);
-        mUsbManagerInternal = LocalServices.getService(UsbManagerInternal.class);
-        assertWithMessage("LocalServices.getService(UsbManagerInternal.class)")
-            .that(mUsbManagerInternal).isNotNull();
+        mIUsbManagerInternal = LocalServices.getService(IUsbManagerInternal.class);
+        assertWithMessage("LocalServices.getService(IUsbManagerInternal.class)")
+            .that(mIUsbManagerInternal).isNotNull();
     }
 
     private void assertToggleUsbSuccessfully(int requester, boolean enable,
@@ -255,30 +262,42 @@
         assertToggleUsbSuccessfully(TEST_INTERNAL_REQUESTER_REASON_1, true, false);
     }
 
-    /**
-     * Verify USB Manager internal calls mPortManager to get UsbPorts
-     */
     @Test
-    public void usbManagerInternal_getPorts_callsPortManager() {
-        when(mUsbPortManager.getPorts()).thenReturn(new UsbPort[] {});
-
-        UsbPort[] ports = mUsbManagerInternal.getPorts();
-
-        verify(mUsbPortManager).getPorts();
-        assertEquals(ports.length, 0);
+    public void usbManagerInternal_enableUsbDataSignal_successfullyEnabled() {
+        assertTrue(runInternalUsbDataSignalTest(true, true, true));
     }
 
     @Test
-    public void usbManagerInternal_enableUsbData_successfullyEnable() {
-        boolean desiredEnableState = true;
+    public void usbManagerInternal_enableUsbDataSignal_successfullyDisabled() {
+        assertTrue(runInternalUsbDataSignalTest(false, true, true));
+    }
 
-        assertTrue(mUsbManagerInternal.enableUsbData(TEST_PORT_ID, desiredEnableState,
-        TEST_TRANSACTION_ID, mCallback, TEST_INTERNAL_REQUESTER_REASON_1));
+    @Test
+    public void usbManagerInternal_enableUsbDataSignal_returnsFalseIfOnePortFails() {
+        assertFalse(runInternalUsbDataSignalTest(true, true, false));
+    }
 
-        verify(mUsbPortManager).enableUsbData(TEST_PORT_ID,
-                desiredEnableState, TEST_TRANSACTION_ID, mCallback, null);
-        verifyZeroInteractions(mCallback);
-        clearInvocations(mUsbPortManager);
-        clearInvocations(mCallback);
+    private boolean runInternalUsbDataSignalTest(boolean desiredEnableState, boolean portOneSuccess,
+        boolean portTwoSuccess) {
+        UsbPort port = mock(UsbPort.class);
+        UsbPort port2 = mock(UsbPort.class);
+        when(port.getId()).thenReturn(TEST_PORT_ID);
+        when(port2.getId()).thenReturn(TEST_PORT_ID_2);
+        when(mUsbPortManager.getPorts()).thenReturn(new UsbPort[] { port, port2 });
+        when(mUsbPortManager.enableUsbData(eq(TEST_PORT_ID),
+                eq(desiredEnableState), anyInt(), any(IUsbOperationInternal.class), isNull()))
+            .thenReturn(portOneSuccess);
+        when(mUsbPortManager.enableUsbData(eq(TEST_PORT_ID_2),
+                eq(desiredEnableState), anyInt(), any(IUsbOperationInternal.class), isNull()))
+            .thenReturn(portTwoSuccess);
+        try {
+            boolean result = mIUsbManagerInternal.enableUsbDataSignal(desiredEnableState,
+                        TEST_INTERNAL_REQUESTER_REASON_1);
+            clearInvocations(mUsbPortManager);
+            return result;
+        } catch(RemoteException e) {
+            fail("RemoteException thrown when calling enableUsbDataSignal");
+            return false;
+        }
     }
 }
diff --git a/tools/codegen/src/com/android/codegen/Debug.kt b/tools/codegen/src/com/android/codegen/Debug.kt
index de31844..6423c4f 100644
--- a/tools/codegen/src/com/android/codegen/Debug.kt
+++ b/tools/codegen/src/com/android/codegen/Debug.kt
@@ -21,7 +21,7 @@
 fun Node.dump(indent: String = ""): String {
     return buildString {
         append(indent)
-        appendln(dumpOneLineNoChildren())
+        appendLine(dumpOneLineNoChildren())
         childNodes.forEach { child ->
             append(child.dump(indent + "  "))
         }
diff --git a/tools/codegen/src/com/android/codegen/FeatureFlag.kt b/tools/codegen/src/com/android/codegen/FeatureFlag.kt
index 24150d6..f305429 100644
--- a/tools/codegen/src/com/android/codegen/FeatureFlag.kt
+++ b/tools/codegen/src/com/android/codegen/FeatureFlag.kt
@@ -22,6 +22,6 @@
     CONST_DEFS(true, "@Int/StringDef's based on declared static constants"),
     FOR_EACH_FIELD(false, "forEachField((name, value) -> ...)");
 
-    val kebabCase = name.toLowerCase().replace("_", "-")
-    val upperCamelCase = name.split("_").map { it.toLowerCase().capitalize() }.joinToString("")
+    val kebabCase = name.lowercase().replace("_", "-")
+    val upperCamelCase = name.split("_").map { it.lowercase().capitalize() }.joinToString("")
 }
diff --git a/tools/codegen/src/com/android/codegen/FileInfo.kt b/tools/codegen/src/com/android/codegen/FileInfo.kt
index cc3a156..ca04f1e 100644
--- a/tools/codegen/src/com/android/codegen/FileInfo.kt
+++ b/tools/codegen/src/com/android/codegen/FileInfo.kt
@@ -126,7 +126,7 @@
                 +"\n}"
             }
             // Print general code as-is
-            is CodeChunk.Code -> chunk.lines.forEach { stringBuilder.appendln(it) }
+            is CodeChunk.Code -> chunk.lines.forEach { stringBuilder.appendLine(it) }
             // Recursively render data classes
             is CodeChunk.DataClass -> chunk.chunks.forEach { print(it) }
         }
@@ -175,11 +175,11 @@
         /** Debug info */
         override fun toString(): String {
             return buildString {
-                appendln("class $name $range")
+                appendLine("class $name $range")
                 nested.forEach {
-                    appendln(it)
+                    appendLine(it)
                 }
-                appendln("end $name")
+                appendLine("end $name")
             }
         }
     }
diff --git a/tools/codegen/src/com/android/codegen/Generators.kt b/tools/codegen/src/com/android/codegen/Generators.kt
index d3a8b03..7109602 100644
--- a/tools/codegen/src/com/android/codegen/Generators.kt
+++ b/tools/codegen/src/com/android/codegen/Generators.kt
@@ -43,7 +43,7 @@
     }
     var AnnotationName = prefix.split("_")
             .filterNot { it.isBlank() }
-            .map { it.toLowerCase().capitalize() }
+            .map { it.lowercase().capitalize() }
             .joinToString("")
     val annotatedConst = consts.find { it.second.annotations.isNonEmpty }
     if (annotatedConst != null) {
@@ -122,7 +122,7 @@
     if (aidl.exists()) return
     aidl.writeText(buildString {
         sourceLines.dropLastWhile { !it.startsWith("package ") }.forEach {
-            appendln(it)
+            appendLine(it)
         }
         append("\nparcelable ${mainClass.nameAsString};\n")
     })
diff --git a/tools/codegen/src/com/android/codegen/Utils.kt b/tools/codegen/src/com/android/codegen/Utils.kt
index a40bdd7..9631443 100644
--- a/tools/codegen/src/com/android/codegen/Utils.kt
+++ b/tools/codegen/src/com/android/codegen/Utils.kt
@@ -62,7 +62,7 @@
     if (length >= 2 && this[0] == 'm' && this[1].isUpperCase()) return substring(1).capitalize()
     if (all { it.isLetterOrDigit() }) return decapitalize()
     return split("[^a-zA-Z0-9]".toRegex())
-            .map { it.toLowerCase().capitalize() }
+            .map { it.lowercase().capitalize() }
             .joinToString("")
             .decapitalize()
 }
diff --git a/tools/fonts/Android.bp b/tools/fonts/Android.bp
index f8629f9..07caa9a 100644
--- a/tools/fonts/Android.bp
+++ b/tools/fonts/Android.bp
@@ -23,11 +23,6 @@
 
 python_defaults {
     name: "fonts_python_defaults",
-    version: {
-        py3: {
-            embedded_launcher: true,
-        },
-    },
 }
 
 python_binary_host {
diff --git a/tools/lint/fix/Android.bp b/tools/lint/fix/Android.bp
index ddacf57..43f2122 100644
--- a/tools/lint/fix/Android.bp
+++ b/tools/lint/fix/Android.bp
@@ -25,11 +25,6 @@
     name: "lint_fix",
     main: "soong_lint_fix.py",
     srcs: ["soong_lint_fix.py"],
-    version: {
-        py3: {
-            embedded_launcher: true,
-        },
-    },
 }
 
 python_library_host {
diff --git a/tools/lint/global/integration_tests/Android.bp b/tools/lint/global/integration_tests/Android.bp
index 05ba405..f887093 100644
--- a/tools/lint/global/integration_tests/Android.bp
+++ b/tools/lint/global/integration_tests/Android.bp
@@ -65,9 +65,4 @@
         "AndroidGlobalLintTestNoAidl_py",
         "AndroidGlobalLintTestMissingAnnotation_py",
     ],
-    version: {
-        py3: {
-            embedded_launcher: true,
-        },
-    },
 }