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

Commit cdf76490 authored by András Kurucz's avatar András Kurucz Committed by Android (Google) Code Review
Browse files

Merge "[Flexiglass] Don't allow scene changes by swipes while expanding notifs" into main

parents a84bd3ea 498166da
Loading
Loading
Loading
Loading
+1 −2
Original line number Diff line number Diff line
@@ -42,7 +42,6 @@ fun NotificationScrimNestedScrollConnection(
    maxScrimOffset: Float,
    contentHeight: () -> Float,
    minVisibleScrimHeight: () -> Float,
    isCurrentGestureOverscroll: () -> Boolean,
    onStart: (Float) -> Unit = {},
    onStop: (Float) -> Unit = {},
    flingBehavior: FlingBehavior,
@@ -60,7 +59,7 @@ fun NotificationScrimNestedScrollConnection(
        // scrolling down and content is done scrolling to top. After that, the scrim
        // needs to collapse; collapse the scrim until it is at the maxScrimOffset.
        canStartPostScroll = { offsetAvailable, _, _ ->
            offsetAvailable > 0 && (scrimOffset() < maxScrimOffset || isCurrentGestureOverscroll())
            offsetAvailable > 0 && (scrimOffset() < maxScrimOffset)
        },
        onStart = { firstScroll ->
            onStart(firstScroll)
+46 −8
Original line number Diff line number Diff line
@@ -70,6 +70,7 @@ import androidx.compose.ui.graphics.BlendMode
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.graphicsLayer
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
import androidx.compose.ui.input.nestedscroll.NestedScrollSource
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.layout.LayoutCoordinates
import androidx.compose.ui.layout.boundsInWindow
@@ -95,6 +96,9 @@ import com.android.compose.animation.scene.content.state.TransitionState
import com.android.compose.gesture.effect.OffsetOverscrollEffect
import com.android.compose.gesture.effect.rememberOffsetOverscrollEffect
import com.android.compose.modifiers.thenIf
import com.android.compose.nestedscroll.OnStopScope
import com.android.compose.nestedscroll.PriorityNestedScrollConnection
import com.android.compose.nestedscroll.ScrollController
import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.jank.InteractionJankMonitor.CUJ_NOTIFICATION_SHADE_SCROLL_FLING
import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadius
@@ -460,13 +464,7 @@ fun ContentScope.NotificationScrollingStack(
    }

    val scrimNestedScrollConnection =
        shadeSession.rememberSession(
            key = "ScrimConnection",
            scrimOffset,
            minScrimTop,
            viewModel.isCurrentGestureOverscroll,
            density,
        ) {
        shadeSession.rememberSession(key = "ScrimConnection", scrimOffset, minScrimTop, density) {
            val flingSpec: DecayAnimationSpec<Float> = splineBasedDecay(density)
            val flingBehavior = NotificationScrimFlingBehavior(flingSpec)
            NotificationScrimNestedScrollConnection(
@@ -479,11 +477,50 @@ fun ContentScope.NotificationScrollingStack(
                maxScrimOffset = 0f,
                contentHeight = { stackHeight.intValue.toFloat() },
                minVisibleScrimHeight = minVisibleScrimHeight,
                isCurrentGestureOverscroll = { viewModel.isCurrentGestureOverscroll },
                flingBehavior = flingBehavior,
            )
        }

    val swipeToExpandNotificationScrollConnection =
        shadeSession.rememberSession(
            key = "SwipeToExpandNotificationScrollConnection",
            scrimOffset,
            minScrimTop,
            density,
            viewModel.isCurrentGestureExpandingNotification,
        ) {
            PriorityNestedScrollConnection(
                orientation = Orientation.Vertical,
                canStartPreScroll = { _, _, _ -> false },
                canStartPostScroll = { _, _, _ -> viewModel.isCurrentGestureExpandingNotification },
                onStart = { firstScroll ->
                    object : ScrollController {
                        override fun onScroll(
                            deltaScroll: Float,
                            source: NestedScrollSource,
                        ): Float {
                            return if (viewModel.isCurrentGestureExpandingNotification) {
                                // consume all the amount, when this swipe is expanding a
                                // notification
                                deltaScroll
                            } else {
                                // don't consume anything, when the expansion is done
                                0f
                            }
                        }

                        override fun onCancel() {
                            // No-op
                        }

                        override fun canStopOnPreFling(): Boolean = false

                        override suspend fun OnStopScope.onStop(initialVelocity: Float): Float = 0f
                    }
                },
            )
        }

    val overScrollEffect: OffsetOverscrollEffect = rememberOffsetOverscrollEffect()
    // whether the stack is moving due to a swipe or fling
    val isScrollInProgress =
@@ -596,6 +633,7 @@ fun ContentScope.NotificationScrollingStack(
            Column(
                modifier =
                    Modifier.disableSwipesWhenScrolling()
                        .nestedScroll(swipeToExpandNotificationScrollConnection)
                        .thenIf(supportNestedScrolling) {
                            Modifier.nestedScroll(scrimNestedScrollConnection)
                        }
+0 −20
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@ class NotificationScrimNestedScrollConnectionTest : SysuiTestCase() {
    private var wasStarted = false
    private var scrimOffset = 0f
    private var contentHeight = 0f
    private var isCurrentGestureOverscroll = false
    private val customFlingBehavior =
        object : FlingBehavior {
            override suspend fun ScrollScope.performFling(initialVelocity: Float): Float {
@@ -54,7 +53,6 @@ class NotificationScrimNestedScrollConnectionTest : SysuiTestCase() {
            maxScrimOffset = MAX_SCRIM_OFFSET,
            contentHeight = { contentHeight },
            minVisibleScrimHeight = { MIN_VISIBLE_SCRIM_HEIGHT },
            isCurrentGestureOverscroll = { isCurrentGestureOverscroll },
            onStart = { isStarted = true },
            onStop = {
                wasStarted = true
@@ -183,24 +181,6 @@ class NotificationScrimNestedScrollConnectionTest : SysuiTestCase() {
        assertThat(isStarted).isEqualTo(false)
    }

    @Test
    fun canStartPostScroll_externalOverscrollGesture_startButIgnoreScroll() = runTest {
        scrimOffset = MAX_SCRIM_OFFSET
        isCurrentGestureOverscroll = true

        val offsetConsumed =
            scrollConnection.onPostScroll(
                consumed = Offset.Zero,
                available = Offset(x = 0f, y = 1f),
                source = UserInput,
            )

        assertThat(offsetConsumed).isEqualTo(Offset.Zero)
        // Returning 0 offset will immediately stop the connection
        assertThat(wasStarted).isEqualTo(true)
        assertThat(isStarted).isEqualTo(false)
    }

    @Test
    fun canContinueScroll_inBetweenMinMaxOffset_true() = runTest {
        scrimOffset = (MIN_SCRIM_OFFSET + MAX_SCRIM_OFFSET) / 2f
+9 −17
Original line number Diff line number Diff line
@@ -1299,9 +1299,10 @@ public class NotificationStackScrollLayout
    }

    @Override
    public void setCurrentGestureOverscrollConsumer(@Nullable Consumer<Boolean> consumer) {
    public void setCurrentGestureExpandingNotificationConsumer(
            @Nullable Consumer<Boolean> consumer) {
        if (SceneContainerFlag.isUnexpectedlyInLegacyMode()) return;
        mScrollViewFields.setCurrentGestureOverscrollConsumer(consumer);
        mScrollViewFields.setCurrentGestureExpandingNotificationConsumer(consumer);
    }

    @Override
@@ -3656,13 +3657,13 @@ public class NotificationStackScrollLayout
            if (action == MotionEvent.ACTION_DOWN && !isTouchInGuts) {
                mController.closeControlsDueToOutsideTouch();
            }
            if (mIsBeingDragged) {
            if (mIsBeingDragged || mExpandingNotification) {
                boolean isUpOrCancel = action == ACTION_UP || action == ACTION_CANCEL;
                if (mSendingTouchesToSceneFramework) {
                    MotionEvent adjustedEvent = MotionEvent.obtain(ev);
                    adjustedEvent.setLocation(ev.getRawX(), ev.getRawY());
                    mScrollViewFields.sendCurrentGestureOverscroll(
                            getExpandedInThisMotion() && !isUpOrCancel);
                    mScrollViewFields.sendCurrentGestureExpandingNotification(
                            mExpandingNotification && !isUpOrCancel);
                    mController.sendTouchToSceneFramework(adjustedEvent);
                    adjustedEvent.recycle();
                } else if (!isUpOrCancel) {
@@ -3673,14 +3674,15 @@ public class NotificationStackScrollLayout
                    downEvent.setAction(MotionEvent.ACTION_DOWN);
                    downEvent.setLocation(ev.getRawX(), ev.getRawY());
                    mScrollViewFields.sendCurrentGestureInGuts(isTouchInGuts);
                    mScrollViewFields.sendCurrentGestureOverscroll(getExpandedInThisMotion());
                    mScrollViewFields.sendCurrentGestureExpandingNotification(
                            mExpandingNotification);
                    mController.sendTouchToSceneFramework(downEvent);
                    downEvent.recycle();
                }

                if (isUpOrCancel) {
                    mScrollViewFields.sendCurrentGestureInGuts(false);
                    mScrollViewFields.sendCurrentGestureOverscroll(false);
                    mScrollViewFields.sendCurrentGestureExpandingNotification(false);
                    setIsBeingDragged(false);
                }
            }
@@ -5872,11 +5874,6 @@ public class NotificationStackScrollLayout
        return mExpandingNotification;
    }

    @VisibleForTesting
    void setExpandingNotification(boolean isExpanding) {
        mExpandingNotification = isExpanding;
    }

    boolean getDisallowScrollingInThisMotion() {
        return mDisallowScrollingInThisMotion;
    }
@@ -5889,11 +5886,6 @@ public class NotificationStackScrollLayout
        return mExpandedInThisMotion;
    }

    @VisibleForTesting
    void setExpandedInThisMotion(boolean expandedInThisMotion) {
        mExpandedInThisMotion = expandedInThisMotion;
    }

    boolean getDisallowDismissInThisMotion() {
        return mDisallowDismissInThisMotion;
    }
+6 −5
Original line number Diff line number Diff line
@@ -62,9 +62,10 @@ class ScrollViewFields {

    /**
     * When a gesture is consumed internally by NSSL but needs to be handled by other elements (such
     * as the notif scrim) as overscroll, we can notify the placeholder through here.
     * as the notif scrim), we can notify the placeholder through here.
     */
    var currentGestureOverscrollConsumer: Consumer<Boolean>? = null
    var currentGestureExpandingNotificationConsumer: Consumer<Boolean>? = null

    /**
     * When a gesture is on open notification guts, which means scene container should not close the
     * guts off of this gesture, we can notify the placeholder through here.
@@ -81,9 +82,9 @@ class ScrollViewFields {
    fun sendSyntheticScroll(syntheticScroll: Float) =
        syntheticScrollConsumer?.accept(syntheticScroll)

    /** send [isCurrentGestureOverscroll] to the [currentGestureOverscrollConsumer], if present. */
    fun sendCurrentGestureOverscroll(isCurrentGestureOverscroll: Boolean) =
        currentGestureOverscrollConsumer?.accept(isCurrentGestureOverscroll)
    /** send [isExpanding] to the [currentGestureExpandingNotificationConsumer], if present. */
    fun sendCurrentGestureExpandingNotification(isExpanding: Boolean) =
        currentGestureExpandingNotificationConsumer?.accept(isExpanding)

    /** send [isCurrentGestureInGuts] to the [currentGestureInGutsConsumer], if present. */
    fun sendCurrentGestureInGuts(isCurrentGestureInGuts: Boolean) =
Loading