Loading packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +36 −7 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBars Loading Loading @@ -155,6 +156,11 @@ fun SceneScope.ConstrainedNotificationStack( viewModel = viewModel, modifier = Modifier.align(Alignment.TopCenter), ) NotificationStackCutoffGuideline( stackScrollView = stackScrollView, viewModel = viewModel, modifier = Modifier.align(Alignment.BottomCenter), ) } } Loading Loading @@ -187,8 +193,12 @@ fun SceneScope.NotificationScrollingStack( viewModel.isCurrentGestureOverscroll.collectAsStateWithLifecycle(false) val expansionFraction by viewModel.expandFraction.collectAsStateWithLifecycle(0f) val navBarHeight = with(density) { WindowInsets.systemBars.asPaddingValues().calculateBottomPadding().toPx() } val navBarHeightPx = with(density) { WindowInsets.systemBars.asPaddingValues().calculateBottomPadding().toPx().toInt() } val bottomPaddingPx = if (shouldReserveSpaceForNavBar) navBarHeightPx else 0 val screenHeight = LocalRawScreenHeight.current /** Loading Loading @@ -352,10 +362,7 @@ fun SceneScope.NotificationScrollingStack( } .verticalScroll(scrollState) .fillMaxWidth() .notificationStackHeight( view = stackScrollView, padding = if (shouldReserveSpaceForNavBar) navBarHeight.toInt() else 0 ) .notificationStackHeight(view = stackScrollView, padding = bottomPaddingPx) .onSizeChanged { size -> stackHeight.intValue = size.height }, ) } Loading Loading @@ -395,6 +402,29 @@ fun SceneScope.NotificationShelfSpace( ) } /** * 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. */ @Composable fun NotificationStackCutoffGuideline( stackScrollView: NotificationScrollView, viewModel: NotificationsPlaceholderViewModel, modifier: Modifier = Modifier, ) { Spacer( modifier = modifier .fillMaxWidth() .height(0.dp) .onGloballyPositioned { coordinates -> val positionY = coordinates.positionInWindow().y debugLog(viewModel) { "STACK cutoff onGloballyPositioned: y=$positionY" } stackScrollView.setStackCutoff(positionY) } ) } @Composable private fun SceneScope.NotificationPlaceholder( stackScrollView: NotificationScrollView, Loading @@ -417,7 +447,6 @@ private fun SceneScope.NotificationPlaceholder( } // NOTE: positionInWindow.y scrolls off screen, but boundsInWindow.top will not stackScrollView.setStackTop(positionInWindow.y) stackScrollView.setStackBottom(positionInWindow.y + coordinates.size.height) } ) } Loading packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +13 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState Loading Loading @@ -82,6 +83,7 @@ import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.controls.ui.view.MediaHostState import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL import com.android.systemui.notifications.ui.composable.NotificationScrollingStack import com.android.systemui.notifications.ui.composable.NotificationStackCutoffGuideline import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility import com.android.systemui.qs.ui.composable.BrightnessMirror import com.android.systemui.qs.ui.composable.QSMediaMeasurePolicy Loading Loading @@ -350,6 +352,11 @@ private fun SceneScope.SingleShade( notificationsPlaceable.placeRelative(x = 0, y = maxNotifScrimTop.value.roundToInt()) } } NotificationStackCutoffGuideline( stackScrollView = notificationStackScrollView, viewModel = viewModel.notifications, modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding() ) } } Loading Loading @@ -529,6 +536,7 @@ private fun SceneScope.SplitShade( viewModel = viewModel.notifications, maxScrimTop = { 0f }, shouldPunchHoleBehindScrim = false, shouldReserveSpaceForNavBar = false, shadeMode = ShadeMode.Split, modifier = Modifier.weight(1f) Loading @@ -538,5 +546,10 @@ private fun SceneScope.SplitShade( ) } } NotificationStackCutoffGuideline( stackScrollView = notificationStackScrollView, viewModel = viewModel.notifications, modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding() ) } } packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +4 −4 Original line number Diff line number Diff line Loading @@ -837,8 +837,8 @@ public class NotificationStackScrollLayout y = (int) mScrollViewFields.getStackTop(); drawDebugInfo(canvas, y, Color.RED, /* label= */ "getStackTop() = " + y); y = (int) mScrollViewFields.getStackBottom(); drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "getStackBottom() = " + y); y = (int) mScrollViewFields.getStackCutoff(); drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "getStackCutoff() = " + y); y = (int) mScrollViewFields.getHeadsUpTop(); drawDebugInfo(canvas, y, Color.GREEN, /* label= */ "getHeadsUpTop() = " + y); Loading Loading @@ -1220,8 +1220,8 @@ public class NotificationStackScrollLayout } @Override public void setStackBottom(float stackBottom) { mScrollViewFields.setStackBottom(stackBottom); public void setStackCutoff(float stackCutoff) { mScrollViewFields.setStackCutoff(stackCutoff); } @Override Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt +2 −2 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ class ScrollViewFields { * Y coordinate in view pixels above which the bottom of the notification stack / shelf / footer * must be. */ var stackBottom: Float = 0f var stackCutoff: Float = 0f /** Y coordinate in view pixels of the top of the HUN */ var headsUpTop: Float = 0f /** Whether the notifications are scrolled all the way to the top (i.e. when freshly opened) */ Loading Loading @@ -80,7 +80,7 @@ class ScrollViewFields { pw.printSection("StackViewStates") { pw.println("scrimClippingShape", scrimClippingShape) pw.println("stackTop", stackTop) pw.println("stackBottom", stackBottom) pw.println("stackCutoff", stackCutoff) pw.println("headsUpTop", headsUpTop) pw.println("isScrolledToTop", isScrolledToTop) } Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt +5 −2 Original line number Diff line number Diff line Loading @@ -50,8 +50,11 @@ interface NotificationScrollView { /** set the y position in px of the top of the stack in this view's coordinates */ fun setStackTop(stackTop: Float) /** set the y position in px of the bottom of the stack in this view's coordinates */ fun setStackBottom(stackBottom: Float) /** * set the bottom-most acceptable y-position of the bottom of the notification stack/ shelf / * footer. */ fun setStackCutoff(stackBottom: Float) /** set the y position in px of the top of the HUN in this view's coordinates */ fun setHeadsUpTop(headsUpTop: Float) Loading Loading
packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +36 −7 Original line number Diff line number Diff line Loading @@ -28,6 +28,7 @@ import androidx.compose.foundation.layout.WindowInsets import androidx.compose.foundation.layout.asPaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.systemBars Loading Loading @@ -155,6 +156,11 @@ fun SceneScope.ConstrainedNotificationStack( viewModel = viewModel, modifier = Modifier.align(Alignment.TopCenter), ) NotificationStackCutoffGuideline( stackScrollView = stackScrollView, viewModel = viewModel, modifier = Modifier.align(Alignment.BottomCenter), ) } } Loading Loading @@ -187,8 +193,12 @@ fun SceneScope.NotificationScrollingStack( viewModel.isCurrentGestureOverscroll.collectAsStateWithLifecycle(false) val expansionFraction by viewModel.expandFraction.collectAsStateWithLifecycle(0f) val navBarHeight = with(density) { WindowInsets.systemBars.asPaddingValues().calculateBottomPadding().toPx() } val navBarHeightPx = with(density) { WindowInsets.systemBars.asPaddingValues().calculateBottomPadding().toPx().toInt() } val bottomPaddingPx = if (shouldReserveSpaceForNavBar) navBarHeightPx else 0 val screenHeight = LocalRawScreenHeight.current /** Loading Loading @@ -352,10 +362,7 @@ fun SceneScope.NotificationScrollingStack( } .verticalScroll(scrollState) .fillMaxWidth() .notificationStackHeight( view = stackScrollView, padding = if (shouldReserveSpaceForNavBar) navBarHeight.toInt() else 0 ) .notificationStackHeight(view = stackScrollView, padding = bottomPaddingPx) .onSizeChanged { size -> stackHeight.intValue = size.height }, ) } Loading Loading @@ -395,6 +402,29 @@ fun SceneScope.NotificationShelfSpace( ) } /** * 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. */ @Composable fun NotificationStackCutoffGuideline( stackScrollView: NotificationScrollView, viewModel: NotificationsPlaceholderViewModel, modifier: Modifier = Modifier, ) { Spacer( modifier = modifier .fillMaxWidth() .height(0.dp) .onGloballyPositioned { coordinates -> val positionY = coordinates.positionInWindow().y debugLog(viewModel) { "STACK cutoff onGloballyPositioned: y=$positionY" } stackScrollView.setStackCutoff(positionY) } ) } @Composable private fun SceneScope.NotificationPlaceholder( stackScrollView: NotificationScrollView, Loading @@ -417,7 +447,6 @@ private fun SceneScope.NotificationPlaceholder( } // NOTE: positionInWindow.y scrolls off screen, but boundsInWindow.top will not stackScrollView.setStackTop(positionInWindow.y) stackScrollView.setStackBottom(positionInWindow.y + coordinates.size.height) } ) } Loading
packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +13 −0 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ import androidx.compose.foundation.layout.fillMaxHeight import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.navigationBars import androidx.compose.foundation.layout.navigationBarsPadding import androidx.compose.foundation.layout.offset import androidx.compose.foundation.layout.padding import androidx.compose.foundation.rememberScrollState Loading Loading @@ -82,6 +83,7 @@ import com.android.systemui.media.controls.ui.view.MediaHost import com.android.systemui.media.controls.ui.view.MediaHostState import com.android.systemui.media.dagger.MediaModule.QUICK_QS_PANEL import com.android.systemui.notifications.ui.composable.NotificationScrollingStack import com.android.systemui.notifications.ui.composable.NotificationStackCutoffGuideline import com.android.systemui.qs.footer.ui.compose.FooterActionsWithAnimatedVisibility import com.android.systemui.qs.ui.composable.BrightnessMirror import com.android.systemui.qs.ui.composable.QSMediaMeasurePolicy Loading Loading @@ -350,6 +352,11 @@ private fun SceneScope.SingleShade( notificationsPlaceable.placeRelative(x = 0, y = maxNotifScrimTop.value.roundToInt()) } } NotificationStackCutoffGuideline( stackScrollView = notificationStackScrollView, viewModel = viewModel.notifications, modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding() ) } } Loading Loading @@ -529,6 +536,7 @@ private fun SceneScope.SplitShade( viewModel = viewModel.notifications, maxScrimTop = { 0f }, shouldPunchHoleBehindScrim = false, shouldReserveSpaceForNavBar = false, shadeMode = ShadeMode.Split, modifier = Modifier.weight(1f) Loading @@ -538,5 +546,10 @@ private fun SceneScope.SplitShade( ) } } NotificationStackCutoffGuideline( stackScrollView = notificationStackScrollView, viewModel = viewModel.notifications, modifier = Modifier.align(Alignment.BottomCenter).navigationBarsPadding() ) } }
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +4 −4 Original line number Diff line number Diff line Loading @@ -837,8 +837,8 @@ public class NotificationStackScrollLayout y = (int) mScrollViewFields.getStackTop(); drawDebugInfo(canvas, y, Color.RED, /* label= */ "getStackTop() = " + y); y = (int) mScrollViewFields.getStackBottom(); drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "getStackBottom() = " + y); y = (int) mScrollViewFields.getStackCutoff(); drawDebugInfo(canvas, y, Color.MAGENTA, /* label= */ "getStackCutoff() = " + y); y = (int) mScrollViewFields.getHeadsUpTop(); drawDebugInfo(canvas, y, Color.GREEN, /* label= */ "getHeadsUpTop() = " + y); Loading Loading @@ -1220,8 +1220,8 @@ public class NotificationStackScrollLayout } @Override public void setStackBottom(float stackBottom) { mScrollViewFields.setStackBottom(stackBottom); public void setStackCutoff(float stackCutoff) { mScrollViewFields.setStackCutoff(stackCutoff); } @Override Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ScrollViewFields.kt +2 −2 Original line number Diff line number Diff line Loading @@ -38,7 +38,7 @@ class ScrollViewFields { * Y coordinate in view pixels above which the bottom of the notification stack / shelf / footer * must be. */ var stackBottom: Float = 0f var stackCutoff: Float = 0f /** Y coordinate in view pixels of the top of the HUN */ var headsUpTop: Float = 0f /** Whether the notifications are scrolled all the way to the top (i.e. when freshly opened) */ Loading Loading @@ -80,7 +80,7 @@ class ScrollViewFields { pw.printSection("StackViewStates") { pw.println("scrimClippingShape", scrimClippingShape) pw.println("stackTop", stackTop) pw.println("stackBottom", stackBottom) pw.println("stackCutoff", stackCutoff) pw.println("headsUpTop", headsUpTop) pw.println("isScrolledToTop", isScrolledToTop) } Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/view/NotificationScrollView.kt +5 −2 Original line number Diff line number Diff line Loading @@ -50,8 +50,11 @@ interface NotificationScrollView { /** set the y position in px of the top of the stack in this view's coordinates */ fun setStackTop(stackTop: Float) /** set the y position in px of the bottom of the stack in this view's coordinates */ fun setStackBottom(stackBottom: Float) /** * set the bottom-most acceptable y-position of the bottom of the notification stack/ shelf / * footer. */ fun setStackCutoff(stackBottom: Float) /** set the y position in px of the top of the HUN in this view's coordinates */ fun setHeadsUpTop(headsUpTop: Float) Loading