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

Commit 6b7dc585 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "[Dual Shade] Introduce `verticalContainerReveal` for shade transitions." into main

parents 27bcbd51 12087a56
Loading
Loading
Loading
Loading
+9 −3
Original line number Diff line number Diff line
@@ -34,13 +34,13 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalHapticFeedback
import androidx.compose.ui.platform.LocalView
import androidx.lifecycle.compose.collectAsStateWithLifecycle
import com.android.compose.animation.scene.ContentKey
import com.android.compose.animation.scene.OverlayKey
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.animation.scene.SceneTransitions
import com.android.compose.animation.scene.UserAction
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.observableTransitionState
@@ -85,7 +85,7 @@ fun SceneContainer(
    sceneByKey: Map<SceneKey, Scene>,
    overlayByKey: Map<OverlayKey, Overlay>,
    initialSceneKey: SceneKey,
    sceneTransitions: SceneTransitions,
    transitionsBuilder: SceneContainerTransitionsBuilder,
    dataSourceDelegator: SceneDataSourceDelegator,
    qsSceneAdapter: Provider<QSSceneAdapter>,
    sceneJankMonitorFactory: SceneJankMonitor.Factory,
@@ -97,6 +97,12 @@ fun SceneContainer(
    val sceneJankMonitor =
        rememberActivated(traceName = "sceneJankMonitor") { sceneJankMonitorFactory.create() }

    val hapticFeedback = LocalHapticFeedback.current
    val sceneTransitions =
        remember(hapticFeedback) {
            transitionsBuilder.build(viewModel.hapticsViewModel.getRevealHaptics(hapticFeedback))
        }

    val state =
        rememberMutableSceneTransitionLayoutState(
            initialScene = initialSceneKey,
@@ -161,7 +167,7 @@ fun SceneContainer(
        if (isFullWidthShade()) stretchOverscrollEffectFactory else offsetOverscrollEffectFactory

    // Inflate qsView here so that shade has the correct qqs height in the first measure pass after
    // rebooting
    // rebooting.
    if (
        viewModel.allContentKeys.contains(Scenes.QuickSettings) ||
            viewModel.allContentKeys.contains(Scenes.Shade)
+192 −154
Original line number Diff line number Diff line
package com.android.systemui.scene.ui.composable

import com.android.compose.animation.scene.SceneTransitions
import com.android.compose.animation.scene.TransitionKey
import com.android.compose.animation.scene.reveal.ContainerRevealHaptics
import com.android.compose.animation.scene.transitions
import com.android.internal.jank.Cuj
import com.android.systemui.notifications.ui.composable.Notifications
@@ -32,7 +34,7 @@ import com.android.systemui.scene.ui.composable.transitions.toQuickSettingsShade
import com.android.systemui.shade.ui.composable.Shade

/**
 * Comprehensive definition of all transitions between scenes in [SceneContainer].
 * Comprehensive definition of all transitions between scenes and overlays in [SceneContainer].
 *
 * Transitions are automatically reversible, so define only one transition per scene pair. By\
 * convention, use the more common transition direction when defining the pair order, e.g.
@@ -43,7 +45,9 @@ import com.android.systemui.shade.ui.composable.Shade
 *
 * Please keep the list sorted alphabetically.
 */
val SceneContainerTransitions = transitions {
class SceneContainerTransitions : SceneContainerTransitionsBuilder {
    override fun build(revealHaptics: ContainerRevealHaptics): SceneTransitions {
        return transitions {
            interruptionHandler = SceneContainerInterruptionHandler

            // Scene transitions
@@ -52,17 +56,25 @@ val SceneContainerTransitions = transitions {
            from(Scenes.Dream, to = Scenes.Bouncer) { dreamToBouncerTransition() }
            from(Scenes.Dream, to = Scenes.Communal) { dreamToCommunalTransition() }
            from(Scenes.Dream, to = Scenes.Gone) { dreamToGoneTransition() }
    from(Scenes.Dream, to = Scenes.Shade, cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE) {
            from(
                Scenes.Dream,
                to = Scenes.Shade,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
                dreamToShadeTransition()
            }
    from(Scenes.Gone, to = Scenes.Shade, cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE) {
            from(
                Scenes.Gone,
                to = Scenes.Shade,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
                goneToShadeTransition()
            }
            from(
                Scenes.Gone,
                to = Scenes.Shade,
                key = ToSplitShade,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
                goneToSplitShadeTransition()
            }
@@ -70,14 +82,14 @@ val SceneContainerTransitions = transitions {
                Scenes.Gone,
                to = Scenes.Shade,
                key = SlightlyFasterShadeCollapse,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
                goneToShadeTransition(durationScale = 0.9)
            }
            from(
                Scenes.Gone,
                to = Scenes.QuickSettings,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
            ) {
                goneToQuickSettingsTransition()
            }
@@ -85,7 +97,7 @@ val SceneContainerTransitions = transitions {
                Scenes.Gone,
                to = Scenes.QuickSettings,
                key = SlightlyFasterShadeCollapse,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
            ) {
                goneToQuickSettingsTransition(durationScale = 0.9)
            }
@@ -101,14 +113,18 @@ val SceneContainerTransitions = transitions {
            }
            from(Scenes.Lockscreen, to = Scenes.Communal) { lockscreenToCommunalTransition() }
            from(Scenes.Lockscreen, to = Scenes.Dream) { lockscreenToDreamTransition() }
    from(Scenes.Lockscreen, to = Scenes.Shade, cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE) {
            from(
                Scenes.Lockscreen,
                to = Scenes.Shade,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
                lockscreenToShadeTransition()
            }
            from(
                Scenes.Lockscreen,
                to = Scenes.Shade,
                key = ToSplitShade,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
                lockscreenToSplitShadeTransition()
                sharedElement(Shade.Elements.BackgroundScrim, enabled = false)
@@ -117,14 +133,14 @@ val SceneContainerTransitions = transitions {
                Scenes.Lockscreen,
                to = Scenes.Shade,
                key = SlightlyFasterShadeCollapse,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
                lockscreenToShadeTransition(durationScale = 0.9)
            }
            from(
                Scenes.Lockscreen,
                to = Scenes.QuickSettings,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
            ) {
                lockscreenToQuickSettingsTransition()
            }
@@ -132,74 +148,96 @@ val SceneContainerTransitions = transitions {
            from(
                Scenes.QuickSettings,
                to = Scenes.Shade,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
            ) {
                reversed { shadeToQuickSettingsTransition() }
        sharedElement(Notifications.Elements.HeadsUpNotificationPlaceholder, enabled = false)
                sharedElement(
                    Notifications.Elements.HeadsUpNotificationPlaceholder,
                    enabled = false,
                )
            }
            from(
                Scenes.Shade,
                to = Scenes.QuickSettings,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
            ) {
                shadeToQuickSettingsTransition()
            }
    from(Scenes.Shade, to = Scenes.Lockscreen, cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE) {
            from(
                Scenes.Shade,
                to = Scenes.Lockscreen,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
                reversed { lockscreenToShadeTransition() }
                sharedElement(Notifications.Elements.NotificationStackPlaceholder, enabled = false)
        sharedElement(Notifications.Elements.HeadsUpNotificationPlaceholder, enabled = false)
                sharedElement(
                    Notifications.Elements.HeadsUpNotificationPlaceholder,
                    enabled = false,
                )
            }
            from(
                Scenes.Shade,
                to = Scenes.Lockscreen,
                key = ToSplitShade,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
                reversed { lockscreenToSplitShadeTransition() }
            }
    from(Scenes.Communal, to = Scenes.Shade, cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE) {
            from(
                Scenes.Communal,
                to = Scenes.Shade,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
                communalToShadeTransition()
            }
            from(Scenes.Communal, to = Scenes.Bouncer) { communalToBouncerTransition() }

            // Overlay transitions

    to(Overlays.NotificationsShade, cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE) {
        toNotificationsShadeTransition()
            to(
                Overlays.NotificationsShade,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
                toNotificationsShadeTransition(revealHaptics = revealHaptics)
            }
    to(Overlays.QuickSettingsShade, cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE) {
        toQuickSettingsShadeTransition()
            to(
                Overlays.QuickSettingsShade,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
            ) {
                toQuickSettingsShadeTransition(revealHaptics = revealHaptics)
            }
            from(
                Scenes.Gone,
                to = Overlays.NotificationsShade,
                key = SlightlyFasterShadeCollapse,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
        toNotificationsShadeTransition(durationScale = 0.9)
                toNotificationsShadeTransition(durationScale = 0.9, revealHaptics = revealHaptics)
            }
            from(
                Scenes.Gone,
                to = Overlays.QuickSettingsShade,
                key = SlightlyFasterShadeCollapse,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
            ) {
        toQuickSettingsShadeTransition(durationScale = 0.9)
                toQuickSettingsShadeTransition(durationScale = 0.9, revealHaptics = revealHaptics)
            }
            from(
                Scenes.Lockscreen,
                to = Overlays.NotificationsShade,
                key = SlightlyFasterShadeCollapse,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_EXPAND_COLLAPSE, // NOTYPO
            ) {
        toNotificationsShadeTransition(durationScale = 0.9)
                toNotificationsShadeTransition(durationScale = 0.9, revealHaptics = revealHaptics)
            }
            from(
                Scenes.Lockscreen,
                to = Overlays.QuickSettingsShade,
                key = SlightlyFasterShadeCollapse,
        cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE,
                cuj = Cuj.CUJ_NOTIFICATION_SHADE_QS_EXPAND_COLLAPSE, // NOTYPO
            ) {
        toQuickSettingsShadeTransition(durationScale = 0.9)
                toQuickSettingsShadeTransition(durationScale = 0.9, revealHaptics = revealHaptics)
            }
        }
    }
}
+41 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2025 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

import com.android.compose.animation.scene.SceneTransitions
import com.android.compose.animation.scene.reveal.ContainerRevealHaptics
import com.android.compose.animation.scene.transitions

/**
 * Builder of the comprehensive definition of all transitions between scenes and overlays in the
 * scene container.
 */
interface SceneContainerTransitionsBuilder {

    /** Build the [SceneContainer] transitions spec. */
    fun build(revealHaptics: ContainerRevealHaptics): SceneTransitions
}

/**
 * Implementation of [SceneContainerTransitionsBuilder] that returns a constant [SceneTransitions]
 * instance, ignoring any parameters passed to [build].
 */
class ConstantSceneContainerTransitionsBuilder(
    private val transitions: SceneTransitions = transitions { /* No transitions */ }
) : SceneContainerTransitionsBuilder {
    override fun build(revealHaptics: ContainerRevealHaptics): SceneTransitions = transitions
}
+7 −12
Original line number Diff line number Diff line
@@ -17,16 +17,18 @@
package com.android.systemui.scene.ui.composable.transitions

import androidx.compose.animation.core.tween
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
import com.android.compose.animation.scene.reveal.ContainerRevealHaptics
import com.android.compose.animation.scene.reveal.verticalContainerReveal
import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys
import com.android.systemui.notifications.ui.composable.Notifications
import com.android.systemui.notifications.ui.composable.NotificationsShade
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.shade.ui.composable.OverlayShade
import kotlin.time.Duration.Companion.milliseconds

fun TransitionBuilder.toNotificationsShadeTransition(durationScale: Double = 1.0) {
fun TransitionBuilder.toNotificationsShadeTransition(
    durationScale: Double = 1.0,
    revealHaptics: ContainerRevealHaptics,
) {
    spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())

    // Ensure the clock isn't clipped by the shade outline during the transition from lockscreen.
@@ -34,14 +36,7 @@ fun TransitionBuilder.toNotificationsShadeTransition(durationScale: Double = 1.0
        ClockElementKeys.smallClockElementKey,
        elevateInContent = Overlays.NotificationsShade,
    )
    scaleSize(OverlayShade.Elements.Panel, height = 0f)
    // Avoid translating the status bar with the shade panel.
    translate(NotificationsShade.Elements.StatusBar)
    // Slide in the shade panel from the top edge.
    translate(OverlayShade.Elements.Panel, Edge.Top)

    fractionRange(end = .5f) { fade(OverlayShade.Elements.Scrim) }
    fractionRange(start = .5f) { fade(Notifications.Elements.NotificationScrim) }
    verticalContainerReveal(OverlayShade.Elements.Panel, revealHaptics)
}

private val DefaultDuration = 300.milliseconds
+7 −4
Original line number Diff line number Diff line
@@ -17,16 +17,19 @@
package com.android.systemui.scene.ui.composable.transitions

import androidx.compose.animation.core.tween
import com.android.compose.animation.scene.Edge
import com.android.compose.animation.scene.TransitionBuilder
import com.android.compose.animation.scene.reveal.ContainerRevealHaptics
import com.android.compose.animation.scene.reveal.verticalContainerReveal
import com.android.systemui.shade.ui.composable.OverlayShade
import kotlin.time.Duration.Companion.milliseconds

fun TransitionBuilder.toQuickSettingsShadeTransition(durationScale: Double = 1.0) {
fun TransitionBuilder.toQuickSettingsShadeTransition(
    durationScale: Double = 1.0,
    revealHaptics: ContainerRevealHaptics,
) {
    spec = tween(durationMillis = (DefaultDuration * durationScale).inWholeMilliseconds.toInt())

    translate(OverlayShade.Elements.Panel, Edge.Top)
    fractionRange(end = .5f) { fade(OverlayShade.Elements.Scrim) }
    verticalContainerReveal(OverlayShade.Elements.Panel, revealHaptics)
}

private val DefaultDuration = 300.milliseconds
Loading