summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt32
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt193
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt90
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt18
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt2
-rw-r--r--packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt18
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt9
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt8
-rw-r--r--packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt3
-rw-r--r--packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt2
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt1
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootView.kt6
-rw-r--r--packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt12
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt4
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationStackAppearanceRepository.kt30
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt43
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/SceneContainerFlagsExtension.kt27
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackAppearanceViewBinder.kt59
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt13
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt41
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt53
-rw-r--r--packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt58
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt2
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt3
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt1
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt15
-rw-r--r--packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt18
35 files changed, 690 insertions, 114 deletions
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
index ee310ab41373..cc95a4b72731 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/LockscreenScene.kt
@@ -33,6 +33,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.geometry.Rect
import androidx.compose.ui.graphics.toComposeRect
import androidx.compose.ui.input.pointer.pointerInput
+import androidx.compose.ui.layout.Layout
import androidx.compose.ui.viewinterop.AndroidView
import androidx.core.view.isVisible
import com.android.compose.animation.scene.SceneScope
@@ -41,6 +42,7 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.qualifiers.KeyguardRootView
import com.android.systemui.keyguard.ui.viewmodel.KeyguardLongPressViewModel
import com.android.systemui.keyguard.ui.viewmodel.LockscreenSceneViewModel
+import com.android.systemui.notifications.ui.composable.NotificationStack
import com.android.systemui.res.R
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.Edge
@@ -88,7 +90,7 @@ constructor(
) {
LockscreenScene(
viewProvider = viewProvider,
- longPressViewModel = viewModel.longPress,
+ viewModel = viewModel,
modifier = modifier,
)
}
@@ -108,9 +110,9 @@ constructor(
}
@Composable
-private fun LockscreenScene(
+private fun SceneScope.LockscreenScene(
viewProvider: () -> View,
- longPressViewModel: KeyguardLongPressViewModel,
+ viewModel: LockscreenSceneViewModel,
modifier: Modifier = Modifier,
) {
fun findSettingsMenu(): View {
@@ -121,7 +123,7 @@ private fun LockscreenScene(
modifier = modifier,
) {
LongPressSurface(
- viewModel = longPressViewModel,
+ viewModel = viewModel.longPress,
isSettingsMenuVisible = { findSettingsMenu().isVisible },
settingsMenuBounds = {
val bounds = android.graphics.Rect()
@@ -141,6 +143,28 @@ private fun LockscreenScene(
},
modifier = Modifier.fillMaxSize(),
)
+
+ val notificationStackPosition by
+ viewModel.keyguardRoot.notificationPositionOnLockscreen.collectAsState()
+
+ Layout(
+ modifier = Modifier.fillMaxSize(),
+ content = {
+ NotificationStack(
+ viewModel = viewModel.notifications,
+ isScrimVisible = false,
+ )
+ }
+ ) { measurables, constraints ->
+ check(measurables.size == 1)
+ val height = notificationStackPosition.height.toInt()
+ val childConstraints = constraints.copy(minHeight = height, maxHeight = height)
+ val placeable = measurables[0].measure(childConstraints)
+ layout(constraints.maxWidth, constraints.maxHeight) {
+ val start = (constraints.maxWidth - placeable.measuredWidth) / 2
+ placeable.placeRelative(x = start, y = notificationStackPosition.top.toInt())
+ }
+ }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
index dd71dfa0b008..c9d31fdcb8e5 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt
@@ -17,56 +17,197 @@
package com.android.systemui.notifications.ui.composable
+import android.util.Log
import androidx.compose.foundation.background
-import androidx.compose.foundation.layout.Column
-import androidx.compose.foundation.layout.Spacer
-import androidx.compose.foundation.layout.defaultMinSize
+import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
+import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
+import androidx.compose.ui.graphics.Color
+import androidx.compose.ui.layout.LayoutCoordinates
+import androidx.compose.ui.layout.boundsInWindow
+import androidx.compose.ui.layout.onPlaced
+import androidx.compose.ui.layout.onSizeChanged
+import androidx.compose.ui.layout.positionInWindow
+import androidx.compose.ui.unit.IntSize
import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.SceneScope
+import com.android.compose.animation.scene.ValueKey
+import com.android.compose.animation.scene.animateSharedFloatAsState
+import com.android.systemui.notifications.ui.composable.Notifications.Form
+import com.android.systemui.notifications.ui.composable.Notifications.SharedValues.SharedExpansionValue
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
object Notifications {
object Elements {
- val Notifications = ElementKey("Notifications")
+ val NotificationScrim = ElementKey("NotificationScrim")
+ val NotificationPlaceholder = ElementKey("NotificationPlaceholder")
+ val ShelfSpace = ElementKey("ShelfSpace")
+ }
+
+ object SharedValues {
+ val SharedExpansionValue = ValueKey("SharedExpansionValue")
+ }
+
+ enum class Form {
+ HunFromTop,
+ Stack,
+ HunFromBottom,
}
}
+/**
+ * Adds the space where heads up notifications can appear in the scene. This should generally be the
+ * entire size of the scene.
+ */
@Composable
-fun SceneScope.Notifications(
+fun SceneScope.HeadsUpNotificationSpace(
+ viewModel: NotificationsPlaceholderViewModel,
+ isPeekFromBottom: Boolean = false,
modifier: Modifier = Modifier,
) {
- // TODO(b/272779828): implement.
- Column(
+ NotificationPlaceholder(
+ viewModel = viewModel,
+ form = if (isPeekFromBottom) Form.HunFromBottom else Form.HunFromTop,
+ modifier = modifier,
+ )
+}
+
+/** Adds the space where notification stack will appear in the scene. */
+@Composable
+fun SceneScope.NotificationStack(
+ viewModel: NotificationsPlaceholderViewModel,
+ isScrimVisible: Boolean,
+ modifier: Modifier = Modifier,
+) {
+ Box(modifier = modifier) {
+ if (isScrimVisible) {
+ Box(
+ modifier =
+ Modifier.element(Notifications.Elements.NotificationScrim)
+ .fillMaxSize()
+ .clip(RoundedCornerShape(32.dp))
+ .background(MaterialTheme.colorScheme.surface)
+ )
+ }
+ NotificationPlaceholder(
+ viewModel = viewModel,
+ form = Form.Stack,
+ modifier = Modifier.fillMaxSize(),
+ )
+ }
+}
+
+/**
+ * This may be added to the lockscreen to provide a space to the start of the lock icon where the
+ * short shelf has room to flow vertically below the lock icon, but to its start, allowing more
+ * notifications to fit in the stack itself. (see: b/213934746)
+ *
+ * NOTE: this is totally unused for now; it is here to clarify the future plan
+ */
+@Composable
+fun SceneScope.NotificationShelfSpace(
+ viewModel: NotificationsPlaceholderViewModel,
+ modifier: Modifier = Modifier,
+) {
+ Text(
+ text = "Shelf Space",
+ modifier
+ .element(key = Notifications.Elements.ShelfSpace)
+ .fillMaxWidth()
+ .onSizeChanged { size: IntSize ->
+ debugLog(viewModel) { "SHELF onSizeChanged: size=$size" }
+ }
+ .onPlaced { coordinates: LayoutCoordinates ->
+ debugLog(viewModel) {
+ ("SHELF onPlaced:" +
+ " size=${coordinates.size}" +
+ " position=${coordinates.positionInWindow()}" +
+ " bounds=${coordinates.boundsInWindow()}")
+ }
+ }
+ .clip(RoundedCornerShape(24.dp))
+ .background(MaterialTheme.colorScheme.primaryContainer)
+ .padding(16.dp),
+ style = MaterialTheme.typography.titleLarge,
+ color = MaterialTheme.colorScheme.onPrimaryContainer,
+ )
+}
+
+@Composable
+private fun SceneScope.NotificationPlaceholder(
+ viewModel: NotificationsPlaceholderViewModel,
+ form: Form,
+ modifier: Modifier = Modifier,
+) {
+ val key = Notifications.Elements.NotificationPlaceholder
+ Box(
modifier =
modifier
- .element(key = Notifications.Elements.Notifications)
- .fillMaxWidth()
- .defaultMinSize(minHeight = 300.dp)
- .clip(RoundedCornerShape(32.dp))
- .background(MaterialTheme.colorScheme.surface)
- .padding(16.dp),
+ .element(key)
+ .debugBackground(viewModel)
+ .onSizeChanged { size: IntSize ->
+ debugLog(viewModel) { "STACK onSizeChanged: size=$size" }
+ }
+ .onPlaced { coordinates: LayoutCoordinates ->
+ debugLog(viewModel) {
+ "STACK onPlaced:" +
+ " size=${coordinates.size}" +
+ " position=${coordinates.positionInWindow()}" +
+ " bounds=${coordinates.boundsInWindow()}"
+ }
+ val boundsInWindow = coordinates.boundsInWindow()
+ viewModel.setPlaceholderPositionInWindow(
+ top = boundsInWindow.top,
+ bottom = boundsInWindow.bottom,
+ )
+ }
) {
- Text(
- text = "Notifications",
- modifier = Modifier.align(Alignment.CenterHorizontally),
- style = MaterialTheme.typography.titleLarge,
- color = MaterialTheme.colorScheme.onSurface,
- )
- Spacer(modifier = Modifier.weight(1f))
- Text(
- text = "Shelf",
- modifier = Modifier.align(Alignment.CenterHorizontally),
- style = MaterialTheme.typography.titleSmall,
- color = MaterialTheme.colorScheme.onSurface,
- )
+ val animatedExpansion by
+ animateSharedFloatAsState(
+ value = if (form == Form.HunFromTop) 0f else 1f,
+ key = SharedExpansionValue,
+ element = key
+ )
+ debugLog(viewModel) { "STACK composed: expansion=$animatedExpansion" }
+ if (viewModel.isPlaceholderTextVisible) {
+ Text(
+ text = "Notifications",
+ style = MaterialTheme.typography.titleLarge,
+ color = MaterialTheme.colorScheme.onSurface,
+ modifier = Modifier.align(Alignment.Center),
+ )
+ }
+ }
+}
+
+private inline fun debugLog(
+ viewModel: NotificationsPlaceholderViewModel,
+ msg: () -> Any,
+) {
+ if (viewModel.isDebugLoggingEnabled) {
+ Log.d(TAG, msg().toString())
}
}
+
+private fun Modifier.debugBackground(
+ viewModel: NotificationsPlaceholderViewModel,
+ color: Color = DEBUG_COLOR,
+): Modifier =
+ if (viewModel.isVisualDebuggingEnabled) {
+ background(color)
+ } else {
+ this
+ }
+
+private const val TAG = "FlexiNotifs"
+private val DEBUG_COLOR = Color(1f, 0f, 0f, 0.2f)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
index b9451d1c1585..9dd7bfaf3549 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt
@@ -24,6 +24,7 @@ import androidx.compose.animation.fadeIn
import androidx.compose.animation.fadeOut
import androidx.compose.animation.shrinkVertically
import androidx.compose.foundation.clickable
+import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
@@ -43,6 +44,7 @@ import com.android.compose.windowsizeclass.LocalWindowSizeClass
import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
+import com.android.systemui.notifications.ui.composable.HeadsUpNotificationSpace
import com.android.systemui.qs.ui.adapter.QSSceneAdapter
import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel
import com.android.systemui.scene.shared.model.SceneKey
@@ -101,53 +103,59 @@ private fun SceneScope.QuickSettingsScene(
modifier: Modifier = Modifier,
) {
// TODO(b/280887232): implement the real UI.
- val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState()
- val collapsedHeaderHeight =
- with(LocalDensity.current) { ShadeHeader.Dimensions.CollapsedHeight.roundToPx() }
- Column(
- horizontalAlignment = Alignment.CenterHorizontally,
- modifier =
- modifier
- .fillMaxSize()
- .clickable(onClick = { viewModel.onContentClicked() })
- .padding(start = 16.dp, end = 16.dp, bottom = 48.dp)
- ) {
- when (LocalWindowSizeClass.current.widthSizeClass) {
- WindowWidthSizeClass.Compact ->
- AnimatedVisibility(
- visible = !isCustomizing,
- enter =
- expandVertically(
- animationSpec = tween(1000),
- initialHeight = { collapsedHeaderHeight },
- ) + fadeIn(tween(1000)),
- exit =
- shrinkVertically(
- animationSpec = tween(1000),
- targetHeight = { collapsedHeaderHeight },
- shrinkTowards = Alignment.Top,
- ) + fadeOut(tween(1000)),
- ) {
- ExpandedShadeHeader(
+ Box(modifier = modifier.fillMaxSize()) {
+ val isCustomizing by viewModel.qsSceneAdapter.isCustomizing.collectAsState()
+ val collapsedHeaderHeight =
+ with(LocalDensity.current) { ShadeHeader.Dimensions.CollapsedHeight.roundToPx() }
+ Column(
+ horizontalAlignment = Alignment.CenterHorizontally,
+ modifier =
+ Modifier.fillMaxSize()
+ .clickable(onClick = { viewModel.onContentClicked() })
+ .padding(start = 16.dp, end = 16.dp, bottom = 48.dp)
+ ) {
+ when (LocalWindowSizeClass.current.widthSizeClass) {
+ WindowWidthSizeClass.Compact ->
+ AnimatedVisibility(
+ visible = !isCustomizing,
+ enter =
+ expandVertically(
+ animationSpec = tween(1000),
+ initialHeight = { collapsedHeaderHeight },
+ ) + fadeIn(tween(1000)),
+ exit =
+ shrinkVertically(
+ animationSpec = tween(1000),
+ targetHeight = { collapsedHeaderHeight },
+ shrinkTowards = Alignment.Top,
+ ) + fadeOut(tween(1000)),
+ ) {
+ ExpandedShadeHeader(
+ viewModel = viewModel.shadeHeaderViewModel,
+ createTintedIconManager = createTintedIconManager,
+ createBatteryMeterViewController = createBatteryMeterViewController,
+ statusBarIconController = statusBarIconController,
+ )
+ }
+ else ->
+ CollapsedShadeHeader(
viewModel = viewModel.shadeHeaderViewModel,
createTintedIconManager = createTintedIconManager,
createBatteryMeterViewController = createBatteryMeterViewController,
statusBarIconController = statusBarIconController,
)
- }
- else ->
- CollapsedShadeHeader(
- viewModel = viewModel.shadeHeaderViewModel,
- createTintedIconManager = createTintedIconManager,
- createBatteryMeterViewController = createBatteryMeterViewController,
- statusBarIconController = statusBarIconController,
- )
+ }
+ Spacer(modifier = Modifier.height(16.dp))
+ QuickSettings(
+ modifier = Modifier.fillMaxHeight(),
+ viewModel.qsSceneAdapter,
+ QSSceneAdapter.State.QS
+ )
}
- Spacer(modifier = Modifier.height(16.dp))
- QuickSettings(
- modifier = Modifier.fillMaxHeight(),
- viewModel.qsSceneAdapter,
- QSSceneAdapter.State.QS
+ HeadsUpNotificationSpace(
+ viewModel = viewModel.notifications,
+ isPeekFromBottom = true,
+ modifier = Modifier.padding(16.dp).fillMaxSize(),
)
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
index f35ea8373db7..bded98d52481 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt
@@ -17,15 +17,20 @@
package com.android.systemui.scene.ui.composable
import androidx.compose.foundation.layout.Box
+import androidx.compose.foundation.layout.fillMaxSize
+import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
+import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.SceneScope
import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.notifications.ui.composable.HeadsUpNotificationSpace
import com.android.systemui.scene.shared.model.Direction
import com.android.systemui.scene.shared.model.Edge
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
@@ -36,7 +41,11 @@ import kotlinx.coroutines.flow.asStateFlow
* content from the scene framework.
*/
@SysUISingleton
-class GoneScene @Inject constructor() : ComposableScene {
+class GoneScene
+@Inject
+constructor(
+ private val notificationsViewModel: NotificationsPlaceholderViewModel,
+) : ComposableScene {
override val key = SceneKey.Gone
override val destinationScenes: StateFlow<Map<UserAction, SceneModel>> =
@@ -56,6 +65,11 @@ class GoneScene @Inject constructor() : ComposableScene {
override fun SceneScope.Content(
modifier: Modifier,
) {
- Box(modifier = modifier)
+ Box(modifier = modifier) {
+ HeadsUpNotificationSpace(
+ viewModel = notificationsViewModel,
+ modifier = Modifier.padding(16.dp).fillMaxSize(),
+ )
+ }
}
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt
index 45df2b1bb20c..6bb525aa00fb 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt
@@ -3,10 +3,12 @@ package com.android.systemui.scene.ui.composable.transitions
import androidx.compose.animation.core.tween
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
+import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.scene.ui.composable.Shade
fun TransitionBuilder.goneToShadeTransition() {
spec = tween(durationMillis = 500)
translate(Shade.rootElementKey, Edge.Top, true)
+ fade(Notifications.Elements.NotificationScrim)
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt
index fadbdce80cbf..b7f12f3b40bd 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt
@@ -20,5 +20,5 @@ fun TransitionBuilder.lockscreenToShadeTransition() {
startsOutsideLayoutBounds = false,
)
}
- fractionRange(start = 0.5f) { fade(Notifications.Elements.Notifications) }
+ fractionRange(start = 0.5f) { fade(Notifications.Elements.NotificationScrim) }
}
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
index 5616175ed11c..d5c2a03b3f9f 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt
@@ -10,7 +10,7 @@ import com.android.systemui.shade.ui.composable.ShadeHeader
fun TransitionBuilder.shadeToQuickSettingsTransition() {
spec = tween(durationMillis = 500)
- translate(Notifications.Elements.Notifications, Edge.Bottom)
+ translate(Notifications.Elements.NotificationScrim, Edge.Bottom)
timestampRange(endMillis = 83) { fade(QuickSettings.Elements.FooterActions) }
translate(ShadeHeader.Elements.CollapsedContent, y = ShadeHeader.Dimensions.CollapsedHeight)
diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
index a02f046a18f5..2df151bc2d8e 100644
--- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
+++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt
@@ -37,7 +37,7 @@ import com.android.compose.animation.scene.SceneScope
import com.android.systemui.battery.BatteryMeterViewController
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
-import com.android.systemui.notifications.ui.composable.Notifications
+import com.android.systemui.notifications.ui.composable.NotificationStack
import com.android.systemui.qs.ui.adapter.QSSceneAdapter
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.scene.shared.model.Direction
@@ -160,7 +160,11 @@ private fun SceneScope.ShadeScene(
QSSceneAdapter.State.QQS
)
Spacer(modifier = Modifier.height(16.dp))
- Notifications(modifier = Modifier.weight(1f))
+ NotificationStack(
+ viewModel = viewModel.notifications,
+ isScrimVisible = true,
+ modifier = Modifier.weight(1f),
+ )
}
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt
index 48d374207388..48d3fe000ff8 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/SharedNotificationContainerPosition.kt
@@ -23,4 +23,6 @@ data class SharedNotificationContainerPosition(
/** Whether any modifications to top/bottom are smoothly animated */
val animate: Boolean = false,
-)
+) {
+ val height: Float = bottom - top
+}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
index e256b49be8f8..949c940bdebc 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardInteractor.kt
@@ -56,6 +56,7 @@ import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
@@ -83,10 +84,18 @@ constructor(
shadeRepository: ShadeRepository,
sceneInteractorProvider: Provider<SceneInteractor>,
) {
- /** Position information for the shared notification container. */
- val sharedNotificationContainerPosition =
+ // TODO(b/296118689): move to a repository
+ private val _sharedNotificationContainerPosition =
MutableStateFlow(SharedNotificationContainerPosition())
+ /** Position information for the shared notification container. */
+ val sharedNotificationContainerPosition: StateFlow<SharedNotificationContainerPosition> =
+ _sharedNotificationContainerPosition.asStateFlow()
+
+ fun setSharedNotificationContainerPosition(position: SharedNotificationContainerPosition) {
+ _sharedNotificationContainerPosition.value = position
+ }
+
/**
* The amount of doze the system is in, where `1.0` is fully dozing and `0.0` is not dozing at
* all.
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
index 165ee364c2c8..5673f997d23d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultNotificationStackScrollLayoutSection.kt
@@ -29,10 +29,13 @@ import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
import javax.inject.Inject
@@ -42,18 +45,24 @@ class DefaultNotificationStackScrollLayoutSection
constructor(
context: Context,
private val featureFlags: FeatureFlags,
+ sceneContainerFlags: SceneContainerFlags,
notificationPanelView: NotificationPanelView,
sharedNotificationContainer: SharedNotificationContainer,
sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
+ notificationStackAppearanceViewModel: NotificationStackAppearanceViewModel,
+ ambientState: AmbientState,
controller: NotificationStackScrollLayoutController,
notificationStackSizeCalculator: NotificationStackSizeCalculator,
private val smartspaceViewModel: KeyguardSmartspaceViewModel,
) :
NotificationStackScrollLayoutSection(
context,
+ sceneContainerFlags,
notificationPanelView,
sharedNotificationContainer,
sharedNotificationContainerViewModel,
+ notificationStackAppearanceViewModel,
+ ambientState,
controller,
notificationStackSizeCalculator,
) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
index 441f59d6df1d..a9e766e5f98d 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/NotificationStackScrollLayoutSection.kt
@@ -24,20 +24,28 @@ import androidx.constraintlayout.widget.ConstraintLayout
import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
import com.android.systemui.keyguard.shared.model.KeyguardSection
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
+import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
+import com.android.systemui.statusbar.notification.stack.ui.viewbinder.NotificationStackAppearanceViewBinder
import com.android.systemui.statusbar.notification.stack.ui.viewbinder.SharedNotificationContainerBinder
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
import kotlinx.coroutines.DisposableHandle
abstract class NotificationStackScrollLayoutSection
constructor(
protected val context: Context,
+ private val sceneContainerFlags: SceneContainerFlags,
private val notificationPanelView: NotificationPanelView,
private val sharedNotificationContainer: SharedNotificationContainer,
private val sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
+ private val notificationStackAppearanceViewModel: NotificationStackAppearanceViewModel,
+ private val ambientState: AmbientState,
private val controller: NotificationStackScrollLayoutController,
private val notificationStackSizeCalculator: NotificationStackSizeCalculator,
) : KeyguardSection() {
@@ -68,9 +76,19 @@ constructor(
SharedNotificationContainerBinder.bind(
sharedNotificationContainer,
sharedNotificationContainerViewModel,
+ sceneContainerFlags,
controller,
notificationStackSizeCalculator,
)
+ if (sceneContainerFlags.flexiNotifsEnabled()) {
+ NotificationStackAppearanceViewBinder.bind(
+ sharedNotificationContainer,
+ notificationStackAppearanceViewModel,
+ sceneContainerFlags,
+ ambientState,
+ controller,
+ )
+ }
}
override fun removeViews(constraintLayout: ConstraintLayout) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
index 2c45da63edb4..ab68ecd920ff 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/SplitShadeNotificationStackScrollLayoutSection.kt
@@ -29,10 +29,13 @@ import com.android.systemui.flags.Flags
import com.android.systemui.keyguard.shared.KeyguardShadeMigrationNssl
import com.android.systemui.keyguard.ui.viewmodel.KeyguardSmartspaceViewModel
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.shade.NotificationPanelView
+import com.android.systemui.statusbar.notification.stack.AmbientState
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
import javax.inject.Inject
@@ -42,18 +45,24 @@ class SplitShadeNotificationStackScrollLayoutSection
constructor(
context: Context,
private val featureFlags: FeatureFlags,
+ sceneContainerFlags: SceneContainerFlags,
notificationPanelView: NotificationPanelView,
sharedNotificationContainer: SharedNotificationContainer,
sharedNotificationContainerViewModel: SharedNotificationContainerViewModel,
+ notificationStackAppearanceViewModel: NotificationStackAppearanceViewModel,
+ ambientState: AmbientState,
controller: NotificationStackScrollLayoutController,
notificationStackSizeCalculator: NotificationStackSizeCalculator,
private val smartspaceViewModel: KeyguardSmartspaceViewModel,
) :
NotificationStackScrollLayoutSection(
context,
+ sceneContainerFlags,
notificationPanelView,
sharedNotificationContainer,
sharedNotificationContainerViewModel,
+ notificationStackAppearanceViewModel,
+ ambientState,
controller,
notificationStackSizeCalculator,
) {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
index 60f75f03609c..56cbd36f8cc5 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardRootViewModel.kt
@@ -49,6 +49,7 @@ import javax.inject.Provider
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableStateFlow
+import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
@@ -99,6 +100,10 @@ constructor(
val goneToAodTransition = keyguardTransitionInteractor.goneToAodTransition
+ /** the shared notification container position *on the lockscreen* */
+ val notificationPositionOnLockscreen: StateFlow<SharedNotificationContainerPosition>
+ get() = keyguardInteractor.sharedNotificationContainerPosition
+
/** An observable for the alpha level for the entire keyguard root view. */
val alpha: Flow<Float> =
previewMode.flatMapLatest {
@@ -249,8 +254,9 @@ constructor(
if (previewMode.value.isInPreviewMode) {
return
}
- keyguardInteractor.sharedNotificationContainerPosition.value =
+ keyguardInteractor.setSharedNotificationContainerPosition(
SharedNotificationContainerPosition(top, bottom)
+ )
}
/** Is there an expanded pulse, are we animating in response? */
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
index c03e4d950cae..539db7fb1ae3 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModel.kt
@@ -21,6 +21,7 @@ import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
@@ -37,6 +38,8 @@ constructor(
deviceEntryInteractor: DeviceEntryInteractor,
communalInteractor: CommunalInteractor,
val longPress: KeyguardLongPressViewModel,
+ val keyguardRoot: KeyguardRootViewModel,
+ val notifications: NotificationsPlaceholderViewModel,
) {
/** The key of the scene we should switch to when swiping up. */
val upDestinationSceneKey: StateFlow<SceneKey> =
diff --git a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
index 3941fd75ebaa..346d5c30a63e 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModel.kt
@@ -24,6 +24,7 @@ import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.shared.model.SceneModel
import com.android.systemui.scene.shared.model.UserAction
import com.android.systemui.shade.ui.viewmodel.ShadeHeaderViewModel
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
import javax.inject.Inject
import kotlinx.coroutines.flow.map
@@ -35,6 +36,7 @@ constructor(
private val deviceEntryInteractor: DeviceEntryInteractor,
val shadeHeaderViewModel: ShadeHeaderViewModel,
val qsSceneAdapter: QSSceneAdapter,
+ val notifications: NotificationsPlaceholderViewModel,
) {
/** Notifies that some content in quick settings was clicked. */
fun onContentClicked() = deviceEntryInteractor.attemptDeviceEntry()
diff --git a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
index 8def457423e4..f3f9c916d705 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/domain/startable/SceneContainerStartable.kt
@@ -97,6 +97,7 @@ constructor(
/** Updates the visibility of the scene container. */
private fun hydrateVisibility() {
applicationScope.launch {
+ // TODO(b/296114544): Combine with some global hun state to make it visible!
sceneInteractor.transitionState
.mapNotNull { state ->
when (state) {
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 7fc409445f50..c88a04c24044 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
@@ -4,9 +4,11 @@ import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.WindowInsets
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.scene.shared.model.Scene
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import kotlinx.coroutines.flow.MutableStateFlow
/** A root view of the main SysUI window that supports scenes. */
@@ -27,6 +29,8 @@ class SceneWindowRootView(
fun init(
viewModel: SceneContainerViewModel,
containerConfig: SceneContainerConfig,
+ sharedNotificationContainer: SharedNotificationContainer,
+ flags: SceneContainerFlags,
scenes: Set<Scene>,
layoutInsetController: LayoutInsetsController,
) {
@@ -37,6 +41,8 @@ class SceneWindowRootView(
viewModel = viewModel,
windowInsets = windowInsets,
containerConfig = containerConfig,
+ sharedNotificationContainer = sharedNotificationContainer,
+ flags = flags,
scenes = scenes,
onVisibilityChangedInternal = { isVisible ->
super.setVisibility(if (isVisible) View.VISIBLE else View.INVISIBLE)
diff --git a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
index 17d6c9d319e8..4a839b8df9ba 100644
--- a/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/scene/ui/view/SceneWindowRootViewBinder.kt
@@ -31,10 +31,13 @@ import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.compose.ComposeFacade
import com.android.systemui.lifecycle.repeatWhenAttached
import com.android.systemui.res.R
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.scene.shared.model.Scene
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.scene.ui.viewmodel.SceneContainerViewModel
+import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
+import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import java.time.Instant
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.launch
@@ -47,6 +50,8 @@ object SceneWindowRootViewBinder {
viewModel: SceneContainerViewModel,
windowInsets: StateFlow<WindowInsets?>,
containerConfig: SceneContainerConfig,
+ sharedNotificationContainer: SharedNotificationContainer,
+ flags: SceneContainerFlags,
scenes: Set<Scene>,
onVisibilityChangedInternal: (isVisible: Boolean) -> Unit,
) {
@@ -91,6 +96,13 @@ object SceneWindowRootViewBinder {
val legacyView = view.requireViewById<View>(R.id.legacy_window_root)
view.addView(createVisibilityToggleView(legacyView))
+ if (flags.flexiNotifsEnabled()) {
+ (sharedNotificationContainer.parent as? ViewGroup)?.removeView(
+ sharedNotificationContainer
+ )
+ view.addView(sharedNotificationContainer)
+ }
+
launch {
viewModel.isVisible.collect { isVisible ->
onVisibilityChangedInternal(isVisible)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
index 37073a6b5a50..e5657d334ff6 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ShadeViewProviderModule.kt
@@ -68,6 +68,7 @@ abstract class ShadeViewProviderModule {
sceneContainerFlags: SceneContainerFlags,
viewModelProvider: Provider<SceneContainerViewModel>,
containerConfigProvider: Provider<SceneContainerConfig>,
+ flagsProvider: Provider<SceneContainerFlags>,
scenesProvider: Provider<Set<@JvmSuppressWildcards Scene>>,
layoutInsetController: NotificationInsetsController,
): WindowRootView {
@@ -77,6 +78,9 @@ abstract class ShadeViewProviderModule {
sceneWindowRootView.init(
viewModel = viewModelProvider.get(),
containerConfig = containerConfigProvider.get(),
+ sharedNotificationContainer =
+ sceneWindowRootView.requireViewById(R.id.shared_notification_container),
+ flags = flagsProvider.get(),
scenes = scenesProvider.get(),
layoutInsetController = layoutInsetController,
)
diff --git a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
index af880816914f..2a071def083a 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModel.kt
@@ -21,12 +21,13 @@ import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.deviceentry.domain.interactor.DeviceEntryInteractor
import com.android.systemui.qs.ui.adapter.QSSceneAdapter
import com.android.systemui.scene.shared.model.SceneKey
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
+import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.SharingStarted
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.stateIn
-import javax.inject.Inject
/** Models UI state and handles user input for the shade scene. */
@SysUISingleton
@@ -37,6 +38,7 @@ constructor(
private val deviceEntryInteractor: DeviceEntryInteractor,
val qsSceneAdapter: QSSceneAdapter,
val shadeHeaderViewModel: ShadeHeaderViewModel,
+ val notifications: NotificationsPlaceholderViewModel,
) {
/** The key of the scene we should switch to when swiping up. */
val upDestinationSceneKey: StateFlow<SceneKey> =
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationStackAppearanceRepository.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationStackAppearanceRepository.kt
new file mode 100644
index 000000000000..7c10663bbb50
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationStackAppearanceRepository.kt
@@ -0,0 +1,30 @@
+/*
+ * 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.statusbar.notification.stack.data.repository
+
+import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
+import com.android.systemui.dagger.SysUISingleton
+import javax.inject.Inject
+import kotlinx.coroutines.flow.MutableStateFlow
+
+/** A repository which holds state about and controlling the appearance of the NSSL */
+@SysUISingleton
+class NotificationStackAppearanceRepository @Inject constructor() {
+ /** The position of the notification stack in the current scene */
+ val stackPosition = MutableStateFlow(SharedNotificationContainerPosition(0f, 0f))
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
new file mode 100644
index 000000000000..820fe0b1f11e
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt
@@ -0,0 +1,43 @@
+/*
+ * 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.statusbar.notification.stack.domain.interactor
+
+import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.statusbar.notification.stack.data.repository.NotificationStackAppearanceRepository
+import javax.inject.Inject
+import kotlinx.coroutines.flow.StateFlow
+import kotlinx.coroutines.flow.asStateFlow
+
+/** An interactor which controls the appearance of the NSSL */
+@SysUISingleton
+class NotificationStackAppearanceInteractor
+@Inject
+constructor(
+ private val repository: NotificationStackAppearanceRepository,
+) {
+ /** The position of the notification stack in the current scene */
+ val stackPosition: StateFlow<SharedNotificationContainerPosition>
+ get() = repository.stackPosition.asStateFlow()
+
+ /** Sets the position of the notification stack in the current scene */
+ fun setStackPosition(position: SharedNotificationContainerPosition) {
+ check(position.top <= position.bottom) { "Invalid position: $position" }
+ repository.stackPosition.value = position
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/SceneContainerFlagsExtension.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/SceneContainerFlagsExtension.kt
new file mode 100644
index 000000000000..5a71bd6fa116
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/shared/SceneContainerFlagsExtension.kt
@@ -0,0 +1,27 @@
+/*
+ * 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.statusbar.notification.stack.shared
+
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
+
+private const val FLEXI_NOTIFS = false
+
+/**
+ * Returns whether flexiglass is displaying notifications, which is currently an optional piece of
+ * flexiglass
+ */
+fun SceneContainerFlags.flexiNotifsEnabled() = FLEXI_NOTIFS && isEnabled()
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackAppearanceViewBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackAppearanceViewBinder.kt
new file mode 100644
index 000000000000..4d6a6ee98b7d
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/NotificationStackAppearanceViewBinder.kt
@@ -0,0 +1,59 @@
+/*
+ * 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.statusbar.notification.stack.ui.viewbinder
+
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
+import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
+import com.android.systemui.statusbar.notification.stack.AmbientState
+import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
+import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationStackAppearanceViewModel
+import kotlinx.coroutines.launch
+
+/** Binds the shared notification container to its view-model. */
+object NotificationStackAppearanceViewBinder {
+
+ @JvmStatic
+ fun bind(
+ view: SharedNotificationContainer,
+ viewModel: NotificationStackAppearanceViewModel,
+ sceneContainerFlags: SceneContainerFlags,
+ ambientState: AmbientState,
+ controller: NotificationStackScrollLayoutController,
+ ) {
+ view.repeatWhenAttached {
+ repeatOnLifecycle(Lifecycle.State.CREATED) {
+ launch {
+ viewModel.stackPosition.collect {
+ controller.updateTopPadding(
+ it.top,
+ controller.isAddOrRemoveAnimationPending
+ )
+ }
+ }
+ launch {
+ viewModel.expandFraction.collect {
+ ambientState.expansionFraction = it
+ controller.expandedHeight = it * controller.view.height
+ }
+ }
+ }
+ }
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
index 0ff1bec84d16..44006fc3fd4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt
@@ -19,8 +19,10 @@ package com.android.systemui.statusbar.notification.stack.ui.viewbinder
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.repeatOnLifecycle
import com.android.systemui.lifecycle.repeatWhenAttached
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
import com.android.systemui.statusbar.notification.stack.NotificationStackScrollLayoutController
import com.android.systemui.statusbar.notification.stack.NotificationStackSizeCalculator
+import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
import com.android.systemui.statusbar.notification.stack.ui.view.SharedNotificationContainer
import com.android.systemui.statusbar.notification.stack.ui.viewmodel.SharedNotificationContainerViewModel
import kotlinx.coroutines.DisposableHandle
@@ -33,6 +35,7 @@ object SharedNotificationContainerBinder {
fun bind(
view: SharedNotificationContainer,
viewModel: SharedNotificationContainerViewModel,
+ sceneContainerFlags: SceneContainerFlags,
controller: NotificationStackScrollLayoutController,
notificationStackSizeCalculator: NotificationStackSizeCalculator,
): DisposableHandle {
@@ -68,10 +71,12 @@ object SharedNotificationContainerBinder {
.collect { controller.setMaxDisplayedNotifications(it) }
}
- launch {
- viewModel.position.collect {
- val animate = it.animate || controller.isAddOrRemoveAnimationPending()
- controller.updateTopPadding(it.top, animate)
+ if (!sceneContainerFlags.flexiNotifsEnabled()) {
+ launch {
+ viewModel.position.collect {
+ val animate = it.animate || controller.isAddOrRemoveAnimationPending
+ controller.updateTopPadding(it.top, animate)
+ }
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt
new file mode 100644
index 000000000000..b86993486097
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationStackAppearanceViewModel.kt
@@ -0,0 +1,41 @@
+/*
+ * 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.statusbar.notification.stack.ui.viewmodel
+
+import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.shade.domain.interactor.ShadeInteractor
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
+import javax.inject.Inject
+import kotlinx.coroutines.flow.Flow
+
+/** ViewModel which represents the state of the NSSL/Controller in the world of flexiglass */
+@SysUISingleton
+class NotificationStackAppearanceViewModel
+@Inject
+constructor(
+ stackAppearanceInteractor: NotificationStackAppearanceInteractor,
+ shadeInteractor: ShadeInteractor,
+) {
+ /** The expansion fraction from the top of the notification shade */
+ val expandFraction: Flow<Float> = shadeInteractor.shadeExpansion
+
+ /** The position of the notification stack in the current scene */
+ val stackPosition: Flow<SharedNotificationContainerPosition> =
+ stackAppearanceInteractor.stackPosition
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
new file mode 100644
index 000000000000..7def6feedb41
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/NotificationsPlaceholderViewModel.kt
@@ -0,0 +1,53 @@
+/*
+ * 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.statusbar.notification.stack.ui.viewmodel
+
+import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
+import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.flags.FeatureFlagsClassic
+import com.android.systemui.flags.Flags
+import com.android.systemui.scene.shared.flag.SceneContainerFlags
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
+import com.android.systemui.statusbar.notification.stack.shared.flexiNotifsEnabled
+import javax.inject.Inject
+
+/**
+ * ViewModel used by the Notification placeholders inside the scene container to update the
+ * [NotificationStackAppearanceInteractor], and by extension control the NSSL.
+ */
+@SysUISingleton
+class NotificationsPlaceholderViewModel
+@Inject
+constructor(
+ private val interactor: NotificationStackAppearanceInteractor,
+ flags: SceneContainerFlags,
+ featureFlags: FeatureFlagsClassic,
+) {
+ /** DEBUG: whether the placeholder "Notifications" text should be shown. */
+ val isPlaceholderTextVisible: Boolean = !flags.flexiNotifsEnabled()
+
+ /** DEBUG: whether the placeholder should be made slightly visible for positional debugging. */
+ val isVisualDebuggingEnabled: Boolean = featureFlags.isEnabled(Flags.NSSL_DEBUG_LINES)
+
+ /** DEBUG: whether the debug logging should be output. */
+ val isDebugLoggingEnabled: Boolean = flags.flexiNotifsEnabled()
+
+ /** Sets the position of the notification stack in the current scene */
+ fun setPlaceholderPositionInWindow(top: Float, bottom: Float) {
+ interactor.setStackPosition(SharedNotificationContainerPosition(top, bottom))
+ }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index d6b6f75b3186..296ea884e5c3 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -18,6 +18,7 @@
package com.android.systemui.statusbar.notification.stack.ui.viewmodel
import com.android.systemui.common.shared.model.SharedNotificationContainerPosition
+import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -25,7 +26,10 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
import com.android.systemui.util.kotlin.sample
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.combine
import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.distinctUntilChanged
@@ -33,12 +37,14 @@ import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.onStart
+import kotlinx.coroutines.flow.stateIn
/** View-model for the shared notification container, used by both the shade and keyguard spaces */
class SharedNotificationContainerViewModel
@Inject
constructor(
private val interactor: SharedNotificationContainerInteractor,
+ @Application applicationScope: CoroutineScope,
keyguardInteractor: KeyguardInteractor,
keyguardTransitionInteractor: KeyguardTransitionInteractor,
private val shadeInteractor: ShadeInteractor,
@@ -103,32 +109,38 @@ constructor(
*
* When the shade is expanding, the position is controlled by... the shade.
*/
- val position: Flow<SharedNotificationContainerPosition> =
- isOnLockscreenWithoutShade.flatMapLatest { onLockscreen ->
- if (onLockscreen) {
- combine(
- keyguardInteractor.sharedNotificationContainerPosition,
- configurationBasedDimensions
- ) { position, config ->
- if (config.useSplitShade) {
- position.copy(top = 0f)
- } else {
- position
+ val position: StateFlow<SharedNotificationContainerPosition> =
+ isOnLockscreenWithoutShade
+ .flatMapLatest { onLockscreen ->
+ if (onLockscreen) {
+ combine(
+ keyguardInteractor.sharedNotificationContainerPosition,
+ configurationBasedDimensions
+ ) { position, config ->
+ if (config.useSplitShade) {
+ position.copy(top = 0f)
+ } else {
+ position
+ }
+ }
+ } else {
+ interactor.topPosition.sample(shadeInteractor.qsExpansion, ::Pair).map {
+ (top, qsExpansion) ->
+ // When QS expansion > 0, it should directly set the top padding so do not
+ // animate it
+ val animate = qsExpansion == 0f
+ keyguardInteractor.sharedNotificationContainerPosition.value.copy(
+ top = top,
+ animate = animate
+ )
}
- }
- } else {
- interactor.topPosition.sample(shadeInteractor.qsExpansion, ::Pair).map {
- (top, qsExpansion) ->
- // When QS expansion > 0, it should directly set the top padding so do not
- // animate it
- val animate = qsExpansion == 0f
- keyguardInteractor.sharedNotificationContainerPosition.value.copy(
- top = top,
- animate = animate
- )
}
}
- }
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.WhileSubscribed(),
+ initialValue = SharedNotificationContainerPosition(0f, 0f),
+ )
/**
* Under certain scenarios, such as swiping up on the lockscreen, the container will need to be
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
index 0b3bc9daa8b7..d07836d3abce 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenSceneViewModelTest.kt
@@ -94,6 +94,8 @@ class LockscreenSceneViewModelTest : SysuiTestCase() {
KeyguardLongPressViewModel(
interactor = mock(),
),
+ keyguardRoot = utils.keyguardRootViewModel(),
+ notifications = utils.notificationsPlaceholderViewModel(),
)
}
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
index ef129c85ed37..5c325ae67369 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/ui/viewmodel/QuickSettingsSceneViewModelTest.kt
@@ -101,6 +101,7 @@ class QuickSettingsSceneViewModelTest : SysuiTestCase() {
),
shadeHeaderViewModel = shadeHeaderViewModel,
qsSceneAdapter = qsFlexiglassAdapter,
+ notifications = utils.notificationsPlaceholderViewModel(),
)
}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
index 6a054cd9aff7..c3294ff2e26c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/scene/SceneFrameworkIntegrationTest.kt
@@ -152,6 +152,8 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
KeyguardLongPressViewModel(
interactor = mock(),
),
+ keyguardRoot = utils.keyguardRootViewModel(),
+ notifications = utils.notificationsPlaceholderViewModel(),
)
private val mobileIconsInteractor = FakeMobileIconsInteractor(FakeMobileMappingsProxy(), mock())
@@ -237,6 +239,7 @@ class SceneFrameworkIntegrationTest : SysuiTestCase() {
deviceEntryInteractor = deviceEntryInteractor,
shadeHeaderViewModel = shadeHeaderViewModel,
qsSceneAdapter = qsFlexiglassAdapter,
+ notifications = utils.notificationsPlaceholderViewModel(),
)
utils.deviceEntryRepository.setUnlocked(false)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
index 0d3b2b372610..e2640af136a7 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/ui/viewmodel/ShadeSceneViewModelTest.kt
@@ -101,6 +101,7 @@ class ShadeSceneViewModelTest : SysuiTestCase() {
deviceEntryInteractor = deviceEntryInteractor,
shadeHeaderViewModel = shadeHeaderViewModel,
qsSceneAdapter = qsFlexiglassAdapter,
+ notifications = utils.notificationsPlaceholderViewModel(),
)
}
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 db8f21714964..3d54fdf9e364 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
@@ -253,8 +253,9 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
// Start on lockscreen
showLockscreen()
- keyguardInteractor.sharedNotificationContainerPosition.value =
+ keyguardInteractor.setSharedNotificationContainerPosition(
SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+ )
assertThat(position)
.isEqualTo(SharedNotificationContainerPosition(top = 1f, bottom = 2f))
@@ -273,8 +274,9 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
// Start on lockscreen
showLockscreen()
- keyguardInteractor.sharedNotificationContainerPosition.value =
+ keyguardInteractor.setSharedNotificationContainerPosition(
SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+ )
runCurrent()
// Top should be overridden to 0f
@@ -327,8 +329,9 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
overrideResource(R.bool.config_use_split_notification_shade, false)
configurationRepository.onAnyConfigurationChange()
- keyguardInteractor.sharedNotificationContainerPosition.value =
+ keyguardInteractor.setSharedNotificationContainerPosition(
SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+ )
assertThat(maxNotifications).isEqualTo(10)
@@ -349,8 +352,9 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
overrideResource(R.bool.config_use_split_notification_shade, false)
configurationRepository.onAnyConfigurationChange()
- keyguardInteractor.sharedNotificationContainerPosition.value =
+ keyguardInteractor.setSharedNotificationContainerPosition(
SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+ )
assertThat(maxNotifications).isEqualTo(10)
@@ -383,8 +387,9 @@ class SharedNotificationContainerViewModelTest : SysuiTestCase() {
overrideResource(R.bool.config_use_split_notification_shade, false)
configurationRepository.onAnyConfigurationChange()
- keyguardInteractor.sharedNotificationContainerPosition.value =
+ keyguardInteractor.setSharedNotificationContainerPosition(
SharedNotificationContainerPosition(top = 1f, bottom = 2f)
+ )
// -1 means No Limit
assertThat(maxNotifications).isEqualTo(-1)
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
index 29e73b548b0b..2decb3e67c53 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/scene/SceneTestUtils.kt
@@ -64,6 +64,7 @@ import com.android.systemui.keyguard.data.repository.FakeTrustRepository
import com.android.systemui.keyguard.data.repository.KeyguardRepository
import com.android.systemui.keyguard.data.repository.TrustRepository
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testDispatcher
import com.android.systemui.kosmos.testScope
@@ -78,6 +79,9 @@ import com.android.systemui.scene.shared.flag.FakeSceneContainerFlags
import com.android.systemui.scene.shared.model.SceneContainerConfig
import com.android.systemui.scene.shared.model.SceneKey
import com.android.systemui.shade.data.repository.FakeShadeRepository
+import com.android.systemui.statusbar.notification.stack.data.repository.NotificationStackAppearanceRepository
+import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor
+import com.android.systemui.statusbar.notification.stack.ui.viewmodel.NotificationsPlaceholderViewModel
import com.android.systemui.statusbar.phone.ScreenOffAnimationController
import com.android.systemui.statusbar.pipeline.mobile.data.repository.FakeMobileConnectionsRepository
import com.android.systemui.statusbar.pipeline.mobile.data.repository.MobileConnectionsRepository
@@ -117,6 +121,7 @@ class SceneTestUtils(
FakeFeatureFlagsClassic().apply {
set(Flags.FACE_AUTH_REFACTOR, false)
set(Flags.FULL_SCREEN_USER_SWITCHER, false)
+ set(Flags.NSSL_DEBUG_LINES, false)
}
val sceneContainerFlags = FakeSceneContainerFlags().apply { enabled = true }
val deviceEntryRepository: FakeDeviceEntryRepository by lazy { FakeDeviceEntryRepository() }
@@ -271,6 +276,19 @@ class SceneTestUtils(
)
}
+ fun keyguardRootViewModel(): KeyguardRootViewModel = mock()
+
+ fun notificationsPlaceholderViewModel(): NotificationsPlaceholderViewModel {
+ return NotificationsPlaceholderViewModel(
+ interactor =
+ NotificationStackAppearanceInteractor(
+ repository = NotificationStackAppearanceRepository(),
+ ),
+ flags = sceneContainerFlags,
+ featureFlags = featureFlags,
+ )
+ }
+
fun bouncerViewModel(
bouncerInteractor: BouncerInteractor,
authenticationInteractor: AuthenticationInteractor,