Loading packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +22 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.notifications.ui.composable import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.gestures.scrollBy import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets Loading Loading @@ -140,6 +141,8 @@ fun SceneScope.NotificationScrollingStack( ) { val density = LocalDensity.current val screenCornerRadius = LocalScreenCornerRadius.current val scrollState = rememberScrollState() val syntheticScroll = viewModel.syntheticScroll.collectAsState(0f) val expansionFraction by viewModel.expandFraction.collectAsState(0f) val navBarHeight = Loading Loading @@ -180,11 +183,28 @@ fun SceneScope.NotificationScrollingStack( // if contentHeight drops below minimum visible scrim height while scrim is // expanded, reset scrim offset. LaunchedEffect(contentHeight, screenHeight, maxScrimTop, scrimOffset) { LaunchedEffect(contentHeight, scrimOffset) { snapshotFlow { contentHeight.value < minVisibleScrimHeight() && scrimOffset.value < 0f } .collect { shouldCollapse -> if (shouldCollapse) scrimOffset.value = 0f } } // if we receive scroll delta from NSSL, offset the scrim and placeholder accordingly. LaunchedEffect(syntheticScroll, scrimOffset, scrollState) { snapshotFlow { syntheticScroll.value } .collect { delta -> val minOffset = minScrimOffset() if (scrimOffset.value > minOffset) { val remainingDelta = (minOffset - (scrimOffset.value - delta)).coerceAtLeast(0f) scrimOffset.value = (scrimOffset.value - delta).coerceAtLeast(minOffset) if (remainingDelta > 0f) { scrollState.scrollBy(remainingDelta) } } else { scrollState.scrollTo(delta.roundToInt()) } } } Box( modifier = modifier Loading Loading @@ -260,7 +280,7 @@ fun SceneScope.NotificationScrollingStack( ) } ) .verticalScroll(rememberScrollState()) .verticalScroll(scrollState) .fillMaxWidth() .height { (contentHeight.value + navBarHeight).roundToInt() }, ) Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +10 −0 Original line number Diff line number Diff line Loading @@ -4363,6 +4363,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable layoutEnd -= mShelf.getIntrinsicHeight() + mPaddingBetweenElements; } if (endPosition > layoutEnd) { // if Scene Container is active, send bottom notification expansion delta // to it so that it can scroll the stack and scrim accordingly. if (SceneContainerFlag.isEnabled()) { float diff = endPosition - layoutEnd; mController.sendSyntheticScrollToSceneFramework(diff); } setOwnScrollY((int) (mOwnScrollY + endPosition - layoutEnd)); mDisallowScrollingInThisMotion = true; } Loading Loading @@ -5081,6 +5087,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } private void setOwnScrollY(int ownScrollY, boolean animateStackYChangeListener) { // If scene container is active, NSSL should not control its own scrolling. if (SceneContainerFlag.isEnabled()) { return; } // Avoid Flicking during clear all // when the shade finishes closing, onExpansionStopped will call // resetScrollPosition to setOwnScrollY to 0 Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +5 −0 Original line number Diff line number Diff line Loading @@ -1151,6 +1151,11 @@ public class NotificationStackScrollLayoutController implements Dumpable { } } /** Send internal notification expansion to the scene container framework. */ public void sendSyntheticScrollToSceneFramework(Float delta) { mStackAppearanceInteractor.setSyntheticScroll(delta); } /** Get the y-coordinate of the top bound of the stack. */ public float getPlaceholderTop() { return mStackAppearanceInteractor.getStackBounds().getValue().getTop(); Loading packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationStackAppearanceRepository.kt +7 −0 Original line number Diff line number Diff line Loading @@ -47,4 +47,11 @@ class NotificationStackAppearanceRepository @Inject constructor() { * further. */ val scrolledToTop = MutableStateFlow(true) /** * The amount in px that the notification stack should scroll due to internal expansion. This * should only happen when a notification expansion hits the bottom of the screen, so it is * necessary to scroll up to keep expanding the notification. */ val syntheticScroll = MutableStateFlow(0f) } packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt +13 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import com.android.systemui.common.shared.model.NotificationContainerBounds import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.notification.stack.data.repository.NotificationStackAppearanceRepository import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow Loading Loading @@ -50,6 +51,13 @@ constructor( */ val scrolledToTop: StateFlow<Boolean> = repository.scrolledToTop.asStateFlow() /** * The amount in px that the notification stack should scroll due to internal expansion. This * should only happen when a notification expansion hits the bottom of the screen, so it is * necessary to scroll up to keep expanding the notification. */ val syntheticScroll: Flow<Float> = repository.syntheticScroll.asStateFlow() /** Sets the position of the notification stack in the current scene. */ fun setStackBounds(bounds: NotificationContainerBounds) { check(bounds.top <= bounds.bottom) { "Invalid bounds: $bounds" } Loading @@ -70,4 +78,9 @@ constructor( fun setScrolledToTop(scrolledToTop: Boolean) { repository.scrolledToTop.value = scrolledToTop } /** Sets the amount (px) that the notification stack should scroll due to internal expansion. */ fun setSyntheticScroll(delta: Float) { repository.syntheticScroll.value = delta } } Loading
packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +22 −2 Original line number Diff line number Diff line Loading @@ -19,6 +19,7 @@ package com.android.systemui.notifications.ui.composable import android.util.Log import androidx.compose.foundation.background import androidx.compose.foundation.gestures.scrollBy import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.WindowInsets Loading Loading @@ -140,6 +141,8 @@ fun SceneScope.NotificationScrollingStack( ) { val density = LocalDensity.current val screenCornerRadius = LocalScreenCornerRadius.current val scrollState = rememberScrollState() val syntheticScroll = viewModel.syntheticScroll.collectAsState(0f) val expansionFraction by viewModel.expandFraction.collectAsState(0f) val navBarHeight = Loading Loading @@ -180,11 +183,28 @@ fun SceneScope.NotificationScrollingStack( // if contentHeight drops below minimum visible scrim height while scrim is // expanded, reset scrim offset. LaunchedEffect(contentHeight, screenHeight, maxScrimTop, scrimOffset) { LaunchedEffect(contentHeight, scrimOffset) { snapshotFlow { contentHeight.value < minVisibleScrimHeight() && scrimOffset.value < 0f } .collect { shouldCollapse -> if (shouldCollapse) scrimOffset.value = 0f } } // if we receive scroll delta from NSSL, offset the scrim and placeholder accordingly. LaunchedEffect(syntheticScroll, scrimOffset, scrollState) { snapshotFlow { syntheticScroll.value } .collect { delta -> val minOffset = minScrimOffset() if (scrimOffset.value > minOffset) { val remainingDelta = (minOffset - (scrimOffset.value - delta)).coerceAtLeast(0f) scrimOffset.value = (scrimOffset.value - delta).coerceAtLeast(minOffset) if (remainingDelta > 0f) { scrollState.scrollBy(remainingDelta) } } else { scrollState.scrollTo(delta.roundToInt()) } } } Box( modifier = modifier Loading Loading @@ -260,7 +280,7 @@ fun SceneScope.NotificationScrollingStack( ) } ) .verticalScroll(rememberScrollState()) .verticalScroll(scrollState) .fillMaxWidth() .height { (contentHeight.value + navBarHeight).roundToInt() }, ) Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java +10 −0 Original line number Diff line number Diff line Loading @@ -4363,6 +4363,12 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable layoutEnd -= mShelf.getIntrinsicHeight() + mPaddingBetweenElements; } if (endPosition > layoutEnd) { // if Scene Container is active, send bottom notification expansion delta // to it so that it can scroll the stack and scrim accordingly. if (SceneContainerFlag.isEnabled()) { float diff = endPosition - layoutEnd; mController.sendSyntheticScrollToSceneFramework(diff); } setOwnScrollY((int) (mOwnScrollY + endPosition - layoutEnd)); mDisallowScrollingInThisMotion = true; } Loading Loading @@ -5081,6 +5087,10 @@ public class NotificationStackScrollLayout extends ViewGroup implements Dumpable } private void setOwnScrollY(int ownScrollY, boolean animateStackYChangeListener) { // If scene container is active, NSSL should not control its own scrolling. if (SceneContainerFlag.isEnabled()) { return; } // Avoid Flicking during clear all // when the shade finishes closing, onExpansionStopped will call // resetScrollPosition to setOwnScrollY to 0 Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutController.java +5 −0 Original line number Diff line number Diff line Loading @@ -1151,6 +1151,11 @@ public class NotificationStackScrollLayoutController implements Dumpable { } } /** Send internal notification expansion to the scene container framework. */ public void sendSyntheticScrollToSceneFramework(Float delta) { mStackAppearanceInteractor.setSyntheticScroll(delta); } /** Get the y-coordinate of the top bound of the stack. */ public float getPlaceholderTop() { return mStackAppearanceInteractor.getStackBounds().getValue().getTop(); Loading
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/data/repository/NotificationStackAppearanceRepository.kt +7 −0 Original line number Diff line number Diff line Loading @@ -47,4 +47,11 @@ class NotificationStackAppearanceRepository @Inject constructor() { * further. */ val scrolledToTop = MutableStateFlow(true) /** * The amount in px that the notification stack should scroll due to internal expansion. This * should only happen when a notification expansion hits the bottom of the screen, so it is * necessary to scroll up to keep expanding the notification. */ val syntheticScroll = MutableStateFlow(0f) }
packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/domain/interactor/NotificationStackAppearanceInteractor.kt +13 −0 Original line number Diff line number Diff line Loading @@ -21,6 +21,7 @@ import com.android.systemui.common.shared.model.NotificationContainerBounds import com.android.systemui.dagger.SysUISingleton import com.android.systemui.statusbar.notification.stack.data.repository.NotificationStackAppearanceRepository import javax.inject.Inject import kotlinx.coroutines.flow.Flow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow Loading Loading @@ -50,6 +51,13 @@ constructor( */ val scrolledToTop: StateFlow<Boolean> = repository.scrolledToTop.asStateFlow() /** * The amount in px that the notification stack should scroll due to internal expansion. This * should only happen when a notification expansion hits the bottom of the screen, so it is * necessary to scroll up to keep expanding the notification. */ val syntheticScroll: Flow<Float> = repository.syntheticScroll.asStateFlow() /** Sets the position of the notification stack in the current scene. */ fun setStackBounds(bounds: NotificationContainerBounds) { check(bounds.top <= bounds.bottom) { "Invalid bounds: $bounds" } Loading @@ -70,4 +78,9 @@ constructor( fun setScrolledToTop(scrolledToTop: Boolean) { repository.scrolledToTop.value = scrolledToTop } /** Sets the amount (px) that the notification stack should scroll due to internal expansion. */ fun setSyntheticScroll(delta: Float) { repository.syntheticScroll.value = delta } }