Loading packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +33 −56 Original line number Diff line number Diff line Loading @@ -47,7 +47,6 @@ import androidx.compose.foundation.layout.windowInsetsBottomHeight import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect Loading @@ -60,7 +59,6 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.graphics.BlendMode import androidx.compose.ui.graphics.Color Loading @@ -70,7 +68,6 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.LayoutCoordinates import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onPlaced import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.layout.positionInWindow import androidx.compose.ui.platform.LocalConfiguration Loading @@ -82,6 +79,7 @@ import androidx.compose.ui.unit.Velocity import androidx.compose.ui.unit.dp import androidx.compose.ui.util.lerp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.LowestZIndexContentPicker import com.android.compose.animation.scene.NestedScrollBehavior Loading @@ -93,8 +91,9 @@ import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadi import com.android.systemui.res.R import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.session.ui.composable.rememberSession import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.shade.ui.composable.ShadeHeader import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimRounding Loading @@ -112,18 +111,16 @@ object Notifications { val NotificationStackPlaceholder = ElementKey("NotificationStackPlaceholder") val HeadsUpNotificationPlaceholder = ElementKey("HeadsUpNotificationPlaceholder", contentPicker = LowestZIndexContentPicker) val ShelfSpace = ElementKey("ShelfSpace") val NotificationStackCutoffGuideline = ElementKey("NotificationStackCutoffGuideline") } // Expansion fraction thresholds (between 0-1f) at which the corresponding value should be // at its maximum, given they are at their minimum value at expansion = 0f. object TransitionThresholds { const val EXPANSION_FOR_MAX_CORNER_RADIUS = 0.1f const val EXPANSION_FOR_MAX_SCRIM_ALPHA = 0.3f } } private val notificationsShadeContentKey: ContentKey get() = if (DualShade.isEnabled) Overlays.NotificationsShade else Scenes.Shade private val quickSettingsShadeContentKey: ContentKey get() = if (DualShade.isEnabled) Overlays.QuickSettingsShade else Scenes.QuickSettings /** * Adds the space where heads up notifications can appear in the scene. This should generally be the * entire size of the scene. Loading @@ -146,7 +143,7 @@ fun SceneScope.HeadsUpNotificationSpace( // This element is sometimes opted out of the shared element system, so there // can be multiple instances of it during a transition. Thus we need to // determine which instance should feed its bounds to NSSL to avoid providing // conflicting values // conflicting values. val useBounds = useHunBounds() if (useBounds) { val positionInWindow = coordinates.positionInWindow() Loading @@ -157,8 +154,8 @@ fun SceneScope.HeadsUpNotificationSpace( " bounds=$boundsInWindow" } // Note: boundsInWindow doesn't scroll off the screen, so use // positionInWindow // for top bound, which can scroll off screen while snoozing // positionInWindow for top bound, which can scroll off screen while // snoozing. stackScrollView.setHeadsUpTop(positionInWindow.y) stackScrollView.setHeadsUpBottom(boundsInWindow.bottom) } Loading Loading @@ -285,7 +282,8 @@ fun SceneScope.NotificationScrollingStack( shouldFillMaxSize: Boolean = true, shouldReserveSpaceForNavBar: Boolean = true, shouldIncludeHeadsUpSpace: Boolean = true, shadeMode: ShadeMode, shouldShowScrim: Boolean = true, supportNestedScrolling: Boolean, onEmptySpaceClick: (() -> Unit)? = null, modifier: Modifier = Modifier, ) { Loading @@ -293,6 +291,7 @@ fun SceneScope.NotificationScrollingStack( val density = LocalDensity.current val screenCornerRadius = LocalScreenCornerRadius.current val scrimCornerRadius = dimensionResource(R.dimen.notification_scrim_corner_radius) val scrimBackgroundColor = MaterialTheme.colorScheme.surface val scrollState = shadeSession.rememberSaveableSession(saver = ScrollState.Saver, key = null) { ScrollState(initial = 0) Loading Loading @@ -427,8 +426,14 @@ fun SceneScope.NotificationScrollingStack( // completes. if ( scrimOffset.value < 0 && layoutState.isTransitioning(from = Scenes.Shade, to = Scenes.Gone) || layoutState.isTransitioning(from = Scenes.Shade, to = Scenes.Lockscreen) (layoutState.isTransitioning( from = notificationsShadeContentKey, to = Scenes.Gone, ) || layoutState.isTransitioning( from = notificationsShadeContentKey, to = Scenes.Lockscreen, )) ) { IntOffset(x = 0, y = (scrimOffset.value * expansionFraction).roundToInt()) } else if ( Loading Loading @@ -498,7 +503,7 @@ fun SceneScope.NotificationScrollingStack( (expansionFraction / EXPANSION_FOR_MAX_SCRIM_ALPHA).coerceAtMost(1f) } else 1f } .background(MaterialTheme.colorScheme.surface) .thenIf(shouldShowScrim) { Modifier.background(scrimBackgroundColor) } .thenIf(shouldFillMaxSize) { Modifier.fillMaxSize() } .debugBackground(viewModel, DEBUG_BOX_COLOR) ) { Loading @@ -508,7 +513,7 @@ fun SceneScope.NotificationScrollingStack( topBehavior = NestedScrollBehavior.EdgeWithPreview, isExternalOverscrollGesture = { isCurrentGestureOverscroll.value }, ) .thenIf(shadeMode == ShadeMode.Single) { .thenIf(supportNestedScrolling) { Modifier.nestedScroll(scrimNestedScrollConnection) } .stackVerticalOverscroll(coroutineScope) { scrollState.canScrollForward } Loading Loading @@ -549,38 +554,6 @@ fun SceneScope.NotificationScrollingStack( } } /** * 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() .onPlaced { coordinates: LayoutCoordinates -> debugLog(viewModel) { ("SHELF onPlaced:" + " size=${coordinates.size}" + " bounds=${coordinates.boundsInWindow()}") } } .clip(RoundedCornerShape(24.dp)) .background(MaterialTheme.colorScheme.primaryContainer) .padding(16.dp), style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.onPrimaryContainer, ) } /** * A 0 height horizontal spacer to be placed at the bottom-most position in the current scene, where * the notification contents (stack, footer, shelf) should be drawn. Loading Loading @@ -673,15 +646,19 @@ private suspend fun scrollNotificationStack( } } private fun TransitionState.isOnLockscreen(): Boolean { return currentScene == Scenes.Lockscreen && currentOverlays.isEmpty() } private fun shouldUseLockscreenStackBounds(state: TransitionState): Boolean { return state is TransitionState.Idle && state.currentScene == Scenes.Lockscreen return state is TransitionState.Idle && state.isOnLockscreen() } private fun shouldUseLockscreenHunBounds(state: TransitionState): Boolean { return when (state) { is TransitionState.Idle -> state.currentScene == Scenes.Lockscreen is TransitionState.Idle -> state.isOnLockscreen() is TransitionState.Transition -> state.isTransitioning(from = Scenes.QuickSettings, to = Scenes.Lockscreen) state.isTransitioning(from = quickSettingsShadeContentKey, to = Scenes.Lockscreen) } } Loading @@ -690,7 +667,7 @@ private fun shouldAnimateScrimCornerRadius( shouldPunchHoleBehindScrim: Boolean, ): Boolean { return shouldPunchHoleBehindScrim || state.isTransitioning(from = Scenes.Shade, to = Scenes.Lockscreen) state.isTransitioning(from = notificationsShadeContentKey, to = Scenes.Lockscreen) } private fun calculateCornerRadius( Loading packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt +4 −9 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlay import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.ui.composable.Overlay import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.ui.composable.ExpandedShadeHeader import com.android.systemui.shade.ui.composable.OverlayShade import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView Loading Loading @@ -69,9 +68,7 @@ constructor( } @Composable override fun ContentScope.Content( modifier: Modifier, ) { override fun ContentScope.Content(modifier: Modifier) { val viewModel = rememberViewModel("NotificationsShadeOverlay-viewModel") { contentViewModelFactory.create() Loading @@ -81,10 +78,7 @@ constructor( viewModel.notificationsPlaceholderViewModelFactory.create() } OverlayShade( modifier = modifier, onScrimClicked = viewModel::onScrimClicked, ) { OverlayShade(modifier = modifier, onScrimClicked = viewModel::onScrimClicked) { Column { ExpandedShadeHeader( viewModelFactory = viewModel.shadeHeaderViewModelFactory, Loading @@ -102,7 +96,8 @@ constructor( shouldPunchHoleBehindScrim = false, shouldFillMaxSize = false, shouldReserveSpaceForNavBar = false, shadeMode = ShadeMode.Dual, shouldShowScrim = false, supportNestedScrolling = false, modifier = Modifier.fillMaxWidth(), ) Loading packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +1 −4 Original line number Diff line number Diff line Loading @@ -100,7 +100,6 @@ import com.android.systemui.res.R import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.composable.Scene import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.ui.composable.CollapsedShadeHeader import com.android.systemui.shade.ui.composable.ExpandedShadeHeader import com.android.systemui.shade.ui.composable.Shade Loading @@ -114,11 +113,9 @@ import dagger.Lazy import javax.inject.Inject import javax.inject.Named import kotlin.math.roundToInt import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow /** The Quick Settings (AKA "QS") scene shows the quick setting tiles. */ @OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class QuickSettingsScene @Inject Loading Loading @@ -427,7 +424,7 @@ private fun SceneScope.QuickSettingsScene( maxScrimTop = { screenHeight }, shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim, shouldIncludeHeadsUpSpace = false, shadeMode = ShadeMode.Single, supportNestedScrolling = true, modifier = Modifier.fillMaxWidth() .offset { IntOffset(x = 0, y = screenHeight.roundToInt()) } Loading packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt +2 −8 Original line number Diff line number Diff line Loading @@ -21,26 +21,20 @@ import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.TransitionBuilder import com.android.compose.animation.scene.UserActionDistance import com.android.systemui.notifications.ui.composable.Notifications import com.android.systemui.shade.ui.composable.OverlayShade import com.android.systemui.shade.ui.composable.Shade import com.android.systemui.shade.ui.composable.ShadeHeader import kotlin.time.Duration.Companion.milliseconds fun TransitionBuilder.toNotificationsShadeTransition( durationScale: Double = 1.0, ) { fun TransitionBuilder.toNotificationsShadeTransition(durationScale: Double = 1.0) { spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt()) swipeSpec = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold, ) distance = UserActionDistance { fromSceneSize, orientation -> fromSceneSize.height.toFloat() * 2 / 3f } scaleSize(OverlayShade.Elements.Panel, height = 0f) translate(OverlayShade.Elements.Panel, Edge.Top) fractionRange(end = .5f) { fade(OverlayShade.Elements.Scrim) } Loading packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +5 −19 Original line number Diff line number Diff line Loading @@ -40,7 +40,6 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect Loading Loading @@ -89,7 +88,6 @@ import com.android.systemui.media.controls.ui.composable.shouldElevateMedia import com.android.systemui.media.controls.ui.controller.MediaCarouselController import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.controls.ui.view.MediaHostState import com.android.systemui.media.controls.ui.view.MediaHostState.Companion.COLLAPSED import com.android.systemui.media.controls.ui.view.MediaHostState.Companion.EXPANDED import com.android.systemui.media.dagger.MediaModule.QS_PANEL Loading Loading @@ -117,7 +115,6 @@ import dagger.Lazy import javax.inject.Inject import javax.inject.Named import kotlin.math.roundToInt import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow object Shade { Loading @@ -128,23 +125,13 @@ object Shade { } object Dimensions { val ScrimCornerSize = 32.dp val HorizontalPadding = 16.dp val ScrimOverscrollLimit = 32.dp const val ScrimVisibilityThreshold = 5f } object Shapes { val Scrim = RoundedCornerShape( topStart = Dimensions.ScrimCornerSize, topEnd = Dimensions.ScrimCornerSize, ) } } /** The shade scene shows scrolling list of notifications and some of the quick setting tiles. */ @OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class ShadeScene @Inject Loading Loading @@ -197,11 +184,11 @@ constructor( ) init { qqsMediaHost.expansion = MediaHostState.EXPANDED qqsMediaHost.expansion = EXPANDED qqsMediaHost.showsOnlyActiveMedia = true qqsMediaHost.init(MediaHierarchyManager.LOCATION_QQS) qsMediaHost.expansion = MediaHostState.EXPANDED qsMediaHost.expansion = EXPANDED qsMediaHost.showsOnlyActiveMedia = false qsMediaHost.init(MediaHierarchyManager.LOCATION_QS) } Loading Loading @@ -329,8 +316,7 @@ private fun SceneScope.SingleShade( modifier = modifier.thenIf(shouldPunchHoleBehindScrim) { // Render the scene to an offscreen buffer so that BlendMode.DstOut only clears this // scene // (and not the one under it) during a scene transition. // scene (and not the one under it) during a scene transition. Modifier.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen) } ) { Loading Loading @@ -382,8 +368,8 @@ private fun SceneScope.SingleShade( stackScrollView = notificationStackScrollView, viewModel = notificationsPlaceholderViewModel, maxScrimTop = { maxNotifScrimTop.toFloat() }, shadeMode = ShadeMode.Single, shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim, supportNestedScrolling = true, onEmptySpaceClick = viewModel::onEmptySpaceClicked.takeIf { isEmptySpaceClickable }, modifier = Loading Loading @@ -601,7 +587,7 @@ private fun SceneScope.SplitShade( maxScrimTop = { 0f }, shouldPunchHoleBehindScrim = false, shouldReserveSpaceForNavBar = false, shadeMode = ShadeMode.Split, supportNestedScrolling = false, onEmptySpaceClick = viewModel::onEmptySpaceClicked.takeIf { isEmptySpaceClickable }, modifier = Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +33 −56 Original line number Diff line number Diff line Loading @@ -47,7 +47,6 @@ import androidx.compose.foundation.layout.windowInsetsBottomHeight import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect import androidx.compose.runtime.LaunchedEffect Loading @@ -60,7 +59,6 @@ import androidx.compose.runtime.setValue import androidx.compose.runtime.snapshotFlow import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.drawBehind import androidx.compose.ui.graphics.BlendMode import androidx.compose.ui.graphics.Color Loading @@ -70,7 +68,6 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.layout.LayoutCoordinates import androidx.compose.ui.layout.boundsInWindow import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onPlaced import androidx.compose.ui.layout.onSizeChanged import androidx.compose.ui.layout.positionInWindow import androidx.compose.ui.platform.LocalConfiguration Loading @@ -82,6 +79,7 @@ import androidx.compose.ui.unit.Velocity import androidx.compose.ui.unit.dp import androidx.compose.ui.util.lerp import androidx.lifecycle.compose.collectAsStateWithLifecycle import com.android.compose.animation.scene.ContentKey import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.LowestZIndexContentPicker import com.android.compose.animation.scene.NestedScrollBehavior Loading @@ -93,8 +91,9 @@ import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadi import com.android.systemui.res.R import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.session.ui.composable.rememberSession import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.shared.flag.DualShade import com.android.systemui.shade.ui.composable.ShadeHeader import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimBounds import com.android.systemui.statusbar.notification.stack.shared.model.ShadeScrimRounding Loading @@ -112,18 +111,16 @@ object Notifications { val NotificationStackPlaceholder = ElementKey("NotificationStackPlaceholder") val HeadsUpNotificationPlaceholder = ElementKey("HeadsUpNotificationPlaceholder", contentPicker = LowestZIndexContentPicker) val ShelfSpace = ElementKey("ShelfSpace") val NotificationStackCutoffGuideline = ElementKey("NotificationStackCutoffGuideline") } // Expansion fraction thresholds (between 0-1f) at which the corresponding value should be // at its maximum, given they are at their minimum value at expansion = 0f. object TransitionThresholds { const val EXPANSION_FOR_MAX_CORNER_RADIUS = 0.1f const val EXPANSION_FOR_MAX_SCRIM_ALPHA = 0.3f } } private val notificationsShadeContentKey: ContentKey get() = if (DualShade.isEnabled) Overlays.NotificationsShade else Scenes.Shade private val quickSettingsShadeContentKey: ContentKey get() = if (DualShade.isEnabled) Overlays.QuickSettingsShade else Scenes.QuickSettings /** * Adds the space where heads up notifications can appear in the scene. This should generally be the * entire size of the scene. Loading @@ -146,7 +143,7 @@ fun SceneScope.HeadsUpNotificationSpace( // This element is sometimes opted out of the shared element system, so there // can be multiple instances of it during a transition. Thus we need to // determine which instance should feed its bounds to NSSL to avoid providing // conflicting values // conflicting values. val useBounds = useHunBounds() if (useBounds) { val positionInWindow = coordinates.positionInWindow() Loading @@ -157,8 +154,8 @@ fun SceneScope.HeadsUpNotificationSpace( " bounds=$boundsInWindow" } // Note: boundsInWindow doesn't scroll off the screen, so use // positionInWindow // for top bound, which can scroll off screen while snoozing // positionInWindow for top bound, which can scroll off screen while // snoozing. stackScrollView.setHeadsUpTop(positionInWindow.y) stackScrollView.setHeadsUpBottom(boundsInWindow.bottom) } Loading Loading @@ -285,7 +282,8 @@ fun SceneScope.NotificationScrollingStack( shouldFillMaxSize: Boolean = true, shouldReserveSpaceForNavBar: Boolean = true, shouldIncludeHeadsUpSpace: Boolean = true, shadeMode: ShadeMode, shouldShowScrim: Boolean = true, supportNestedScrolling: Boolean, onEmptySpaceClick: (() -> Unit)? = null, modifier: Modifier = Modifier, ) { Loading @@ -293,6 +291,7 @@ fun SceneScope.NotificationScrollingStack( val density = LocalDensity.current val screenCornerRadius = LocalScreenCornerRadius.current val scrimCornerRadius = dimensionResource(R.dimen.notification_scrim_corner_radius) val scrimBackgroundColor = MaterialTheme.colorScheme.surface val scrollState = shadeSession.rememberSaveableSession(saver = ScrollState.Saver, key = null) { ScrollState(initial = 0) Loading Loading @@ -427,8 +426,14 @@ fun SceneScope.NotificationScrollingStack( // completes. if ( scrimOffset.value < 0 && layoutState.isTransitioning(from = Scenes.Shade, to = Scenes.Gone) || layoutState.isTransitioning(from = Scenes.Shade, to = Scenes.Lockscreen) (layoutState.isTransitioning( from = notificationsShadeContentKey, to = Scenes.Gone, ) || layoutState.isTransitioning( from = notificationsShadeContentKey, to = Scenes.Lockscreen, )) ) { IntOffset(x = 0, y = (scrimOffset.value * expansionFraction).roundToInt()) } else if ( Loading Loading @@ -498,7 +503,7 @@ fun SceneScope.NotificationScrollingStack( (expansionFraction / EXPANSION_FOR_MAX_SCRIM_ALPHA).coerceAtMost(1f) } else 1f } .background(MaterialTheme.colorScheme.surface) .thenIf(shouldShowScrim) { Modifier.background(scrimBackgroundColor) } .thenIf(shouldFillMaxSize) { Modifier.fillMaxSize() } .debugBackground(viewModel, DEBUG_BOX_COLOR) ) { Loading @@ -508,7 +513,7 @@ fun SceneScope.NotificationScrollingStack( topBehavior = NestedScrollBehavior.EdgeWithPreview, isExternalOverscrollGesture = { isCurrentGestureOverscroll.value }, ) .thenIf(shadeMode == ShadeMode.Single) { .thenIf(supportNestedScrolling) { Modifier.nestedScroll(scrimNestedScrollConnection) } .stackVerticalOverscroll(coroutineScope) { scrollState.canScrollForward } Loading Loading @@ -549,38 +554,6 @@ fun SceneScope.NotificationScrollingStack( } } /** * 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() .onPlaced { coordinates: LayoutCoordinates -> debugLog(viewModel) { ("SHELF onPlaced:" + " size=${coordinates.size}" + " bounds=${coordinates.boundsInWindow()}") } } .clip(RoundedCornerShape(24.dp)) .background(MaterialTheme.colorScheme.primaryContainer) .padding(16.dp), style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.onPrimaryContainer, ) } /** * A 0 height horizontal spacer to be placed at the bottom-most position in the current scene, where * the notification contents (stack, footer, shelf) should be drawn. Loading Loading @@ -673,15 +646,19 @@ private suspend fun scrollNotificationStack( } } private fun TransitionState.isOnLockscreen(): Boolean { return currentScene == Scenes.Lockscreen && currentOverlays.isEmpty() } private fun shouldUseLockscreenStackBounds(state: TransitionState): Boolean { return state is TransitionState.Idle && state.currentScene == Scenes.Lockscreen return state is TransitionState.Idle && state.isOnLockscreen() } private fun shouldUseLockscreenHunBounds(state: TransitionState): Boolean { return when (state) { is TransitionState.Idle -> state.currentScene == Scenes.Lockscreen is TransitionState.Idle -> state.isOnLockscreen() is TransitionState.Transition -> state.isTransitioning(from = Scenes.QuickSettings, to = Scenes.Lockscreen) state.isTransitioning(from = quickSettingsShadeContentKey, to = Scenes.Lockscreen) } } Loading @@ -690,7 +667,7 @@ private fun shouldAnimateScrimCornerRadius( shouldPunchHoleBehindScrim: Boolean, ): Boolean { return shouldPunchHoleBehindScrim || state.isTransitioning(from = Scenes.Shade, to = Scenes.Lockscreen) state.isTransitioning(from = notificationsShadeContentKey, to = Scenes.Lockscreen) } private fun calculateCornerRadius( Loading
packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/NotificationsShadeOverlay.kt +4 −9 Original line number Diff line number Diff line Loading @@ -33,7 +33,6 @@ import com.android.systemui.notifications.ui.viewmodel.NotificationsShadeOverlay import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.shared.model.Overlays import com.android.systemui.scene.ui.composable.Overlay import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.ui.composable.ExpandedShadeHeader import com.android.systemui.shade.ui.composable.OverlayShade import com.android.systemui.statusbar.notification.stack.ui.view.NotificationScrollView Loading Loading @@ -69,9 +68,7 @@ constructor( } @Composable override fun ContentScope.Content( modifier: Modifier, ) { override fun ContentScope.Content(modifier: Modifier) { val viewModel = rememberViewModel("NotificationsShadeOverlay-viewModel") { contentViewModelFactory.create() Loading @@ -81,10 +78,7 @@ constructor( viewModel.notificationsPlaceholderViewModelFactory.create() } OverlayShade( modifier = modifier, onScrimClicked = viewModel::onScrimClicked, ) { OverlayShade(modifier = modifier, onScrimClicked = viewModel::onScrimClicked) { Column { ExpandedShadeHeader( viewModelFactory = viewModel.shadeHeaderViewModelFactory, Loading @@ -102,7 +96,8 @@ constructor( shouldPunchHoleBehindScrim = false, shouldFillMaxSize = false, shouldReserveSpaceForNavBar = false, shadeMode = ShadeMode.Dual, shouldShowScrim = false, supportNestedScrolling = false, modifier = Modifier.fillMaxWidth(), ) Loading
packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +1 −4 Original line number Diff line number Diff line Loading @@ -100,7 +100,6 @@ import com.android.systemui.res.R import com.android.systemui.scene.session.ui.composable.SaveableSession import com.android.systemui.scene.shared.model.Scenes import com.android.systemui.scene.ui.composable.Scene import com.android.systemui.shade.shared.model.ShadeMode import com.android.systemui.shade.ui.composable.CollapsedShadeHeader import com.android.systemui.shade.ui.composable.ExpandedShadeHeader import com.android.systemui.shade.ui.composable.Shade Loading @@ -114,11 +113,9 @@ import dagger.Lazy import javax.inject.Inject import javax.inject.Named import kotlin.math.roundToInt import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow /** The Quick Settings (AKA "QS") scene shows the quick setting tiles. */ @OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class QuickSettingsScene @Inject Loading Loading @@ -427,7 +424,7 @@ private fun SceneScope.QuickSettingsScene( maxScrimTop = { screenHeight }, shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim, shouldIncludeHeadsUpSpace = false, shadeMode = ShadeMode.Single, supportNestedScrolling = true, modifier = Modifier.fillMaxWidth() .offset { IntOffset(x = 0, y = screenHeight.roundToInt()) } Loading
packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt +2 −8 Original line number Diff line number Diff line Loading @@ -21,26 +21,20 @@ import androidx.compose.animation.core.spring import androidx.compose.animation.core.tween import com.android.compose.animation.scene.Edge import com.android.compose.animation.scene.TransitionBuilder import com.android.compose.animation.scene.UserActionDistance import com.android.systemui.notifications.ui.composable.Notifications import com.android.systemui.shade.ui.composable.OverlayShade import com.android.systemui.shade.ui.composable.Shade import com.android.systemui.shade.ui.composable.ShadeHeader import kotlin.time.Duration.Companion.milliseconds fun TransitionBuilder.toNotificationsShadeTransition( durationScale: Double = 1.0, ) { fun TransitionBuilder.toNotificationsShadeTransition(durationScale: Double = 1.0) { spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt()) swipeSpec = spring( stiffness = Spring.StiffnessMediumLow, visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold, ) distance = UserActionDistance { fromSceneSize, orientation -> fromSceneSize.height.toFloat() * 2 / 3f } scaleSize(OverlayShade.Elements.Panel, height = 0f) translate(OverlayShade.Elements.Panel, Edge.Top) fractionRange(end = .5f) { fade(OverlayShade.Elements.Scrim) } Loading
packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +5 −19 Original line number Diff line number Diff line Loading @@ -40,7 +40,6 @@ import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBars import androidx.compose.foundation.rememberScrollState import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.DisposableEffect Loading Loading @@ -89,7 +88,6 @@ import com.android.systemui.media.controls.ui.composable.shouldElevateMedia import com.android.systemui.media.controls.ui.controller.MediaCarouselController import com.android.systemui.media.controls.ui.controller.MediaHierarchyManager import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.controls.ui.view.MediaHostState import com.android.systemui.media.controls.ui.view.MediaHostState.Companion.COLLAPSED import com.android.systemui.media.controls.ui.view.MediaHostState.Companion.EXPANDED import com.android.systemui.media.dagger.MediaModule.QS_PANEL Loading Loading @@ -117,7 +115,6 @@ import dagger.Lazy import javax.inject.Inject import javax.inject.Named import kotlin.math.roundToInt import kotlinx.coroutines.ExperimentalCoroutinesApi import kotlinx.coroutines.flow.Flow object Shade { Loading @@ -128,23 +125,13 @@ object Shade { } object Dimensions { val ScrimCornerSize = 32.dp val HorizontalPadding = 16.dp val ScrimOverscrollLimit = 32.dp const val ScrimVisibilityThreshold = 5f } object Shapes { val Scrim = RoundedCornerShape( topStart = Dimensions.ScrimCornerSize, topEnd = Dimensions.ScrimCornerSize, ) } } /** The shade scene shows scrolling list of notifications and some of the quick setting tiles. */ @OptIn(ExperimentalCoroutinesApi::class) @SysUISingleton class ShadeScene @Inject Loading Loading @@ -197,11 +184,11 @@ constructor( ) init { qqsMediaHost.expansion = MediaHostState.EXPANDED qqsMediaHost.expansion = EXPANDED qqsMediaHost.showsOnlyActiveMedia = true qqsMediaHost.init(MediaHierarchyManager.LOCATION_QQS) qsMediaHost.expansion = MediaHostState.EXPANDED qsMediaHost.expansion = EXPANDED qsMediaHost.showsOnlyActiveMedia = false qsMediaHost.init(MediaHierarchyManager.LOCATION_QS) } Loading Loading @@ -329,8 +316,7 @@ private fun SceneScope.SingleShade( modifier = modifier.thenIf(shouldPunchHoleBehindScrim) { // Render the scene to an offscreen buffer so that BlendMode.DstOut only clears this // scene // (and not the one under it) during a scene transition. // scene (and not the one under it) during a scene transition. Modifier.graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen) } ) { Loading Loading @@ -382,8 +368,8 @@ private fun SceneScope.SingleShade( stackScrollView = notificationStackScrollView, viewModel = notificationsPlaceholderViewModel, maxScrimTop = { maxNotifScrimTop.toFloat() }, shadeMode = ShadeMode.Single, shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim, supportNestedScrolling = true, onEmptySpaceClick = viewModel::onEmptySpaceClicked.takeIf { isEmptySpaceClickable }, modifier = Loading Loading @@ -601,7 +587,7 @@ private fun SceneScope.SplitShade( maxScrimTop = { 0f }, shouldPunchHoleBehindScrim = false, shouldReserveSpaceForNavBar = false, shadeMode = ShadeMode.Split, supportNestedScrolling = false, onEmptySpaceClick = viewModel::onEmptySpaceClicked.takeIf { isEmptySpaceClickable }, modifier = Loading