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

Commit cc3b3b3a authored by Shawn Lee's avatar Shawn Lee
Browse files

[flexiglass] Fix NSSL scrolling in split shade and lockscreen to splitshade transition.

Also turns off NSSL ignoring width of notifications when expanding them, greatly improving landscape shade usability. This behavior diverges from legacy but is a clear improvement.

Bug: 338080993
Bug: 335828150
Test: visually verified lockscreen -> split shade transition
Test: visually verified NSSL scrolling with overflowing notifications
Test: added unit test
Flag: ACONFIG com.android.systemui.scene_container DEVELOPMENT
Change-Id: I43b6c0bb5db6fa820a720e6e1d2f6444b972d5f8
parent 99bbe52e
Loading
Loading
Loading
Loading
+27 −25
Original line number Diff line number Diff line
@@ -68,12 +68,14 @@ import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.NestedScrollBehavior
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.height
import com.android.compose.modifiers.thenIf
import com.android.systemui.common.ui.compose.windowinsets.LocalRawScreenHeight
import com.android.systemui.common.ui.compose.windowinsets.LocalScreenCornerRadius
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.Scenes
import com.android.systemui.shade.shared.model.ShadeMode
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
@@ -165,6 +167,7 @@ fun SceneScope.NotificationScrollingStack(
    viewModel: NotificationsPlaceholderViewModel,
    maxScrimTop: () -> Float,
    shouldPunchHoleBehindScrim: Boolean,
    shadeMode: ShadeMode,
    modifier: Modifier = Modifier,
) {
    val coroutineScope = rememberCoroutineScope()
@@ -242,6 +245,27 @@ fun SceneScope.NotificationScrollingStack(
            }
    }

    val scrimNestedScrollConnection =
        shadeSession.rememberSession(
            scrimOffset,
            maxScrimTop,
            minScrimTop,
            isCurrentGestureOverscroll,
        ) {
            NotificationScrimNestedScrollConnection(
                scrimOffset = { scrimOffset.value },
                snapScrimOffset = { value -> coroutineScope.launch { scrimOffset.snapTo(value) } },
                animateScrimOffset = { value ->
                    coroutineScope.launch { scrimOffset.animateTo(value) }
                },
                minScrimOffset = minScrimOffset,
                maxScrimOffset = 0f,
                contentHeight = { stackHeight.intValue.toFloat() },
                minVisibleScrimHeight = minVisibleScrimHeight,
                isCurrentGestureOverscroll = { isCurrentGestureOverscroll.value },
            )
        }

    Box(
        modifier =
            modifier
@@ -316,31 +340,9 @@ fun SceneScope.NotificationScrollingStack(
                            topBehavior = NestedScrollBehavior.EdgeWithPreview,
                            isExternalOverscrollGesture = { isCurrentGestureOverscroll.value }
                        )
                        .nestedScroll(
                            shadeSession.rememberSession(
                                scrimOffset,
                                maxScrimTop,
                                minScrimTop,
                                isCurrentGestureOverscroll,
                            ) {
                                NotificationScrimNestedScrollConnection(
                                    scrimOffset = { scrimOffset.value },
                                    snapScrimOffset = { value ->
                                        coroutineScope.launch { scrimOffset.snapTo(value) }
                                    },
                                    animateScrimOffset = { value ->
                                        coroutineScope.launch { scrimOffset.animateTo(value) }
                                    },
                                    minScrimOffset = minScrimOffset,
                                    maxScrimOffset = 0f,
                                    contentHeight = { stackHeight.intValue.toFloat() },
                                    minVisibleScrimHeight = minVisibleScrimHeight,
                                    isCurrentGestureOverscroll = {
                                        isCurrentGestureOverscroll.value
                                    },
                                )
                        .thenIf(shadeMode == ShadeMode.Single) {
                            Modifier.nestedScroll(scrimNestedScrollConnection)
                        }
                        )
                        .verticalScroll(scrollState)
                        .fillMaxWidth()
                        .notificationStackHeight(
+2 −0
Original line number Diff line number Diff line
@@ -86,6 +86,7 @@ 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.ComposableScene
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
@@ -370,6 +371,7 @@ private fun SceneScope.QuickSettingsScene(
            shadeSession = shadeSession,
            maxScrimTop = { screenHeight },
            shouldPunchHoleBehindScrim = shouldPunchHoleBehindScrim,
            shadeMode = ShadeMode.Single,
            modifier =
                Modifier.fillMaxWidth().offset { IntOffset(x = 0, y = screenHeight.roundToInt()) },
        )
+10 −3
Original line number Diff line number Diff line
@@ -5,9 +5,8 @@ import com.android.compose.animation.scene.transitions
import com.android.systemui.bouncer.ui.composable.Bouncer
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.TransitionKeys.CollapseShadeInstantly
import com.android.systemui.scene.shared.model.TransitionKeys.GoneToSplitShade
import com.android.systemui.scene.shared.model.TransitionKeys.SlightlyFasterShadeCollapse
import com.android.systemui.scene.shared.model.TransitionKeys.ToSplitShade
import com.android.systemui.scene.ui.composable.transitions.bouncerToGoneTransition
import com.android.systemui.scene.ui.composable.transitions.goneToQuickSettingsTransition
import com.android.systemui.scene.ui.composable.transitions.goneToShadeTransition
@@ -17,6 +16,7 @@ import com.android.systemui.scene.ui.composable.transitions.lockscreenToCommunal
import com.android.systemui.scene.ui.composable.transitions.lockscreenToGoneTransition
import com.android.systemui.scene.ui.composable.transitions.lockscreenToQuickSettingsTransition
import com.android.systemui.scene.ui.composable.transitions.lockscreenToShadeTransition
import com.android.systemui.scene.ui.composable.transitions.lockscreenToSplitShadeTransition
import com.android.systemui.scene.ui.composable.transitions.shadeToQuickSettingsTransition
import com.android.systemui.shade.ui.composable.Shade

@@ -41,7 +41,7 @@ val SceneContainerTransitions = transitions {
    from(
        Scenes.Gone,
        to = Scenes.Shade,
        key = GoneToSplitShade,
        key = ToSplitShade,
    ) {
        goneToSplitShadeTransition()
    }
@@ -56,6 +56,13 @@ val SceneContainerTransitions = transitions {
    from(Scenes.Lockscreen, to = Scenes.Bouncer) { lockscreenToBouncerTransition() }
    from(Scenes.Lockscreen, to = Scenes.Communal) { lockscreenToCommunalTransition() }
    from(Scenes.Lockscreen, to = Scenes.Shade) { lockscreenToShadeTransition() }
    from(
        Scenes.Lockscreen,
        to = Scenes.Shade,
        key = ToSplitShade,
    ) {
        lockscreenToSplitShadeTransition()
    }
    from(
        Scenes.Lockscreen,
        to = Scenes.Shade,
+1 −41
Original line number Diff line number Diff line
@@ -16,50 +16,10 @@

package com.android.systemui.scene.ui.composable.transitions

import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.animation.core.tween
import androidx.compose.foundation.gestures.Orientation
import androidx.compose.ui.unit.IntSize
import com.android.compose.animation.scene.TransitionBuilder
import com.android.compose.animation.scene.UserActionDistance
import com.android.compose.animation.scene.UserActionDistanceScope
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.qs.ui.composable.QuickSettings
import com.android.systemui.shade.ui.composable.Shade
import com.android.systemui.shade.ui.composable.ShadeHeader
import kotlin.time.Duration.Companion.milliseconds

fun TransitionBuilder.goneToSplitShadeTransition(
    durationScale: Double = 1.0,
) {
    spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())
    swipeSpec =
        spring(
            stiffness = Spring.StiffnessMediumLow,
            visibilityThreshold = Shade.Dimensions.ScrimVisibilityThreshold,
        )
    distance =
        object : UserActionDistance {
            override fun UserActionDistanceScope.absoluteDistance(
                fromSceneSize: IntSize,
                orientation: Orientation,
            ): Float {
                return fromSceneSize.height.toFloat() * 2 / 3f
    toSplitShadeTransition(durationScale)
}
        }

    fractionRange(end = .33f) { fade(Shade.Elements.BackgroundScrim) }

    fractionRange(start = .33f) {
        fade(ShadeHeader.Elements.Clock)
        fade(ShadeHeader.Elements.CollapsedContentStart)
        fade(ShadeHeader.Elements.CollapsedContentEnd)
        fade(ShadeHeader.Elements.PrivacyChip)
        fade(QuickSettings.Elements.SplitShadeQuickSettings)
        fade(QuickSettings.Elements.FooterActions)
        fade(Notifications.Elements.NotificationScrim)
    }
}

private val DefaultDuration = 500.milliseconds
+25 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.systemui.scene.ui.composable.transitions

import com.android.compose.animation.scene.TransitionBuilder

fun TransitionBuilder.lockscreenToSplitShadeTransition(
    durationScale: Double = 1.0,
) {
    toSplitShadeTransition(durationScale = durationScale)
}
Loading