Merge changes from topic "cherrypicker-L27500000962600793:N19100001397012006" into main

* changes:
  Enable the Compose implementation of the QS footer actions
  Enable the Compose implementation of the PeopleSpaceActivity
  Hide Flexiglass Compose code behind a constant Boolean flag
diff --git a/AconfigFlags.bp b/AconfigFlags.bp
index 9a417e9..2ab8d80 100644
--- a/AconfigFlags.bp
+++ b/AconfigFlags.bp
@@ -21,6 +21,7 @@
         ":android.os.flags-aconfig-java{.generated_srcjars}",
         ":android.os.vibrator.flags-aconfig-java{.generated_srcjars}",
         ":android.security.flags-aconfig-java{.generated_srcjars}",
+        ":android.media.flags-aconfig-java{.generated_srcjars}",
         ":camera_platform_flags_core_java_lib{.generated_srcjars}",
         ":com.android.window.flags.window-aconfig-java{.generated_srcjars}",
         ":com.android.text.flags-aconfig-java{.generated_srcjars}",
@@ -157,3 +158,16 @@
     aconfig_declarations: "android.os.vibrator.flags-aconfig",
     defaults: ["framework-minus-apex-aconfig-java-defaults"],
 }
+
+// Media
+aconfig_declarations {
+    name: "android.media.flags-aconfig",
+    package: "android.media",
+    srcs: ["media/java/android/media/*.aconfig"],
+}
+
+java_aconfig_library {
+    name: "android.media.flags-aconfig-java",
+    aconfig_declarations: "android.media.flags-aconfig",
+    defaults: ["framework-minus-apex-aconfig-java-defaults"],
+}
diff --git a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
index a41fb64..0778311 100644
--- a/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
+++ b/core/tests/coretests/src/android/app/activity/ActivityThreadTest.java
@@ -67,7 +67,6 @@
 import android.window.WindowContextInfo;
 import android.window.WindowTokenClientController;
 
-import androidx.test.filters.FlakyTest;
 import androidx.test.filters.MediumTest;
 import androidx.test.platform.app.InstrumentationRegistry;
 import androidx.test.rule.ActivityTestRule;
@@ -254,15 +253,9 @@
 
             // Execute a local relaunch item with current scaled config (e.g. simulate recreate),
             // the config should not be scaled again.
-            final Configuration currentConfig = activity.getResources().getConfiguration();
-            final ClientTransaction localTransaction =
-                    newTransaction(activityThread, activity.getActivityToken());
-            localTransaction.addCallback(ActivityRelaunchItem.obtain(
-                    null /* pendingResults */, null /* pendingIntents */, 0 /* configChanges */,
-                    new MergedConfiguration(currentConfig, currentConfig),
-                    true /* preserveWindow */));
             InstrumentationRegistry.getInstrumentation().runOnMainSync(
-                    () -> activityThread.executeTransaction(localTransaction));
+                    () -> activityThread.executeTransaction(
+                            newRelaunchResumeTransaction(activity)));
 
             assertScreenScale(scale, activity, originalActivityConfig, originalActivityMetrics);
         } finally {
@@ -630,7 +623,6 @@
         });
     }
 
-    @FlakyTest(bugId = 298331121)
     @Test
     public void testHandleConfigurationChanged_DoesntOverrideActivityConfig() {
         final TestActivity activity = mActivityTestRule.launchActivity(new Intent());
diff --git a/media/java/android/media/flags.aconfig b/media/java/android/media/flags.aconfig
new file mode 100644
index 0000000..8567a3b
--- /dev/null
+++ b/media/java/android/media/flags.aconfig
@@ -0,0 +1,8 @@
+package: "android.media"
+
+flag {
+    name: "haptics_customization_enabled"
+    namespace: "media"
+    description: "Enables the haptics customization feature"
+    bug: "241918098"
+}
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
index 90a723f..b77368a 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/CustomizedAppBar.kt
@@ -253,6 +253,7 @@
             hideTitleSemantics = false,
             navigationIcon = navigationIcon,
             actions = actionsRow,
+            titleScaleDisabled = false,
         )
     }
 }
