Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4bdceb3e authored by Shawn Lee's avatar Shawn Lee
Browse files

[flexiglass] Send scroll from NSSL to flexiglass when bottom notif expands

When a notification expansion hits the bottom of the screen, we need to scroll the notif stack and scrim up to make room for the notification to fully expand. This means there needs to be a way for NSSL to pass scrolling delta to flexiglass to cover this specific case (NSSL does not reposition itself based off this delta - it waits for flexiglass to tell it how to move after having consumed the delta).

Bug: 296118689
Test: manual
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT
Change-Id: Ie7b43dbcd372c422259915457261e946a387234a
parent 601a1a2d
Loading
Loading
Loading
Loading
+22 −2
Original line number Diff line number Diff line
@@ -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
@@ -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 =
@@ -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
@@ -260,7 +280,7 @@ fun SceneScope.NotificationScrollingStack(
                                )
                            }
                        )
                        .verticalScroll(rememberScrollState())
                        .verticalScroll(scrollState)
                        .fillMaxWidth()
                        .height { (contentHeight.value + navBarHeight).roundToInt() },
            )
+10 −0
Original line number Diff line number Diff line
@@ -4359,6 +4359,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;
                }
@@ -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
+5 −0
Original line number Diff line number Diff line
@@ -1142,6 +1142,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();
+7 −0
Original line number Diff line number Diff line
@@ -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)
}
+13 −0
Original line number Diff line number Diff line
@@ -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

@@ -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" }
@@ -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