Loading packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt +9 −3 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading @@ -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, Loading Loading @@ -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) Loading packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt +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 Loading Loading @@ -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. Loading @@ -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 Loading @@ -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() } Loading @@ -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() } Loading @@ -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) } Loading @@ -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) Loading @@ -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() } Loading @@ -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) } } } } packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitionsBuilder.kt 0 → 100644 +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 } packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt +7 −12 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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 packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt +7 −4 Original line number Diff line number Diff line Loading @@ -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
packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt +9 −3 Original line number Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading @@ -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, Loading Loading @@ -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) Loading
packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt +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 Loading Loading @@ -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. Loading @@ -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 Loading @@ -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() } Loading @@ -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() } Loading @@ -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) } Loading @@ -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) Loading @@ -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() } Loading @@ -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) } } } }
packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitionsBuilder.kt 0 → 100644 +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 }
packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToNotificationsShadeTransition.kt +7 −12 Original line number Diff line number Diff line Loading @@ -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. Loading @@ -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
packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/ToQuickSettingsShadeTransition.kt +7 −4 Original line number Diff line number Diff line Loading @@ -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