Loading packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/elements/NotificationStackElementProvider.kt +0 −9 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import com.android.compose.animation.scene.ElementContentScope import com.android.systemui.dagger.SysUISingleton import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.notifications.ui.composable.ConstrainedNotificationStack import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotificationSpace import com.android.systemui.plugins.keyguard.ui.composable.elements.LockscreenElement import com.android.systemui.plugins.keyguard.ui.composable.elements.LockscreenElementContext import com.android.systemui.plugins.keyguard.ui.composable.elements.LockscreenElementFactory Loading Loading @@ -98,12 +97,4 @@ constructor( modifier = modifier.fillMaxSize(), ) } @Composable private fun ContentScope.HeadsUpNotifications(modifier: Modifier = Modifier) { SnoozeableHeadsUpNotificationSpace( stackScrollView = stackScrollView.get(), viewModel = rememberViewModel("HeadsUpNotifications") { viewModelFactory.create() }, ) } } packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +38 −4 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ import androidx.compose.ui.geometry.Rect import androidx.compose.ui.graphics.BlendMode import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.toAndroidRectF import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll Loading Loading @@ -181,14 +182,18 @@ fun ContentScope.HeadsUpNotificationSpace( /** * A version of [HeadsUpNotificationSpace] that can be swiped up off the top edge of the screen by * the user. When swiped up, the heads up notification is snoozed. * * @param useDrawBounds Whether to communicate drawBounds updated to the [stackScrollView]. This * should be `true` when content rendering the regular stack is not setting draw bounds anymore, * but HUNs can still appear. */ @Composable fun ContentScope.SnoozeableHeadsUpNotificationSpace( useDrawBounds: () -> Boolean, stackScrollView: NotificationScrollView, viewModel: NotificationsPlaceholderViewModel, modifier: Modifier = Modifier, ) { val isSnoozable by viewModel.isHeadsUpOrAnimatingAway.collectAsStateWithLifecycle(false) var scrollOffset by remember { mutableFloatStateOf(0f) } Loading Loading @@ -229,11 +234,38 @@ fun ContentScope.SnoozeableHeadsUpNotificationSpace( } } // Wait for being Idle on this content, otherwise LaunchedEffect would fire too soon, and // another transition could override the NSSL stack bounds. val updateDrawBounds = layoutState.transitionState.isIdle() && useDrawBounds() LaunchedEffect(updateDrawBounds) { if (updateDrawBounds) { // Reset the stack bounds to avoid caching these values from the previous Scenes, and // not to confuse the StackScrollAlgorithm when it displays a HUN over GONE. stackScrollView.apply { // use -headsUpInset to allow HUN translation outside bounds for snoozing setStackTop(-headsUpInset) } } } HeadsUpNotificationSpace( stackScrollView = stackScrollView, viewModel = viewModel, modifier = modifier .onGloballyPositioned { if (updateDrawBounds) { stackScrollView.updateDrawBounds( it.boundsInWindow().toAndroidRectF().apply { // extend bounds to the screen top to avoid cutting off HUN // transitions top = 0f bottom += headsUpInset } ) } } .absoluteOffset { IntOffset( x = 0, Loading Loading @@ -836,13 +868,15 @@ private suspend fun scrollNotificationStack( private fun TransitionState.isOnLockscreen(): Boolean { return currentScene == Scenes.Lockscreen && currentOverlays.isEmpty() } private fun shouldUseLockscreenStackBounds(state: TransitionState): Boolean { return when (state) { is TransitionState.Idle -> state.isOnLockscreen() is TransitionState.Transition -> // Keep using the lockscreen stack bounds when there is no placeholder on the next content state.fromContent == Scenes.Lockscreen && state.toContent != Scenes.Shade || state.isTransitioningBetween(content = Scenes.Lockscreen, other = Overlays.Bouncer) // Keep using the lockscreen stack bounds when there is no placeholder on the next // content state.fromContent == Scenes.Lockscreen && state.toContent != Scenes.Shade || state.isTransitioningBetween(content = Scenes.Lockscreen, other = Overlays.Bouncer) } } Loading packages/SystemUI/compose/features/src/com/android/systemui/occluded/ui/composable/OccludedScene.kt +8 −46 Original line number Diff line number Diff line Loading @@ -19,13 +19,8 @@ package com.android.systemui.occluded.ui.composable import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.toAndroidRectF import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalDensity import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult Loading @@ -34,7 +29,6 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotificationSpace import com.android.systemui.notifications.ui.composable.headsUpTopInset import com.android.systemui.qs.shared.ui.QuickSettings import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes Loading @@ -46,7 +40,7 @@ import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.flow.Flow /** The occluded scene shows when a non-dream activity is showing over keyguard */ /** The occluded scene shows when a non-dream activity is showing over the lock screen. */ @SysUISingleton class OccludedScene @Inject Loading @@ -69,49 +63,17 @@ constructor( @Composable override fun ContentScope.Content(modifier: Modifier) { val isIdleAndNotShadeExpanded = with(layoutState.transitionState) { isIdle(key) && !isIdle(Overlays.NotificationsShade) && !isIdle(Overlays.QuickSettingsShade) } val headsUpInset = with(LocalDensity.current) { headsUpTopInset().toPx() } LaunchedEffect(isIdleAndNotShadeExpanded) { // Wait for being Idle on this Scene, otherwise LaunchedEffect would fire too soon, // and another transition could override the NSSL stack bounds. if (isIdleAndNotShadeExpanded) { // Reset the stack bounds to avoid caching these values from the previous Scenes, // and not to confuse the StackScrollAlgorithm when it displays a HUN over OCCLUDED. notificationStackScrollView.get().apply { // use -headsUpInset to allow HUN translation outside bounds for snoozing setStackTop(-headsUpInset) } } } animateContentFloatAsState( value = QuickSettings.SharedValues.SquishinessValues.OccludedSceneStarting, key = QuickSettings.SharedValues.TilesSquishiness, ) Spacer(modifier.fillMaxSize()) SnoozeableHeadsUpNotificationSpace( modifier = Modifier.onGloballyPositioned { // Once we are on the non-occluded Lockscreen, the regular stack is not setting // draw bounds anymore, but HUNs can still appear. if (isIdleAndNotShadeExpanded) { notificationStackScrollView .get() .updateDrawBounds( it.boundsInWindow().toAndroidRectF().apply { // extend bounds to the screen top to avoid cutting off HUN // transitions top = 0f } ) useDrawBounds = { with(layoutState.transitionState) { isIdle(key) && !isIdle(Overlays.NotificationsShade) && !isIdle(Overlays.QuickSettingsShade) } }, stackScrollView = notificationStackScrollView.get(), Loading packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +8 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,7 @@ import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayActionsView import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayContentViewModel import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.composable.Overlay import com.android.systemui.shade.ui.composable.ChipHighlightModel import com.android.systemui.shade.ui.composable.OverlayShade Loading Loading @@ -218,6 +219,13 @@ constructor( ) } SnoozeableHeadsUpNotificationSpace( useDrawBounds = { with(layoutState.transitionState) { // When overlaid on top of the lock screen, drawBounds updates are already // being sent. isIdle(key) && !isIdle(Scenes.Lockscreen) } }, stackScrollView = notificationStackScrollView.get(), viewModel = hunPlaceholderViewModel, ) Loading packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt +10 −50 Original line number Diff line number Diff line Loading @@ -19,13 +19,7 @@ package com.android.systemui.scene.ui.composable import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.toAndroidRectF import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalDensity import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult Loading @@ -34,7 +28,6 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotificationSpace import com.android.systemui.notifications.ui.composable.headsUpTopInset import com.android.systemui.qs.shared.ui.QuickSettings import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes Loading @@ -47,13 +40,13 @@ import kotlinx.coroutines.flow.Flow /** * "Gone" is not a real scene but rather the absence of scenes when we want to skip showing any * content from the scene framework. * scene from the scene framework. Overlays from the scene framework may still be shown. */ @SysUISingleton class GoneScene @Inject constructor( private val notificationStackScrolLView: Lazy<NotificationScrollView>, private val notificationStackScrollView: Lazy<NotificationScrollView>, private val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory, private val viewModelFactory: GoneUserActionsViewModel.Factory, ) : ExclusiveActivatable(), Scene { Loading @@ -71,53 +64,20 @@ constructor( @Composable override fun ContentScope.Content(modifier: Modifier) { val isIdleAndNotOccluded = with(layoutState.transitionState) { isIdle(key) && !isIdle(Overlays.NotificationsShade) && !isIdle(Overlays.QuickSettingsShade) } val headsUpInset = with(LocalDensity.current) { headsUpTopInset().toPx() } LaunchedEffect(isIdleAndNotOccluded) { // Wait for being Idle on this Scene, otherwise LaunchedEffect would fire too soon, // and another transition could override the NSSL stack bounds. if (isIdleAndNotOccluded) { // Reset the stack bounds to avoid caching these values from the previous Scenes, // and not to confuse the StackScrollAlgorithm when it displays a HUN over GONE. notificationStackScrolLView.get().apply { // use -headsUpInset to allow HUN translation outside bounds for snoozing setStackTop(-headsUpInset) } } } animateContentFloatAsState( value = QuickSettings.SharedValues.SquishinessValues.GoneSceneStarting, key = QuickSettings.SharedValues.TilesSquishiness, ) Spacer(modifier.fillMaxSize()) SnoozeableHeadsUpNotificationSpace( modifier = Modifier.onGloballyPositioned { // Once we are on the non-occluded Lockscreen, the regular stack is not setting // draw bounds anymore, but HUNs can still appear. if (isIdleAndNotOccluded) { notificationStackScrolLView .get() .updateDrawBounds( it.boundsInWindow().toAndroidRectF().apply { // extend bounds to the screen top to avoid cutting off HUN // transitions top = 0f bottom += headsUpInset } ) useDrawBounds = { with(layoutState.transitionState) { isIdle(key) && !isIdle(Overlays.NotificationsShade) && !isIdle(Overlays.QuickSettingsShade) } }, stackScrollView = notificationStackScrolLView.get(), stackScrollView = notificationStackScrollView.get(), viewModel = rememberViewModel("GoneScene") { notificationsPlaceholderViewModelFactory.create() }, ) Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/keyguard/ui/composable/elements/NotificationStackElementProvider.kt +0 −9 Original line number Diff line number Diff line Loading @@ -28,7 +28,6 @@ import com.android.compose.animation.scene.ElementContentScope import com.android.systemui.dagger.SysUISingleton import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.notifications.ui.composable.ConstrainedNotificationStack import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotificationSpace import com.android.systemui.plugins.keyguard.ui.composable.elements.LockscreenElement import com.android.systemui.plugins.keyguard.ui.composable.elements.LockscreenElementContext import com.android.systemui.plugins.keyguard.ui.composable.elements.LockscreenElementFactory Loading Loading @@ -98,12 +97,4 @@ constructor( modifier = modifier.fillMaxSize(), ) } @Composable private fun ContentScope.HeadsUpNotifications(modifier: Modifier = Modifier) { SnoozeableHeadsUpNotificationSpace( stackScrollView = stackScrollView.get(), viewModel = rememberViewModel("HeadsUpNotifications") { viewModelFactory.create() }, ) } }
packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +38 −4 Original line number Diff line number Diff line Loading @@ -68,6 +68,7 @@ import androidx.compose.ui.geometry.Rect import androidx.compose.ui.graphics.BlendMode import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.graphicsLayer import androidx.compose.ui.graphics.toAndroidRectF import androidx.compose.ui.input.nestedscroll.NestedScrollConnection import androidx.compose.ui.input.nestedscroll.NestedScrollSource import androidx.compose.ui.input.nestedscroll.nestedScroll Loading Loading @@ -181,14 +182,18 @@ fun ContentScope.HeadsUpNotificationSpace( /** * A version of [HeadsUpNotificationSpace] that can be swiped up off the top edge of the screen by * the user. When swiped up, the heads up notification is snoozed. * * @param useDrawBounds Whether to communicate drawBounds updated to the [stackScrollView]. This * should be `true` when content rendering the regular stack is not setting draw bounds anymore, * but HUNs can still appear. */ @Composable fun ContentScope.SnoozeableHeadsUpNotificationSpace( useDrawBounds: () -> Boolean, stackScrollView: NotificationScrollView, viewModel: NotificationsPlaceholderViewModel, modifier: Modifier = Modifier, ) { val isSnoozable by viewModel.isHeadsUpOrAnimatingAway.collectAsStateWithLifecycle(false) var scrollOffset by remember { mutableFloatStateOf(0f) } Loading Loading @@ -229,11 +234,38 @@ fun ContentScope.SnoozeableHeadsUpNotificationSpace( } } // Wait for being Idle on this content, otherwise LaunchedEffect would fire too soon, and // another transition could override the NSSL stack bounds. val updateDrawBounds = layoutState.transitionState.isIdle() && useDrawBounds() LaunchedEffect(updateDrawBounds) { if (updateDrawBounds) { // Reset the stack bounds to avoid caching these values from the previous Scenes, and // not to confuse the StackScrollAlgorithm when it displays a HUN over GONE. stackScrollView.apply { // use -headsUpInset to allow HUN translation outside bounds for snoozing setStackTop(-headsUpInset) } } } HeadsUpNotificationSpace( stackScrollView = stackScrollView, viewModel = viewModel, modifier = modifier .onGloballyPositioned { if (updateDrawBounds) { stackScrollView.updateDrawBounds( it.boundsInWindow().toAndroidRectF().apply { // extend bounds to the screen top to avoid cutting off HUN // transitions top = 0f bottom += headsUpInset } ) } } .absoluteOffset { IntOffset( x = 0, Loading Loading @@ -836,13 +868,15 @@ private suspend fun scrollNotificationStack( private fun TransitionState.isOnLockscreen(): Boolean { return currentScene == Scenes.Lockscreen && currentOverlays.isEmpty() } private fun shouldUseLockscreenStackBounds(state: TransitionState): Boolean { return when (state) { is TransitionState.Idle -> state.isOnLockscreen() is TransitionState.Transition -> // Keep using the lockscreen stack bounds when there is no placeholder on the next content state.fromContent == Scenes.Lockscreen && state.toContent != Scenes.Shade || state.isTransitioningBetween(content = Scenes.Lockscreen, other = Overlays.Bouncer) // Keep using the lockscreen stack bounds when there is no placeholder on the next // content state.fromContent == Scenes.Lockscreen && state.toContent != Scenes.Shade || state.isTransitioningBetween(content = Scenes.Lockscreen, other = Overlays.Bouncer) } } Loading
packages/SystemUI/compose/features/src/com/android/systemui/occluded/ui/composable/OccludedScene.kt +8 −46 Original line number Diff line number Diff line Loading @@ -19,13 +19,8 @@ package com.android.systemui.occluded.ui.composable import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.toAndroidRectF import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalDensity import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult Loading @@ -34,7 +29,6 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotificationSpace import com.android.systemui.notifications.ui.composable.headsUpTopInset import com.android.systemui.qs.shared.ui.QuickSettings import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes Loading @@ -46,7 +40,7 @@ import dagger.Lazy import javax.inject.Inject import kotlinx.coroutines.flow.Flow /** The occluded scene shows when a non-dream activity is showing over keyguard */ /** The occluded scene shows when a non-dream activity is showing over the lock screen. */ @SysUISingleton class OccludedScene @Inject Loading @@ -69,49 +63,17 @@ constructor( @Composable override fun ContentScope.Content(modifier: Modifier) { val isIdleAndNotShadeExpanded = with(layoutState.transitionState) { isIdle(key) && !isIdle(Overlays.NotificationsShade) && !isIdle(Overlays.QuickSettingsShade) } val headsUpInset = with(LocalDensity.current) { headsUpTopInset().toPx() } LaunchedEffect(isIdleAndNotShadeExpanded) { // Wait for being Idle on this Scene, otherwise LaunchedEffect would fire too soon, // and another transition could override the NSSL stack bounds. if (isIdleAndNotShadeExpanded) { // Reset the stack bounds to avoid caching these values from the previous Scenes, // and not to confuse the StackScrollAlgorithm when it displays a HUN over OCCLUDED. notificationStackScrollView.get().apply { // use -headsUpInset to allow HUN translation outside bounds for snoozing setStackTop(-headsUpInset) } } } animateContentFloatAsState( value = QuickSettings.SharedValues.SquishinessValues.OccludedSceneStarting, key = QuickSettings.SharedValues.TilesSquishiness, ) Spacer(modifier.fillMaxSize()) SnoozeableHeadsUpNotificationSpace( modifier = Modifier.onGloballyPositioned { // Once we are on the non-occluded Lockscreen, the regular stack is not setting // draw bounds anymore, but HUNs can still appear. if (isIdleAndNotShadeExpanded) { notificationStackScrollView .get() .updateDrawBounds( it.boundsInWindow().toAndroidRectF().apply { // extend bounds to the screen top to avoid cutting off HUN // transitions top = 0f } ) useDrawBounds = { with(layoutState.transitionState) { isIdle(key) && !isIdle(Overlays.NotificationsShade) && !isIdle(Overlays.QuickSettingsShade) } }, stackScrollView = notificationStackScrollView.get(), Loading
packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsShadeOverlay.kt +8 −0 Original line number Diff line number Diff line Loading @@ -92,6 +92,7 @@ import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayActionsView import com.android.systemui.qs.ui.viewmodel.QuickSettingsShadeOverlayContentViewModel import com.android.systemui.res.R import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.composable.Overlay import com.android.systemui.shade.ui.composable.ChipHighlightModel import com.android.systemui.shade.ui.composable.OverlayShade Loading Loading @@ -218,6 +219,13 @@ constructor( ) } SnoozeableHeadsUpNotificationSpace( useDrawBounds = { with(layoutState.transitionState) { // When overlaid on top of the lock screen, drawBounds updates are already // being sent. isIdle(key) && !isIdle(Scenes.Lockscreen) } }, stackScrollView = notificationStackScrollView.get(), viewModel = hunPlaceholderViewModel, ) Loading
packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/GoneScene.kt +10 −50 Original line number Diff line number Diff line Loading @@ -19,13 +19,7 @@ package com.android.systemui.scene.ui.composable import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.runtime.Composable import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.getValue import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.toAndroidRectF import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.platform.LocalDensity import com.android.compose.animation.scene.ContentScope import com.android.compose.animation.scene.UserAction import com.android.compose.animation.scene.UserActionResult Loading @@ -34,7 +28,6 @@ import com.android.systemui.dagger.SysUISingleton import com.android.systemui.lifecycle.ExclusiveActivatable import com.android.systemui.lifecycle.rememberViewModel import com.android.systemui.notifications.ui.composable.SnoozeableHeadsUpNotificationSpace import com.android.systemui.notifications.ui.composable.headsUpTopInset import com.android.systemui.qs.shared.ui.QuickSettings import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes Loading @@ -47,13 +40,13 @@ import kotlinx.coroutines.flow.Flow /** * "Gone" is not a real scene but rather the absence of scenes when we want to skip showing any * content from the scene framework. * scene from the scene framework. Overlays from the scene framework may still be shown. */ @SysUISingleton class GoneScene @Inject constructor( private val notificationStackScrolLView: Lazy<NotificationScrollView>, private val notificationStackScrollView: Lazy<NotificationScrollView>, private val notificationsPlaceholderViewModelFactory: NotificationsPlaceholderViewModel.Factory, private val viewModelFactory: GoneUserActionsViewModel.Factory, ) : ExclusiveActivatable(), Scene { Loading @@ -71,53 +64,20 @@ constructor( @Composable override fun ContentScope.Content(modifier: Modifier) { val isIdleAndNotOccluded = with(layoutState.transitionState) { isIdle(key) && !isIdle(Overlays.NotificationsShade) && !isIdle(Overlays.QuickSettingsShade) } val headsUpInset = with(LocalDensity.current) { headsUpTopInset().toPx() } LaunchedEffect(isIdleAndNotOccluded) { // Wait for being Idle on this Scene, otherwise LaunchedEffect would fire too soon, // and another transition could override the NSSL stack bounds. if (isIdleAndNotOccluded) { // Reset the stack bounds to avoid caching these values from the previous Scenes, // and not to confuse the StackScrollAlgorithm when it displays a HUN over GONE. notificationStackScrolLView.get().apply { // use -headsUpInset to allow HUN translation outside bounds for snoozing setStackTop(-headsUpInset) } } } animateContentFloatAsState( value = QuickSettings.SharedValues.SquishinessValues.GoneSceneStarting, key = QuickSettings.SharedValues.TilesSquishiness, ) Spacer(modifier.fillMaxSize()) SnoozeableHeadsUpNotificationSpace( modifier = Modifier.onGloballyPositioned { // Once we are on the non-occluded Lockscreen, the regular stack is not setting // draw bounds anymore, but HUNs can still appear. if (isIdleAndNotOccluded) { notificationStackScrolLView .get() .updateDrawBounds( it.boundsInWindow().toAndroidRectF().apply { // extend bounds to the screen top to avoid cutting off HUN // transitions top = 0f bottom += headsUpInset } ) useDrawBounds = { with(layoutState.transitionState) { isIdle(key) && !isIdle(Overlays.NotificationsShade) && !isIdle(Overlays.QuickSettingsShade) } }, stackScrollView = notificationStackScrolLView.get(), stackScrollView = notificationStackScrollView.get(), viewModel = rememberViewModel("GoneScene") { notificationsPlaceholderViewModelFactory.create() }, ) Loading