@@ -426,6 +427,7 @@
  * accessibility services at the same time, when animating between collapsed / expanded states.
  * @param navigationIcon a navigation icon [Composable]
  * @param actions actions [Composable]
+ * @param titleScaleDisabled whether the title font scaling is disabled. Default is disabled.
  */
 @Composable
 private fun TopAppBarLayout(
@@ -443,6 +445,7 @@
     hideTitleSemantics: Boolean,
     navigationIcon: @Composable () -> Unit,
     actions: @Composable () -> Unit,
+    titleScaleDisabled: Boolean = true,
 ) {
     Layout(
         {
@@ -466,9 +469,12 @@
                 ProvideTextStyle(value = titleTextStyle) {
                     CompositionLocalProvider(
                         LocalContentColor provides titleContentColor,
-                        // Disable the title font scaling by only passing the density but not the
-                        // font scale.
-                        LocalDensity provides Density(density = LocalDensity.current.density),
+                        LocalDensity provides with(LocalDensity.current) {
+                          Density(
+                              density = density,
+                              fontScale = if (titleScaleDisabled) 1f else fontScale,
+                          )
+                        },
                         content = title
                     )
                 }
diff --git a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
index d437e35..696e877 100644
--- a/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
+++ b/packages/SettingsLib/Spa/spa/src/com/android/settingslib/spa/widget/scaffold/SearchScaffold.kt
@@ -18,6 +18,7 @@
 
 import androidx.activity.compose.BackHandler
 import androidx.appcompat.R
+import androidx.compose.foundation.focusable
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.Column
 import androidx.compose.foundation.layout.RowScope
@@ -96,7 +97,8 @@
             Modifier
                 .padding(paddingValues.horizontalValues())
                 .padding(top = paddingValues.calculateTopPadding())
-                .fillMaxSize(),
+                .focusable()
+                .fillMaxSize()
         ) {
             content(
                 paddingValues.calculateBottomPadding(),
diff --git a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
index f68078a..82b0324 100644
--- a/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/display/data/repository/DisplayRepository.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.dagger.qualifiers.Background
+import com.android.systemui.util.Compile
 import com.android.systemui.util.traceSection
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineDispatcher
@@ -239,7 +240,7 @@
 
     private companion object {
         const val TAG = "DisplayRepository"
-        val DEBUG = Log.isLoggable(TAG, Log.DEBUG)
+        val DEBUG = Log.isLoggable(TAG, Log.DEBUG) || Compile.IS_DEBUG
     }
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 8db7abf..c199904 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -163,6 +163,7 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
+import com.android.systemui.shade.data.repository.ShadeRepository;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.shared.system.InteractionJankMonitorWrapper;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -350,6 +351,7 @@
     private final Interpolator mBounceInterpolator;
     private final NotificationShadeWindowController mNotificationShadeWindowController;
     private final ShadeExpansionStateManager mShadeExpansionStateManager;
+    private final ShadeRepository mShadeRepository;
     private final FalsingTapListener mFalsingTapListener = this::falsingAdditionalTapRequired;
     private final AccessibilityDelegate mAccessibilityDelegate = new ShadeAccessibilityDelegate();
     private final NotificationGutsManager mGutsManager;
@@ -710,7 +712,8 @@
             VibratorHelper vibratorHelper,
             LatencyTracker latencyTracker,
             PowerManager powerManager,
-            AccessibilityManager accessibilityManager, @DisplayId int displayId,
+            AccessibilityManager accessibilityManager,
+            @DisplayId int displayId,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             MetricsLogger metricsLogger,
             ShadeLogger shadeLogger,
@@ -746,6 +749,7 @@
             ScreenOffAnimationController screenOffAnimationController,
             LockscreenGestureLogger lockscreenGestureLogger,
             ShadeExpansionStateManager shadeExpansionStateManager,
+            ShadeRepository shadeRepository,
             Optional<SysUIUnfoldComponent> unfoldComponent,
             SysUiState sysUiState,
             Provider<KeyguardBottomAreaViewController> keyguardBottomAreaViewControllerProvider,
@@ -788,6 +792,7 @@
         mStatusBarKeyguardViewManager = statusBarKeyguardViewManager;
         mLockscreenGestureLogger = lockscreenGestureLogger;
         mShadeExpansionStateManager = shadeExpansionStateManager;
+        mShadeRepository = shadeRepository;
         mShadeLog = shadeLogger;
         mGutsManager = gutsManager;
         mDreamingToLockscreenTransitionViewModel = dreamingToLockscreenTransitionViewModel;
@@ -3952,6 +3957,7 @@
             }
             mExpandedFraction = Math.min(1f,
                     maxPanelHeight == 0 ? 0 : mExpandedHeight / maxPanelHeight);
+            mShadeRepository.setLegacyShadeExpansion(mExpandedFraction);
             mQsController.setShadeExpansion(mExpandedHeight, mExpandedFraction);
             mExpansionDragDownAmountPx = h;
             mAmbientState.setExpansionFraction(mExpandedFraction);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
index 5a8be1e..509921f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/data/repository/ShadeRepository.kt
@@ -34,21 +34,48 @@
     /** ShadeModel information regarding shade expansion events */
     val shadeModel: Flow<ShadeModel>
 
-    /** Amount qs has expanded. Quick Settings can be expanded without the full shade expansion. */
+    /**
+     * Amount qs has expanded, [0-1]. 0 means fully collapsed, 1 means fully expanded. Quick
+     * Settings can be expanded without the full shade expansion.
+     */
     val qsExpansion: StateFlow<Float>
 
-    /** The amount the shade has expanded */
-    val shadeExpansion: StateFlow<Float>
+    /**
+     * The amount the lockscreen shade has dragged down by the user, [0-1]. 0 means fully collapsed,
+     * 1 means fully expanded.
+     */
+    val lockscreenShadeExpansion: StateFlow<Float>
+
+    /**
+     * NotificationPanelViewController.mExpandedFraction as a StateFlow. This nominally represents
+     * the amount the shade has expanded 0-1 like many other flows in this repo, but there are cases
+     * where its value will be 1 and no shade will be rendered, e.g. whenever the keyguard is
+     * visible and when quick settings is expanded. The confusing nature and impending deletion of
+     * this makes it unsuitable for future development, so usage is discouraged.
+     */
+    @Deprecated("Use ShadeInteractor.shadeExpansion instead")
+    val legacyShadeExpansion: StateFlow<Float>
 
     /** Amount shade has expanded with regard to the UDFPS location */
     val udfpsTransitionToFullShadeProgress: StateFlow<Float>
 
     /** The amount QS has expanded without notifications */
     fun setQsExpansion(qsExpansion: Float)
+
     fun setUdfpsTransitionToFullShadeProgress(progress: Float)
 
-    /** The amount the shade has expanded, [0-1]. 0 means fully collapsed, 1 means fully expanded */
-    fun setShadeExpansion(expansion: Float)
+    /**
+     * Set the amount the shade has dragged down by the user, [0-1]. 0 means fully collapsed, 1
+     * means fully expanded.
+     */
+    fun setLockscreenShadeExpansion(lockscreenShadeExpansion: Float)
+
+    /**
+     * Set the legacy expansion value. This should only be called whenever the value of
+     * NotificationPanelViewController.mExpandedFraction changes or in tests.
+     */
+    @Deprecated("Should only be called by NPVC and tests")
+    fun setLegacyShadeExpansion(expandedFraction: Float)
 }
 
 /** Business logic for shade interactions */
@@ -84,18 +111,29 @@
     private val _qsExpansion = MutableStateFlow(0f)
     override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow()
 
-    private val _shadeExpansion = MutableStateFlow(0f)
-    override val shadeExpansion: StateFlow<Float> = _shadeExpansion.asStateFlow()
+    private val _lockscreenShadeExpansion = MutableStateFlow(0f)
+    override val lockscreenShadeExpansion: StateFlow<Float> =
+        _lockscreenShadeExpansion.asStateFlow()
 
     private var _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
     override val udfpsTransitionToFullShadeProgress: StateFlow<Float> =
         _udfpsTransitionToFullShadeProgress.asStateFlow()
+
+    private val _legacyShadeExpansion = MutableStateFlow(0f)
+    @Deprecated("Use ShadeInteractor.shadeExpansion instead")
+    override val legacyShadeExpansion: StateFlow<Float> = _legacyShadeExpansion.asStateFlow()
+
     override fun setQsExpansion(qsExpansion: Float) {
         _qsExpansion.value = qsExpansion
     }
 
-    override fun setShadeExpansion(expansion: Float) {
-        _shadeExpansion.value = expansion
+    @Deprecated("Should only be called by NPVC and tests")
+    override fun setLegacyShadeExpansion(expandedFraction: Float) {
+        _legacyShadeExpansion.value = expandedFraction
+    }
+
+    override fun setLockscreenShadeExpansion(lockscreenShadeExpansion: Float) {
+        _lockscreenShadeExpansion.value = lockscreenShadeExpansion
     }
 
     override fun setUdfpsTransitionToFullShadeProgress(progress: Float) {
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index 288d32e..fd63b89 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.shade.data.repository.ShadeRepository
 import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
+import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.UserSetupRepository
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.user.domain.interactor.UserInteractor
@@ -31,6 +32,7 @@
 import kotlinx.coroutines.flow.SharingStarted
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.distinctUntilChanged
 import kotlinx.coroutines.flow.map
 import kotlinx.coroutines.flow.stateIn
 
@@ -45,6 +47,7 @@
     userSetupRepository: UserSetupRepository,
     deviceProvisionedController: DeviceProvisionedController,
     userInteractor: UserInteractor,
+    sharedNotificationContainerInteractor: SharedNotificationContainerInteractor,
     repository: ShadeRepository,
 ) {
     /** Emits true if the shade is currently allowed and false otherwise. */
@@ -53,16 +56,31 @@
             .map { it.isShadeEnabled() }
             .stateIn(scope, SharingStarted.Eagerly, initialValue = false)
 
+    /**
+     * Whether split shade, the combined notifications and quick settings shade used for large
+     * screens, is enabled.
+     */
+    val splitShadeEnabled: Flow<Boolean> =
+        sharedNotificationContainerInteractor.configurationBasedDimensions
+            .map { dimens -> dimens.useSplitShade }
+            .distinctUntilChanged()
+
     /** The amount [0-1] that the shade has been opened */
     val shadeExpansion: Flow<Float> =
-        combine(repository.shadeExpansion, keyguardRepository.statusBarState) {
-            shadeExpansion,
-            statusBarState ->
-            // This is required, as shadeExpansion gets reset to 0f even with the shade open
-            if (statusBarState == StatusBarState.SHADE_LOCKED) {
-                1f
-            } else {
-                shadeExpansion
+        combine(
+            repository.lockscreenShadeExpansion,
+            keyguardRepository.statusBarState,
+            repository.legacyShadeExpansion,
+            repository.qsExpansion,
+            splitShadeEnabled
+        ) { dragDownAmount, statusBarState, legacyShadeExpansion, qsExpansion, splitShadeEnabled ->
+            when (statusBarState) {
+                // legacyShadeExpansion is 1 instead of 0 when QS is expanded
+                StatusBarState.SHADE ->
+                    if (!splitShadeEnabled && qsExpansion > 0f) 0f else legacyShadeExpansion
+                StatusBarState.KEYGUARD -> dragDownAmount
+                // This is required, as shadeExpansion gets reset to 0f even with the shade open
+                StatusBarState.SHADE_LOCKED -> 1f
             }
         }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
index f004982..73bbbca 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/LockscreenShadeTransitionController.kt
@@ -447,7 +447,7 @@
                 if (!nsslController.isInLockedDownShade() || field == 0f || forceApplyAmount) {
                     fractionToShade =
                         MathUtils.saturate(dragDownAmount / notificationShelfTransitionDistance)
-                    shadeRepository.setShadeExpansion(fractionToShade)
+                    shadeRepository.setLockscreenShadeExpansion(fractionToShade)
                     nsslController.setTransitionToFullShadeAmount(fractionToShade)
 
                     qsTransitionController.dragDownAmount = value
@@ -857,12 +857,12 @@
             MotionEvent.ACTION_MOVE -> {
                 val h = y - initialTouchY
                 // Adjust the touch slop if another gesture may be being performed.
-                val touchSlop = if (event.classification
-                    == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE) {
-                    touchSlop * slopMultiplier
-                } else {
-                    touchSlop
-                }
+                val touchSlop =
+                    if (event.classification == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE) {
+                        touchSlop * slopMultiplier
+                    } else {
+                        touchSlop
+                    }
                 if (h > touchSlop && h > Math.abs(x - initialTouchX)) {
                     isDraggingDown = true
                     captureStartingChild(initialTouchX, initialTouchY)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
index c573ac63..1c9ec27 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -626,6 +626,7 @@
                 mScreenOffAnimationController,
                 mLockscreenGestureLogger,
                 mShadeExpansionStateManager,
+                mShadeRepository,
                 mSysUIUnfoldComponent,
                 mSysUiState,
                 () -> mKeyguardBottomAreaViewController,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
index ab0ae05..e42a7a6 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerBaseTest.java
@@ -37,6 +37,7 @@
 import com.android.keyguard.TestScopeProvider;
 import com.android.systemui.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.flags.FeatureFlags;
 import com.android.systemui.fragments.FragmentHostManager;
@@ -61,6 +62,7 @@
 import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository;
 import com.android.systemui.statusbar.notification.stack.AmbientState;
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController;
+import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor;
 import com.android.systemui.statusbar.phone.KeyguardBottomAreaView;
 import com.android.systemui.statusbar.phone.KeyguardBypassController;
 import com.android.systemui.statusbar.phone.KeyguardStatusBarView;
@@ -174,6 +176,9 @@
                         new FakeUserSetupRepository(),
                         mDeviceProvisionedController,
                         mUserInteractor,
+                        new SharedNotificationContainerInteractor(
+                                new FakeConfigurationRepository(),
+                                mContext),
                         mShadeRepository
                 );
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
index e6e7482..41ea5b7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeInteractorTest.kt
@@ -25,7 +25,9 @@
 import androidx.test.filters.SmallTest
 import com.android.internal.logging.UiEventLogger
 import com.android.keyguard.KeyguardUpdateMonitor
+import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
 import com.android.systemui.coroutines.collectLastValue
 import com.android.systemui.flags.FakeFeatureFlags
 import com.android.systemui.flags.Flags
@@ -36,6 +38,7 @@
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.statusbar.disableflags.data.model.DisableFlagsModel
 import com.android.systemui.statusbar.disableflags.data.repository.FakeDisableFlagsRepository
+import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
 import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeUserSetupRepository
 import com.android.systemui.statusbar.policy.DeviceProvisionedController
 import com.android.systemui.telephony.data.repository.FakeTelephonyRepository
@@ -52,6 +55,7 @@
 import kotlinx.coroutines.runBlocking
 import kotlinx.coroutines.test.StandardTestDispatcher
 import kotlinx.coroutines.test.TestScope
+import kotlinx.coroutines.test.runCurrent
 import kotlinx.coroutines.test.runTest
 import org.junit.Before
 import org.junit.Test
@@ -71,6 +75,12 @@
     private val disableFlagsRepository = FakeDisableFlagsRepository()
     private val keyguardRepository = FakeKeyguardRepository()
     private val shadeRepository = FakeShadeRepository()
+    private val configurationRepository = FakeConfigurationRepository()
+    private val sharedNotificationContainerInteractor =
+        SharedNotificationContainerInteractor(
+            configurationRepository,
+            mContext,
+        )
 
     @Mock private lateinit var manager: UserManager
     @Mock private lateinit var headlessSystemUserMode: HeadlessSystemUserMode
@@ -145,6 +155,7 @@
                 userSetupRepository,
                 deviceProvisionedController,
                 userInteractor,
+                sharedNotificationContainerInteractor,
                 shadeRepository,
             )
     }
@@ -363,7 +374,7 @@
             val actual by collectLastValue(underTest.shadeExpansion)
 
             keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
-            shadeRepository.setShadeExpansion(0.5f)
+            shadeRepository.setLockscreenShadeExpansion(0.5f)
 
             assertThat(actual).isEqualTo(1f)
         }
@@ -375,10 +386,52 @@
 
             keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
 
-            shadeRepository.setShadeExpansion(0.5f)
+            shadeRepository.setLockscreenShadeExpansion(0.5f)
             assertThat(actual).isEqualTo(0.5f)
 
-            shadeRepository.setShadeExpansion(0.8f)
+            shadeRepository.setLockscreenShadeExpansion(0.8f)
             assertThat(actual).isEqualTo(0.8f)
         }
+
+    fun shadeExpansionWhenInSplitShadeAndQsExpanded() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.shadeExpansion)
+
+            // WHEN split shade is enabled and QS is expanded
+            keyguardRepository.setStatusBarState(StatusBarState.SHADE)
+            overrideResource(R.bool.config_use_split_notification_shade, true)
+            configurationRepository.onAnyConfigurationChange()
+            runCurrent()
+            shadeRepository.setQsExpansion(.5f)
+            shadeRepository.setLegacyShadeExpansion(.7f)
+
+            // THEN legacy shade expansion is passed through
+            assertThat(actual).isEqualTo(.7f)
+        }
+
+    fun shadeExpansionWhenNotInSplitShadeAndQsExpanded() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.shadeExpansion)
+
+            // WHEN split shade is not enabled and QS is expanded
+            keyguardRepository.setStatusBarState(StatusBarState.SHADE)
+            shadeRepository.setQsExpansion(.5f)
+            shadeRepository.setLegacyShadeExpansion(1f)
+
+            // THEN shade expansion is zero
+            assertThat(actual).isEqualTo(0f)
+        }
+
+    fun shadeExpansionWhenNotInSplitShadeAndQsCollapsed() =
+        testScope.runTest {
+            val actual by collectLastValue(underTest.shadeExpansion)
+
+            // WHEN split shade is not enabled and QS is expanded
+            keyguardRepository.setStatusBarState(StatusBarState.SHADE)
+            shadeRepository.setQsExpansion(0f)
+            shadeRepository.setLegacyShadeExpansion(.6f)
+
+            // THEN shade expansion is zero
+            assertThat(actual).isEqualTo(.6f)
+        }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
index fdaea22..e086712 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/data/repository/ShadeRepositoryImplTest.kt
@@ -121,18 +121,33 @@
         }
 
     @Test
