[flexiglass] Allow dual notification shade to align to the bottom.

This allows NotificationsShadeScene to be customized such that instead
of align to the top, it is now align to the bottom (positioning to the
right side remains unchanged).

This also adds a new transition to the framework so that when it is on
the bottom, the scene appears from the bottom edge rather than the top.

Flag: com.android.systemui.scene_container
Bug: 343744476
Test: Manual; Change config.xml content to be true instead, and then
call on adb shell service call statusbar 1 to see animation
Test: Manual; verify on Goldfish phone emulator with flexiglass on flag
off still works

Change-Id: Id44ad8ca9be2a9d2b35caed657589eebe164160c
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
index f62a28c..899b256 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeScene.kt
@@ -20,7 +20,6 @@
 import androidx.compose.foundation.layout.fillMaxWidth
 import androidx.compose.foundation.layout.padding
 import androidx.compose.runtime.Composable
-import androidx.compose.ui.Alignment
 import androidx.compose.ui.Modifier
 import androidx.compose.ui.unit.dp
 import com.android.compose.animation.scene.SceneScope
@@ -75,7 +74,6 @@
         OverlayShade(
             modifier = modifier,
             viewModel = overlayShadeViewModel,
-            panelAlignment = Alignment.TopEnd,
             lockscreenContent = lockscreenContent,
         ) {
             Column {
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
index a0d6be9..4914aea 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeScene.kt
@@ -82,7 +82,6 @@
     ) {
         OverlayShade(
             viewModel = viewModel.overlayShadeViewModel,
-            panelAlignment = Alignment.TopEnd,
             lockscreenContent = lockscreenContent,
             modifier = modifier,
         ) {
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 68395b4..03e5249 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
@@ -1,10 +1,12 @@
 package com.android.systemui.scene.ui.composable
 
 import androidx.compose.foundation.gestures.Orientation
+import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.transitions
 import com.android.systemui.bouncer.ui.composable.Bouncer
 import com.android.systemui.notifications.ui.composable.Notifications
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.TransitionKeys.OpenBottomShade
 import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
 import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
 import com.android.systemui.scene.ui.composable.transitions.bouncerToGoneTransition
@@ -42,7 +44,12 @@
     // Scene transitions
 
     from(Scenes.Bouncer, to = Scenes.Gone) { bouncerToGoneTransition() }
-    from(Scenes.Gone, to = Scenes.NotificationsShade) { goneToNotificationsShadeTransition() }
+    from(Scenes.Gone, to = Scenes.NotificationsShade) {
+        goneToNotificationsShadeTransition(Edge.Top)
+    }
+    from(Scenes.Gone, to = Scenes.NotificationsShade, key = OpenBottomShade) {
+        goneToNotificationsShadeTransition(Edge.Bottom)
+    }
     from(Scenes.Gone, to = Scenes.Shade) { goneToShadeTransition() }
     from(
         Scenes.Gone,
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
index 48ec198..fb41374 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToNotificationsShadeTransition.kt
@@ -16,10 +16,12 @@
 
 package com.android.systemui.scene.ui.composable.transitions
 
+import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.TransitionBuilder
 
 fun TransitionBuilder.goneToNotificationsShadeTransition(
+    edge: Edge = Edge.Top,
     durationScale: Double = 1.0,
 ) {
-    toNotificationsShadeTransition(durationScale)
+    toNotificationsShadeTransition(edge, durationScale)
 }
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt
index 372e4a1a..02664c1 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToNotificationsShadeTransition.kt
@@ -21,5 +21,5 @@
 fun TransitionBuilder.lockscreenToNotificationsShadeTransition(
     durationScale: Double = 1.0,
 ) {
-    toNotificationsShadeTransition(durationScale)
+    toNotificationsShadeTransition(durationScale = durationScale)
 }
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 6b3b760..05949b2 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
@@ -32,6 +32,11 @@
 import kotlin.time.Duration.Companion.milliseconds
 
 fun TransitionBuilder.toNotificationsShadeTransition(
+    /**
+     * The edge where the shade will animate from. This is statically determined (i.e. doesn't
+     * change during runtime).
+     */
+    edge: Edge = Edge.Top,
     durationScale: Double = 1.0,
 ) {
     spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
@@ -50,7 +55,7 @@
             }
         }
 
-    translate(OverlayShade.Elements.Panel, Edge.Top)
+    translate(OverlayShade.Elements.Panel, edge)
 
     fractionRange(end = .5f) { fade(OverlayShade.Elements.Scrim) }
 
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 c189d73..a94ebc8 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
@@ -54,6 +54,7 @@
 import com.android.compose.windowsizeclass.LocalWindowSizeClass
 import com.android.systemui.keyguard.ui.composable.LockscreenContent
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.shared.model.ShadeAlignment
 import com.android.systemui.shade.ui.viewmodel.OverlayShadeViewModel
 import com.android.systemui.util.kotlin.getOrNull
 import dagger.Lazy
@@ -63,7 +64,6 @@
 @Composable
 fun SceneScope.OverlayShade(
     viewModel: OverlayShadeViewModel,
-    panelAlignment: Alignment,
     lockscreenContent: Lazy<Optional<LockscreenContent>>,
     modifier: Modifier = Modifier,
     content: @Composable () -> Unit,
@@ -82,7 +82,12 @@
 
         Box(
             modifier = Modifier.fillMaxSize().panelPadding(),
-            contentAlignment = panelAlignment,
+            contentAlignment =
+                if (viewModel.panelAlignment == ShadeAlignment.Top) {
+                    Alignment.TopEnd
+                } else {
+                    Alignment.BottomEnd
+                },
         ) {
             Panel(
                 modifier = Modifier.element(OverlayShade.Elements.Panel).panelSize(),
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index f8762f0..4ef9442 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -1049,4 +1049,7 @@
 
     <!-- The width of the shortcut helper container, as a fraction of the screen's width. -->
     <item name="shortcut_helper_screen_width_fraction" format="float" type="dimen">1.0</item>
+
+    <!-- Only applicable for dual shade - Allow Notifications/QS shade to anchor to the bottom. -->
+    <bool name="config_dualShadeAlignedToBottom">false</bool>
 </resources>
diff --git a/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt b/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt
index ef393e4..be95441 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/shared/model/TransitionKeys.kt
@@ -31,6 +31,11 @@
     val CollapseShadeInstantly = TransitionKey("CollapseShadeInstantly")
 
     /**
+     * Reference to a scene transition that brings up the shade from the bottom instead of the top.
+     */
+    val OpenBottomShade = TransitionKey("OpenBottomShade")
+
+    /**
      * Reference to a scene transition that can collapse the shade scene slightly faster than a
      * normal collapse would.
      */
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
index c34a6cd..ac91337 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/viewmodel/GoneSceneViewModel.kt
@@ -16,6 +16,7 @@
 
 package com.android.systemui.scene.ui.viewmodel
 
+import androidx.compose.ui.Alignment
 import com.android.compose.animation.scene.Edge
 import com.android.compose.animation.scene.Swipe
 import com.android.compose.animation.scene.SwipeDirection
@@ -24,6 +25,7 @@
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Application
 import com.android.systemui.scene.shared.model.SceneFamilies
+import com.android.systemui.scene.shared.model.TransitionKeys.OpenBottomShade
 import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import com.android.systemui.shade.shared.model.ShadeMode
@@ -39,7 +41,7 @@
 @Inject
 constructor(
     @Application private val applicationScope: CoroutineScope,
-    shadeInteractor: ShadeInteractor,
+    private val shadeInteractor: ShadeInteractor,
 ) {
     val destinationScenes: StateFlow<Map<UserAction, UserActionResult>> =
         shadeInteractor.shadeMode
@@ -72,13 +74,17 @@
                 )
             }
 
-            put(
-                Swipe(direction = SwipeDirection.Down),
-                UserActionResult(
-                    SceneFamilies.NotifShade,
-                    ToSplitShade.takeIf { shadeMode is ShadeMode.Split }
+            if (shadeInteractor.shadeAlignment == Alignment.BottomEnd) {
+                put(Swipe.Up, UserActionResult(SceneFamilies.NotifShade, OpenBottomShade))
+            } else {
+                put(
+                    Swipe.Down,
+                    UserActionResult(
+                        SceneFamilies.NotifShade,
+                        ToSplitShade.takeIf { shadeMode is ShadeMode.Split }
+                    )
                 )
-            )
+            }
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
index 004db16..ee8161c 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeControllerSceneImpl.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.shade
 
 import android.view.MotionEvent
+import androidx.compose.ui.Alignment
 import com.android.systemui.assist.AssistManager
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Background
@@ -24,6 +25,7 @@
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.model.SceneFamilies
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.scene.shared.model.TransitionKeys.OpenBottomShade
 import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
 import com.android.systemui.shade.ShadeController.ShadeVisibilityListener
 import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -175,6 +177,7 @@
         sceneInteractor.changeScene(
             SceneFamilies.NotifShade,
             "ShadeController.animateExpandShade",
+            OpenBottomShade.takeIf { shadeInteractor.shadeAlignment == Alignment.BottomEnd }
         )
     }
 
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 7e1a310..4d43ad5 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
@@ -15,7 +15,10 @@
  */
 package com.android.systemui.shade.data.repository
 
+import android.content.Context
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.res.R
 import com.android.systemui.shade.shared.flag.DualShade
 import com.android.systemui.shade.shared.model.ShadeMode
 import javax.inject.Inject
@@ -104,6 +107,9 @@
 
     val shadeMode: StateFlow<ShadeMode>
 
+    /** Whether dual shade should be aligned to the bottom (true) or to the top (false). */
+    val isDualShadeAlignedToBottom: Boolean
+
     /** True when QS is taking up the entire screen, i.e. fully expanded on a non-unfolded phone. */
     @Deprecated("Use ShadeInteractor instead") val legacyQsFullscreen: StateFlow<Boolean>
 
@@ -174,7 +180,8 @@
 
 /** Business logic for shade interactions */
 @SysUISingleton
-class ShadeRepositoryImpl @Inject constructor() : ShadeRepository {
+class ShadeRepositoryImpl @Inject constructor(@Application applicationContext: Context) :
+    ShadeRepository {
     private val _qsExpansion = MutableStateFlow(0f)
     override val qsExpansion: StateFlow<Float> = _qsExpansion.asStateFlow()
 
@@ -223,6 +230,9 @@
     val _shadeMode = MutableStateFlow(if (DualShade.isEnabled) ShadeMode.Dual else ShadeMode.Single)
     override val shadeMode: StateFlow<ShadeMode> = _shadeMode.asStateFlow()
 
+    override val isDualShadeAlignedToBottom =
+        applicationContext.resources.getBoolean(R.bool.config_dualShadeAlignedToBottom)
+
     override fun setShadeMode(shadeMode: ShadeMode) {
         _shadeMode.value = shadeMode
     }
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 18407cc..ef0a842 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
@@ -16,6 +16,7 @@
 
 package com.android.systemui.shade.domain.interactor
 
+import com.android.systemui.shade.shared.model.ShadeAlignment
 import com.android.systemui.shade.shared.model.ShadeMode
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.Flow
@@ -53,6 +54,9 @@
 
     /** Emits true if the shade can be expanded from QQS to QS and false otherwise. */
     val isExpandToQsEnabled: Flow<Boolean>
+
+    /** How to align the shade content. */
+    val shadeAlignment: ShadeAlignment
 }
 
 /** ShadeInteractor methods with implementations that differ between non-empty impls. */
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
index bb4baa3..6226d07 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
@@ -17,6 +17,7 @@
 package com.android.systemui.shade.domain.interactor
 
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shade.shared.model.ShadeAlignment
 import com.android.systemui.shade.shared.model.ShadeMode
 import javax.inject.Inject
 import kotlinx.coroutines.flow.Flow
@@ -46,4 +47,5 @@
     override val isShadeTouchable: Flow<Boolean> = inactiveFlowBoolean
     override val isExpandToQsEnabled: Flow<Boolean> = inactiveFlowBoolean
     override val shadeMode: StateFlow<ShadeMode> = MutableStateFlow(ShadeMode.Single)
+    override val shadeAlignment: ShadeAlignment = ShadeAlignment.Top
 }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
index 4014512..55f019b 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorImpl.kt
@@ -24,6 +24,8 @@
 import com.android.systemui.keyguard.shared.model.Edge
 import com.android.systemui.keyguard.shared.model.KeyguardState
 import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.shade.data.repository.ShadeRepository
+import com.android.systemui.shade.shared.model.ShadeAlignment
 import com.android.systemui.statusbar.disableflags.data.repository.DisableFlagsRepository
 import com.android.systemui.statusbar.phone.DozeParameters
 import com.android.systemui.statusbar.policy.data.repository.UserSetupRepository
@@ -51,6 +53,7 @@
     keyguardRepository: KeyguardRepository,
     keyguardTransitionInteractor: KeyguardTransitionInteractor,
     powerInteractor: PowerInteractor,
+    shadeRepository: ShadeRepository,
     userSetupRepository: UserSetupRepository,
     userSwitcherInteractor: UserSwitcherInteractor,
     private val baseShadeInteractor: BaseShadeInteractor,
@@ -99,6 +102,13 @@
             }
         }
 
+    override val shadeAlignment: ShadeAlignment =
+        if (shadeRepository.isDualShadeAlignedToBottom) {
+            ShadeAlignment.Bottom
+        } else {
+            ShadeAlignment.Top
+        }
+
     override val isExpandToQsEnabled: Flow<Boolean> =
         combine(
             disableFlagsRepository.disableFlags,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeAlignment.kt b/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeAlignment.kt
new file mode 100644
index 0000000..06905379
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/shade/shared/model/ShadeAlignment.kt
@@ -0,0 +1,27 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.shade.shared.model
+
+/** Enumerates all supported alignments of the shade. */
+sealed interface ShadeAlignment {
+
+    /** Aligns the shade to the top. */
+    data object Top : ShadeAlignment
+
+    /** Aligns the shade to the bottom. */
+    data object Bottom : ShadeAlignment
+}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt
index 0314091..b946129 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModel.kt
@@ -22,6 +22,7 @@
 import com.android.systemui.scene.domain.interactor.SceneInteractor
 import com.android.systemui.scene.shared.model.SceneFamilies
 import com.android.systemui.scene.shared.model.Scenes
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
 import javax.inject.Inject
 import kotlinx.coroutines.CoroutineScope
 import kotlinx.coroutines.flow.SharingStarted
@@ -38,6 +39,7 @@
 constructor(
     @Application applicationScope: CoroutineScope,
     private val sceneInteractor: SceneInteractor,
+    shadeInteractor: ShadeInteractor
 ) {
     /** The scene to show in the background when the overlay shade is open. */
     val backgroundScene: StateFlow<SceneKey> =
@@ -49,6 +51,9 @@
                 initialValue = Scenes.Lockscreen,
             )
 
+    /** Dictates whether the panel is aligned to the top or the bottom. */
+    val panelAlignment = shadeInteractor.shadeAlignment
+
     /** Notifies that the user has clicked the semi-transparent background scrim. */
     fun onScrimClicked() {
         sceneInteractor.changeScene(
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 c3cedf8..88b832d 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerBaseTest.java
@@ -438,6 +438,7 @@
                 mFakeKeyguardRepository,
                 mKeyguardTransitionInteractor,
                 mPowerInteractor,
+                mShadeRepository,
                 new FakeUserSetupRepository(),
                 mock(UserSwitcherInteractor.class),
                 new ShadeInteractorLegacyImpl(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
index 85541aa..06a883c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/QuickSettingsControllerImplBaseTest.java
@@ -218,6 +218,7 @@
                 mKeyguardRepository,
                 keyguardTransitionInteractor,
                 powerInteractor,
+                mShadeRepository,
                 new FakeUserSetupRepository(),
                 mUserSwitcherInteractor,
                 new ShadeInteractorLegacyImpl(
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 750693c..97acc6e 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
@@ -40,7 +40,7 @@
 
     @Before
     fun setUp() {
-        underTest = ShadeRepositoryImpl()
+        underTest = ShadeRepositoryImpl(getContext())
     }
 
     @Test
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 728c67a..4813794 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
@@ -64,6 +64,8 @@
     private val _shadeMode = MutableStateFlow<ShadeMode>(ShadeMode.Single)
     override val shadeMode: StateFlow<ShadeMode> = _shadeMode.asStateFlow()
 
+    override val isDualShadeAlignedToBottom = false
+
     @Deprecated("Use ShadeInteractor instead")
     override fun setLegacyIsQsExpanded(legacyIsQsExpanded: Boolean) {
         _legacyIsQsExpanded.value = legacyIsQsExpanded
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
index 543d5b6..a00d2f4 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/domain/interactor/ShadeInteractorKosmos.kt
@@ -71,5 +71,6 @@
             userSetupRepository = userSetupRepository,
             userSwitcherInteractor = userSwitcherInteractor,
             baseShadeInteractor = baseShadeInteractor,
+            shadeRepository = shadeRepository,
         )
     }
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModelKosmos.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModelKosmos.kt
index fec1028..8d4d547 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModelKosmos.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/shade/ui/viewmodel/OverlayShadeViewModelKosmos.kt
@@ -19,11 +19,13 @@
 import com.android.systemui.kosmos.Kosmos
 import com.android.systemui.kosmos.applicationCoroutineScope
 import com.android.systemui.scene.domain.interactor.sceneInteractor
+import com.android.systemui.shade.domain.interactor.shadeInteractor
 
 val Kosmos.overlayShadeViewModel: OverlayShadeViewModel by
     Kosmos.Fixture {
         OverlayShadeViewModel(
             applicationScope = applicationCoroutineScope,
             sceneInteractor = sceneInteractor,
+            shadeInteractor = shadeInteractor,
         )
     }