diff options
19 files changed, 345 insertions, 123 deletions
diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt index c3f44f8b1069..f7ebe2fc6d34 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/Key.kt @@ -37,7 +37,14 @@ sealed class Key(val name: String, val identity: Any) { } /** Key for a scene. */ -class SceneKey(name: String, identity: Any = Object()) : Key(name, identity) { +class SceneKey( + name: String, + identity: Any = Object(), +) : Key(name, identity) { + + /** The unique [ElementKey] identifying this scene's root element. */ + val rootElementKey = ElementKey(name, identity) + override fun toString(): String { return "SceneKey(name=$name)" } diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitions.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitions.kt index 9752f53fbd49..f4e39023edfe 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitions.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/SceneTransitions.kt @@ -35,7 +35,7 @@ import com.android.compose.ui.util.fastMap /** The transitions configuration of a [SceneTransitionLayout]. */ class SceneTransitions( - val transitionSpecs: List<TransitionSpec>, + private val transitionSpecs: List<TransitionSpec>, ) { private val cache = mutableMapOf<SceneKey, MutableMap<SceneKey, TransitionSpec>>() diff --git a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDslImpl.kt b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDslImpl.kt index afd49b4fde09..48d5638e8b4e 100644 --- a/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDslImpl.kt +++ b/packages/SystemUI/compose/core/src/com/android/compose/animation/scene/TransitionDslImpl.kt @@ -75,7 +75,7 @@ private class SceneTransitionsBuilderImpl : SceneTransitionsBuilder { } } -private class TransitionBuilderImpl : TransitionBuilder { +internal class TransitionBuilderImpl : TransitionBuilder { val transformations = mutableListOf<Transformation>() override var spec: AnimationSpec<Float> = spring(stiffness = Spring.StiffnessLow) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt index b9baa7930b4e..81b9eb067e7f 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/bouncer/ui/composable/BouncerScene.kt @@ -24,7 +24,7 @@ import android.content.DialogInterface import androidx.compose.animation.Crossfade import androidx.compose.animation.core.snap import androidx.compose.animation.core.tween -import androidx.compose.foundation.background +import androidx.compose.foundation.Canvas import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column @@ -46,6 +46,7 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp +import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope import com.android.systemui.R import com.android.systemui.bouncer.ui.viewmodel.AuthMethodBouncerViewModel @@ -63,6 +64,13 @@ import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.asStateFlow +object Bouncer { + object Elements { + val Background = ElementKey("BouncerBackground") + val Content = ElementKey("BouncerContent") + } +} + /** The bouncer scene displays authentication challenges like PIN, password, or pattern. */ @SysUISingleton class BouncerScene @@ -88,7 +96,7 @@ constructor( } @Composable -private fun BouncerScene( +private fun SceneScope.BouncerScene( viewModel: BouncerViewModel, dialogFactory: BouncerSceneDialogFactory, modifier: Modifier = Modifier, @@ -97,84 +105,90 @@ private fun BouncerScene( val authMethodViewModel: AuthMethodBouncerViewModel? by viewModel.authMethod.collectAsState() val dialogMessage: String? by viewModel.throttlingDialogMessage.collectAsState() var dialog: Dialog? by remember { mutableStateOf(null) } + val backgroundColor = MaterialTheme.colorScheme.surface - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(60.dp), - modifier = - modifier - .fillMaxSize() - .background(MaterialTheme.colorScheme.surface) - .padding(start = 32.dp, top = 92.dp, end = 32.dp, bottom = 32.dp) - ) { - Crossfade( - targetState = message, - label = "Bouncer message", - animationSpec = if (message.isUpdateAnimated) tween() else snap(), - ) { message -> - Text( - text = message.text, - color = MaterialTheme.colorScheme.onSurface, - style = MaterialTheme.typography.bodyLarge, - ) + Box(modifier) { + Canvas(Modifier.element(Bouncer.Elements.Background).fillMaxSize()) { + drawRect(color = backgroundColor) } - Box(Modifier.weight(1f)) { - when (val nonNullViewModel = authMethodViewModel) { - is PinBouncerViewModel -> - PinBouncer( - viewModel = nonNullViewModel, - modifier = Modifier.align(Alignment.Center), - ) - is PasswordBouncerViewModel -> - PasswordBouncer( - viewModel = nonNullViewModel, - modifier = Modifier.align(Alignment.Center), - ) - is PatternBouncerViewModel -> - PatternBouncer( - viewModel = nonNullViewModel, - modifier = - Modifier.aspectRatio(1f, matchHeightConstraintsFirst = false) - .align(Alignment.BottomCenter), - ) - else -> Unit + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(60.dp), + modifier = + Modifier.element(Bouncer.Elements.Content) + .fillMaxSize() + .padding(start = 32.dp, top = 92.dp, end = 32.dp, bottom = 32.dp) + ) { + Crossfade( + targetState = message, + label = "Bouncer message", + animationSpec = if (message.isUpdateAnimated) tween() else snap(), + ) { message -> + Text( + text = message.text, + color = MaterialTheme.colorScheme.onSurface, + style = MaterialTheme.typography.bodyLarge, + ) } - } - Button( - onClick = viewModel::onEmergencyServicesButtonClicked, - colors = - ButtonDefaults.buttonColors( - containerColor = MaterialTheme.colorScheme.tertiaryContainer, - contentColor = MaterialTheme.colorScheme.onTertiaryContainer, - ), - ) { - Text( - text = stringResource(com.android.internal.R.string.lockscreen_emergency_call), - style = MaterialTheme.typography.bodyMedium, - ) - } + Box(Modifier.weight(1f)) { + when (val nonNullViewModel = authMethodViewModel) { + is PinBouncerViewModel -> + PinBouncer( + viewModel = nonNullViewModel, + modifier = Modifier.align(Alignment.Center), + ) + is PasswordBouncerViewModel -> + PasswordBouncer( + viewModel = nonNullViewModel, + modifier = Modifier.align(Alignment.Center), + ) + is PatternBouncerViewModel -> + PatternBouncer( + viewModel = nonNullViewModel, + modifier = + Modifier.aspectRatio(1f, matchHeightConstraintsFirst = false) + .align(Alignment.BottomCenter), + ) + else -> Unit + } + } + + Button( + onClick = viewModel::onEmergencyServicesButtonClicked, + colors = + ButtonDefaults.buttonColors( + containerColor = MaterialTheme.colorScheme.tertiaryContainer, + contentColor = MaterialTheme.colorScheme.onTertiaryContainer, + ), + ) { + Text( + text = stringResource(com.android.internal.R.string.lockscreen_emergency_call), + style = MaterialTheme.typography.bodyMedium, + ) + } - if (dialogMessage != null) { - if (dialog == null) { - dialog = - dialogFactory().apply { - setMessage(dialogMessage) - setButton( - DialogInterface.BUTTON_NEUTRAL, - context.getString(R.string.ok), - ) { _, _ -> - viewModel.onThrottlingDialogDismissed() + if (dialogMessage != null) { + if (dialog == null) { + dialog = + dialogFactory().apply { + setMessage(dialogMessage) + setButton( + DialogInterface.BUTTON_NEUTRAL, + context.getString(R.string.ok), + ) { _, _ -> + viewModel.onThrottlingDialogDismissed() + } + setCancelable(false) + setCanceledOnTouchOutside(false) + show() } - setCancelable(false) - setCanceledOnTouchOutside(false) - show() - } + } + } else { + dialog?.dismiss() + dialog = null } - } else { - dialog?.dismiss() - dialog = null } } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt index 38b751c9445d..889c026a0568 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/notifications/ui/composable/Notifications.kt @@ -31,9 +31,17 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp +import com.android.compose.animation.scene.ElementKey +import com.android.compose.animation.scene.SceneScope + +object Notifications { + object Elements { + val Notifications = ElementKey("Notifications") + } +} @Composable -fun Notifications( +fun SceneScope.Notifications( modifier: Modifier = Modifier, ) { // TODO(b/272779828): implement. diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/QuickSettings.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/QuickSettings.kt index 1bb341c76e69..c84a5e91ca50 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/QuickSettings.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/footer/ui/compose/QuickSettings.kt @@ -31,15 +31,27 @@ import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.draw.clip import androidx.compose.ui.unit.dp +import com.android.compose.animation.scene.ElementKey +import com.android.compose.animation.scene.SceneScope + +object QuickSettings { + object Elements { + // TODO RENAME + val Content = ElementKey("QuickSettingsContent") + val CollapsedGrid = ElementKey("QuickSettingsCollapsedGrid") + val FooterActions = ElementKey("QuickSettingsFooterActions") + } +} @Composable -fun QuickSettings( +fun SceneScope.QuickSettings( modifier: Modifier = Modifier, ) { // TODO(b/272780058): implement. Column( modifier = modifier + .element(QuickSettings.Elements.Content) .fillMaxWidth() .defaultMinSize(minHeight = 300.dp) .clip(RoundedCornerShape(32.dp)) @@ -47,15 +59,19 @@ fun QuickSettings( .padding(16.dp), ) { Text( - text = "Quick settings", - modifier = Modifier.align(Alignment.CenterHorizontally), + text = "Quick settings grid", + modifier = + Modifier.element(QuickSettings.Elements.CollapsedGrid) + .align(Alignment.CenterHorizontally), style = MaterialTheme.typography.titleLarge, color = MaterialTheme.colorScheme.onPrimary, ) Spacer(modifier = Modifier.weight(1f)) Text( text = "QS footer actions", - modifier = Modifier.align(Alignment.CenterHorizontally), + modifier = + Modifier.element(QuickSettings.Elements.FooterActions) + .align(Alignment.CenterHorizontally), style = MaterialTheme.typography.titleSmall, color = MaterialTheme.colorScheme.onPrimary, ) diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt index 29763c2e329d..e5cd4397166e 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/qs/ui/composable/QuickSettingsScene.kt @@ -16,19 +16,17 @@ package com.android.systemui.qs.ui.composable -import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Column -import androidx.compose.foundation.layout.Row -import androidx.compose.material3.Button -import androidx.compose.material3.MaterialTheme -import androidx.compose.material3.Text +import androidx.compose.foundation.layout.fillMaxHeight +import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.padding import androidx.compose.runtime.Composable -import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp import com.android.compose.animation.scene.SceneScope import com.android.systemui.dagger.SysUISingleton +import com.android.systemui.qs.footer.ui.compose.QuickSettings import com.android.systemui.qs.ui.viewmodel.QuickSettingsSceneViewModel import com.android.systemui.scene.shared.model.Direction import com.android.systemui.scene.shared.model.SceneKey @@ -69,23 +67,18 @@ constructor( } @Composable -private fun QuickSettingsScene( +private fun SceneScope.QuickSettingsScene( viewModel: QuickSettingsSceneViewModel, modifier: Modifier = Modifier, ) { // TODO(b/280887232): implement the real UI. - Box(modifier = modifier) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - modifier = Modifier.align(Alignment.Center) - ) { - Text("Quick settings", style = MaterialTheme.typography.headlineMedium) - Row( - horizontalArrangement = Arrangement.spacedBy(8.dp), - ) { - Button(onClick = { viewModel.onContentClicked() }) { Text("Open some content") } - } - } + Box( + modifier + .fillMaxSize() + .clickable(onClick = { viewModel.onContentClicked() }) + .padding(horizontal = 16.dp, vertical = 48.dp) + ) { + QuickSettings(modifier = Modifier.fillMaxHeight()) } } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt index f91baf298347..c865070b2c91 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainer.kt @@ -31,7 +31,6 @@ import com.android.compose.animation.scene.SceneTransitionLayoutState import com.android.compose.animation.scene.Swipe import com.android.compose.animation.scene.UserAction as SceneTransitionUserAction import com.android.compose.animation.scene.observableTransitionState -import com.android.compose.animation.scene.transitions import com.android.systemui.scene.shared.model.Direction import com.android.systemui.scene.shared.model.ObservableTransitionState import com.android.systemui.scene.shared.model.SceneKey @@ -78,7 +77,7 @@ fun SceneContainer( SceneTransitionLayout( currentScene = currentSceneKey.toTransitionSceneKey(), onChangeScene = viewModel::onSceneChanged, - transitions = transitions {}, + transitions = SceneContainerTransitions, state = state, modifier = modifier.fillMaxSize(), ) { @@ -98,7 +97,9 @@ fun SceneContainer( ) { with(composableScene) { this@scene.Content( - modifier = Modifier.fillMaxSize(), + modifier = + Modifier.element(sceneKey.toTransitionSceneKey().rootElementKey) + .fillMaxSize(), ) } } @@ -129,14 +130,6 @@ private fun toTransitionModels( } // TODO(b/293899074): remove this once we can use the one from SceneTransitionLayout. -private fun SceneKey.toTransitionSceneKey(): SceneTransitionSceneKey { - return SceneTransitionSceneKey( - name = toString(), - identity = this, - ) -} - -// TODO(b/293899074): remove this once we can use the one from SceneTransitionLayout. private fun SceneTransitionSceneKey.toModel(): SceneModel { return SceneModel(key = identity as SceneKey) } diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt new file mode 100644 index 000000000000..404bf81ee387 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/SceneContainerTransitions.kt @@ -0,0 +1,34 @@ +package com.android.systemui.scene.ui.composable + +import com.android.compose.animation.scene.transitions +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 +import com.android.systemui.scene.ui.composable.transitions.lockscreenToBouncerTransition +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.shadeToQuickSettingsTransition + +/** + * Comprehensive definition of all transitions between scenes 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. + * Lockscreen to Bouncer rather than Bouncer to Lockscreen. + * + * The actual transition DSL must be placed in a separate file under the package + * [com.android.systemui.scene.ui.composable.transitions]. + * + * Please keep the list sorted alphabetically. + */ +val SceneContainerTransitions = transitions { + from(Bouncer, to = Gone) { bouncerToGoneTransition() } + from(Gone, to = Shade) { goneToShadeTransition() } + from(Gone, to = QuickSettings) { goneToQuickSettingsTransition() } + from(Lockscreen, to = Bouncer) { lockscreenToBouncerTransition() } + from(Lockscreen, to = Shade) { lockscreenToShadeTransition() } + from(Lockscreen, to = QuickSettings) { lockscreenToQuickSettingsTransition() } + from(Lockscreen, to = Gone) { lockscreenToGoneTransition() } + from(Shade, to = QuickSettings) { shadeToQuickSettingsTransition() } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/TransitionSceneKeys.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/TransitionSceneKeys.kt new file mode 100644 index 000000000000..8d0d7050dcca --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/TransitionSceneKeys.kt @@ -0,0 +1,15 @@ +package com.android.systemui.scene.ui.composable + +import com.android.compose.animation.scene.SceneKey as SceneTransitionSceneKey +import com.android.systemui.scene.shared.model.SceneKey + +val Lockscreen = SceneKey.Lockscreen.toTransitionSceneKey() +val Bouncer = SceneKey.Bouncer.toTransitionSceneKey() +val Shade = SceneKey.Shade.toTransitionSceneKey() +val QuickSettings = SceneKey.QuickSettings.toTransitionSceneKey() +val Gone = SceneKey.Gone.toTransitionSceneKey() + +// TODO(b/293899074): Remove this file once we can use the scene keys from SceneTransitionLayout. +fun SceneKey.toTransitionSceneKey(): SceneTransitionSceneKey { + return SceneTransitionSceneKey(name = toString(), identity = this) +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromBouncerToGoneTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromBouncerToGoneTransition.kt new file mode 100644 index 000000000000..1a9facea7518 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromBouncerToGoneTransition.kt @@ -0,0 +1,11 @@ +package com.android.systemui.scene.ui.composable.transitions + +import androidx.compose.animation.core.tween +import com.android.compose.animation.scene.TransitionBuilder +import com.android.systemui.scene.ui.composable.Bouncer + +fun TransitionBuilder.bouncerToGoneTransition() { + spec = tween(durationMillis = 500) + + fade(Bouncer.rootElementKey) +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsTransition.kt new file mode 100644 index 000000000000..38712b01ae44 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToQuickSettingsTransition.kt @@ -0,0 +1,11 @@ +package com.android.systemui.scene.ui.composable.transitions + +import androidx.compose.animation.core.tween +import com.android.compose.animation.scene.TransitionBuilder +import com.android.systemui.scene.ui.composable.QuickSettings + +fun TransitionBuilder.goneToQuickSettingsTransition() { + spec = tween(durationMillis = 500) + + fade(QuickSettings.rootElementKey) +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt new file mode 100644 index 000000000000..1d57c1a377e5 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromGoneToShadeTransition.kt @@ -0,0 +1,11 @@ +package com.android.systemui.scene.ui.composable.transitions + +import androidx.compose.animation.core.tween +import com.android.compose.animation.scene.TransitionBuilder +import com.android.systemui.scene.ui.composable.Shade + +fun TransitionBuilder.goneToShadeTransition() { + spec = tween(durationMillis = 500) + + fade(Shade.rootElementKey) +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToBouncerTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToBouncerTransition.kt new file mode 100644 index 000000000000..1fee8741fe48 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToBouncerTransition.kt @@ -0,0 +1,14 @@ +package com.android.systemui.scene.ui.composable.transitions + +import androidx.compose.animation.core.tween +import androidx.compose.ui.unit.dp +import com.android.compose.animation.scene.TransitionBuilder +import com.android.systemui.bouncer.ui.composable.Bouncer + +fun TransitionBuilder.lockscreenToBouncerTransition() { + spec = tween(durationMillis = 500) + + translate(Bouncer.Elements.Content, y = 300.dp) + fractionRange(end = 0.5f) { fade(Bouncer.Elements.Background) } + fractionRange(start = 0.5f) { fade(Bouncer.Elements.Content) } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToGoneTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToGoneTransition.kt new file mode 100644 index 000000000000..da6306dc656d --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToGoneTransition.kt @@ -0,0 +1,11 @@ +package com.android.systemui.scene.ui.composable.transitions + +import androidx.compose.animation.core.tween +import com.android.compose.animation.scene.TransitionBuilder +import com.android.systemui.scene.ui.composable.Lockscreen + +fun TransitionBuilder.lockscreenToGoneTransition() { + spec = tween(durationMillis = 500) + + fade(Lockscreen.rootElementKey) +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsTransition.kt new file mode 100644 index 000000000000..9a8a3e2048d1 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToQuickSettingsTransition.kt @@ -0,0 +1,11 @@ +package com.android.systemui.scene.ui.composable.transitions + +import androidx.compose.animation.core.tween +import com.android.compose.animation.scene.TransitionBuilder +import com.android.systemui.scene.ui.composable.QuickSettings + +fun TransitionBuilder.lockscreenToQuickSettingsTransition() { + spec = tween(durationMillis = 500) + + fade(QuickSettings.rootElementKey) +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt new file mode 100644 index 000000000000..7ecfb62c4f62 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromLockscreenToShadeTransition.kt @@ -0,0 +1,24 @@ +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.systemui.notifications.ui.composable.Notifications +import com.android.systemui.qs.footer.ui.compose.QuickSettings +import com.android.systemui.shade.ui.composable.Shade + +fun TransitionBuilder.lockscreenToShadeTransition() { + spec = tween(durationMillis = 500) + + punchHole(Shade.Elements.QuickSettings, bounds = Shade.Elements.Scrim, Shade.Shapes.Scrim) + translate(Shade.Elements.Scrim, Edge.Top, startsOutsideLayoutBounds = false) + fractionRange(end = 0.5f) { + fade(Shade.Elements.ScrimBackground) + translate( + QuickSettings.Elements.CollapsedGrid, + Edge.Top, + startsOutsideLayoutBounds = false, + ) + } + fractionRange(start = 0.5f) { fade(Notifications.Elements.Notifications) } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt new file mode 100644 index 000000000000..6c7964b30989 --- /dev/null +++ b/packages/SystemUI/compose/features/src/com/android/systemui/scene/ui/composable/transitions/FromShadeToQuickSettingsTransition.kt @@ -0,0 +1,15 @@ +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.systemui.notifications.ui.composable.Notifications +import com.android.systemui.qs.footer.ui.compose.QuickSettings + +fun TransitionBuilder.shadeToQuickSettingsTransition() { + spec = tween(durationMillis = 500) + + translate(Notifications.Elements.Notifications, Edge.Bottom) + fade(Notifications.Elements.Notifications) + timestampRange(endMillis = 83) { fade(QuickSettings.Elements.FooterActions) } +} diff --git a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt index ff1cb5f1afa3..f985aa2a2aa0 100644 --- a/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt +++ b/packages/SystemUI/compose/features/src/com/android/systemui/shade/ui/composable/ShadeScene.kt @@ -16,16 +16,22 @@ package com.android.systemui.shade.ui.composable +import androidx.compose.foundation.background import androidx.compose.foundation.clickable import androidx.compose.foundation.layout.Arrangement +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Column +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.unit.dp +import com.android.compose.animation.scene.ElementKey import com.android.compose.animation.scene.SceneScope import com.android.systemui.dagger.SysUISingleton import com.android.systemui.dagger.qualifiers.Application @@ -44,6 +50,26 @@ import kotlinx.coroutines.flow.StateFlow import kotlinx.coroutines.flow.map import kotlinx.coroutines.flow.stateIn +object Shade { + object Elements { + val QuickSettings = ElementKey("ShadeQuickSettings") + val Scrim = ElementKey("ShadeScrim") + val ScrimBackground = ElementKey("ShadeScrimBackground") + } + + object Dimensions { + val ScrimCornerSize = 32.dp + } + + object Shapes { + val Scrim = + RoundedCornerShape( + topStart = Dimensions.ScrimCornerSize, + topEnd = Dimensions.ScrimCornerSize, + ) + } +} + /** The shade scene shows scrolling list of notifications and some of the quick setting tiles. */ @SysUISingleton class ShadeScene @@ -79,20 +105,28 @@ constructor( } @Composable -private fun ShadeScene( +private fun SceneScope.ShadeScene( viewModel: ShadeSceneViewModel, modifier: Modifier = Modifier, ) { - Column( - horizontalAlignment = Alignment.CenterHorizontally, - verticalArrangement = Arrangement.spacedBy(16.dp), - modifier = - modifier - .fillMaxSize() - .clickable(onClick = { viewModel.onContentClicked() }) - .padding(horizontal = 16.dp, vertical = 48.dp) - ) { - QuickSettings(modifier = Modifier.height(160.dp)) - Notifications(modifier = Modifier.weight(1f)) + Box(modifier.element(Shade.Elements.Scrim)) { + Spacer( + modifier = + Modifier.element(Shade.Elements.ScrimBackground) + .fillMaxSize() + .background(MaterialTheme.colorScheme.scrim, shape = Shade.Shapes.Scrim) + ) + + Column( + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.spacedBy(16.dp), + modifier = + Modifier.fillMaxSize() + .clickable(onClick = { viewModel.onContentClicked() }) + .padding(horizontal = 16.dp, vertical = 48.dp) + ) { + QuickSettings(modifier = Modifier.height(160.dp)) + Notifications(modifier = Modifier.weight(1f)) + } } } |