-    fun updateShadeExpansion() =
+    fun updateDragDownAmount() =
         testScope.runTest {
-            assertThat(underTest.shadeExpansion.value).isEqualTo(0f)
+            assertThat(underTest.lockscreenShadeExpansion.value).isEqualTo(0f)
 
-            underTest.setShadeExpansion(.5f)
-            assertThat(underTest.shadeExpansion.value).isEqualTo(.5f)
+            underTest.setLockscreenShadeExpansion(.5f)
+            assertThat(underTest.lockscreenShadeExpansion.value).isEqualTo(.5f)
 
-            underTest.setShadeExpansion(.82f)
-            assertThat(underTest.shadeExpansion.value).isEqualTo(.82f)
+            underTest.setLockscreenShadeExpansion(.82f)
+            assertThat(underTest.lockscreenShadeExpansion.value).isEqualTo(.82f)
 
-            underTest.setShadeExpansion(1f)
-            assertThat(underTest.shadeExpansion.value).isEqualTo(1f)
+            underTest.setLockscreenShadeExpansion(1f)
+            assertThat(underTest.lockscreenShadeExpansion.value).isEqualTo(1f)
+        }
+
+    @Test
+    fun updateLegacyShadeExpansion() =
+        testScope.runTest {
+            assertThat(underTest.legacyShadeExpansion.value).isEqualTo(0f)
+
+            underTest.setLegacyShadeExpansion(.5f)
+            assertThat(underTest.legacyShadeExpansion.value).isEqualTo(.5f)
+
+            underTest.setLegacyShadeExpansion(.82f)
+            assertThat(underTest.legacyShadeExpansion.value).isEqualTo(.82f)
+
+            underTest.setLegacyShadeExpansion(1f)
+            assertThat(underTest.legacyShadeExpansion.value).isEqualTo(1f)
         }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
index 51e72c6..6f75880 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/LockscreenShadeTransitionControllerTest.kt
@@ -10,6 +10,7 @@
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollector
 import com.android.systemui.classifier.FalsingCollectorFake
+import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.keyguard.WakefulnessLifecycle
 import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
@@ -29,6 +30,7 @@
 import com.android.systemui.statusbar.notification.stack.AmbientState
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayout
 import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.phone.KeyguardBypassController
 import com.android.systemui.statusbar.phone.LSShadeTransitionLogger
@@ -102,6 +104,11 @@
     @Mock lateinit var transitionControllerCallback: LockscreenShadeTransitionController.Callback
     private val disableFlagsRepository = FakeDisableFlagsRepository()
     private val keyguardRepository = FakeKeyguardRepository()
+    private val configurationRepository = FakeConfigurationRepository()
+    private val sharedNotificationContainerInteractor = SharedNotificationContainerInteractor(
+        configurationRepository,
+        mContext,
+    )
     private val shadeInteractor =
         ShadeInteractor(
             testScope.backgroundScope,
@@ -110,6 +117,7 @@
             userSetupRepository = FakeUserSetupRepository(),
             deviceProvisionedController = mock(),
             userInteractor = mock(),
+            sharedNotificationContainerInteractor,
             repository = FakeShadeRepository(),
         )
     private val powerInteractor =
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 55b52dc..75fb22d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -30,6 +30,7 @@
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
 import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractorFactory
 import com.android.systemui.keyguard.shared.model.KeyguardState
+import com.android.systemui.keyguard.shared.model.StatusBarState
 import com.android.systemui.keyguard.shared.model.TransitionState
 import com.android.systemui.keyguard.shared.model.TransitionStep
 import com.android.systemui.shade.data.repository.FakeShadeRepository
@@ -97,7 +98,11 @@
                 keyguardTransitionInteractor = it.keyguardTransitionInteractor
                 keyguardTransitionRepository = it.repository
             }
-
+        sharedNotificationContainerInteractor =
+            SharedNotificationContainerInteractor(
+                configurationRepository,
+                mContext,
+            )
         shadeInteractor =
             ShadeInteractor(
                 testScope.backgroundScope,
@@ -106,14 +111,9 @@
                 userSetupRepository,
                 deviceProvisionedController,
                 userInteractor,
+                sharedNotificationContainerInteractor,
                 shadeRepository,
             )
-
-        sharedNotificationContainerInteractor =
-            SharedNotificationContainerInteractor(
-                configurationRepository,
-                mContext,
-            )
         underTest =
             SharedNotificationContainerViewModel(
                 sharedNotificationContainerInteractor,
@@ -228,7 +228,7 @@
             val isOnLockscreenWithoutShade by collectLastValue(underTest.isOnLockscreenWithoutShade)
 
             // First on AOD
-            shadeRepository.setShadeExpansion(0f)
+            shadeRepository.setLockscreenShadeExpansion(0f)
             shadeRepository.setQsExpansion(0f)
             keyguardTransitionRepository.sendTransitionStep(
                 TransitionStep(
@@ -242,19 +242,19 @@
             showLockscreen()
 
             // While state is LOCKSCREEN, validate variations of both shade and qs expansion
-            shadeRepository.setShadeExpansion(0.1f)
+            shadeRepository.setLockscreenShadeExpansion(0.1f)
             shadeRepository.setQsExpansion(0f)
             assertThat(isOnLockscreenWithoutShade).isFalse()
 
-            shadeRepository.setShadeExpansion(0.1f)
+            shadeRepository.setLockscreenShadeExpansion(0.1f)
             shadeRepository.setQsExpansion(0.1f)
             assertThat(isOnLockscreenWithoutShade).isFalse()
 
-            shadeRepository.setShadeExpansion(0f)
+            shadeRepository.setLockscreenShadeExpansion(0f)
             shadeRepository.setQsExpansion(0.1f)
             assertThat(isOnLockscreenWithoutShade).isFalse()
 
-            shadeRepository.setShadeExpansion(0f)
+            shadeRepository.setLockscreenShadeExpansion(0f)
             shadeRepository.setQsExpansion(0f)
             assertThat(isOnLockscreenWithoutShade).isTrue()
         }
@@ -366,8 +366,9 @@
         }
 
     private suspend fun showLockscreen() {
-        shadeRepository.setShadeExpansion(0f)
+        shadeRepository.setLockscreenShadeExpansion(0f)
         shadeRepository.setQsExpansion(0f)
+        keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
         keyguardTransitionRepository.sendTransitionStep(
             TransitionStep(
                 to = KeyguardState.LOCKSCREEN,
@@ -377,8 +378,9 @@
     }
 
     private suspend fun showLockscreenWithShadeExpanded() {
-        shadeRepository.setShadeExpansion(1f)
+        shadeRepository.setLockscreenShadeExpansion(1f)
         shadeRepository.setQsExpansion(0f)
+        keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
         keyguardTransitionRepository.sendTransitionStep(
             TransitionStep(
                 to = KeyguardState.LOCKSCREEN,
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
index ccddca2..08152a3 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/data/repository/FakeShadeRepository.kt
@@ -33,8 +33,12 @@
     private val _udfpsTransitionToFullShadeProgress = MutableStateFlow(0f)
     override val udfpsTransitionToFullShadeProgress = _udfpsTransitionToFullShadeProgress
 
-    private val _shadeExpansion = MutableStateFlow(0f)
-    override val shadeExpansion = _shadeExpansion
+    private val _lockscreenShadeExpansion = MutableStateFlow(0f)
+    override val lockscreenShadeExpansion = _lockscreenShadeExpansion
+
+    private val _legacyShadeExpansion = MutableStateFlow(0f)
+    @Deprecated("Use ShadeInteractor instead")
+    override val legacyShadeExpansion = _legacyShadeExpansion
 
     fun setShadeModel(model: ShadeModel) {
         _shadeModel.value = model
@@ -48,7 +52,12 @@
         _udfpsTransitionToFullShadeProgress.value = progress
     }
 
-    override fun setShadeExpansion(expansion: Float) {
-        _shadeExpansion.value = expansion
+    override fun setLockscreenShadeExpansion(lockscreenShadeExpansion: Float) {
+        _lockscreenShadeExpansion.value = lockscreenShadeExpansion
+    }
+
+    @Deprecated("Should only be called by NPVC and tests")
+    override fun setLegacyShadeExpansion(expandedFraction: Float) {
+        _legacyShadeExpansion.value = expandedFraction
     }
 }
diff --git a/services/core/java/com/android/server/notification/flags.aconfig b/services/core/java/com/android/server/notification/flags.aconfig
index 1908e4d..dcac8c9 100644
--- a/services/core/java/com/android/server/notification/flags.aconfig
+++ b/services/core/java/com/android/server/notification/flags.aconfig
@@ -13,3 +13,10 @@
   description: "This flag controls the polite notification feature"
   bug: "270456865"
 }
+
+flag {
+  name: "refactor_attention_helper"
+  namespace: "systemui"
+  description: "This flag controls the refactoring of NMS to NotificationAttentionHelper"
+  bug: "291907312"
+}
diff --git a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java
index 06033c7..3fcec96 100644
--- a/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/LetterboxConfigurationPersisterTest.java
@@ -184,7 +184,7 @@
                 LETTERBOX_HORIZONTAL_REACHABILITY_POSITION_LEFT);
         firstPersister.setLetterboxPositionForVerticalReachability(false,
                 LETTERBOX_VERTICAL_REACHABILITY_POSITION_TOP);
-        waitForCompletion(mPersisterQueue);
+        waitForCompletion(firstPersisterQueue);
         final int newPositionForHorizontalReachability =
                 firstPersister.getLetterboxPositionForHorizontalReachability(false);
         final int newPositionForVerticalReachability =