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

Commit c6782323 authored by Aaron Liu's avatar Aaron Liu Committed by Android (Google) Code Review
Browse files

Merge "Use SceneTransitionLayout to animate clocks." into main

parents fe901279 485c4955
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -18,13 +18,16 @@ package com.android.systemui.keyguard.ui.composable

import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalView
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.animation.scene.transitions
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.blueprint.ComposableLockscreenSceneBlueprint
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import javax.inject.Inject
@@ -40,6 +43,7 @@ class LockscreenContent
constructor(
    private val viewModel: LockscreenContentViewModel,
    private val blueprints: Set<@JvmSuppressWildcards ComposableLockscreenSceneBlueprint>,
    private val clockInteractor: KeyguardClockInteractor,
) {

    private val sceneKeyByBlueprint: Map<ComposableLockscreenSceneBlueprint, SceneKey> by lazy {
@@ -55,6 +59,12 @@ constructor(
    ) {
        val coroutineScope = rememberCoroutineScope()
        val blueprintId by viewModel.blueprintId(coroutineScope).collectAsState()
        val view = LocalView.current
        DisposableEffect(view) {
            clockInteractor.clockEventController.registerListeners(view)

            onDispose { clockInteractor.clockEventController.unregisterListeners() }
        }

        // Switch smoothly between blueprints, any composable tagged with element() will be
        // transition-animated between any two blueprints, if they both display the same element.
+79 −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.keyguard.ui.composable.blueprint

import androidx.compose.animation.core.tween
import com.android.compose.animation.scene.ElementKey
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.TransitionBuilder
import com.android.compose.animation.scene.transitions
import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.largeClockElementKey
import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.smallClockElementKey
import com.android.systemui.keyguard.ui.composable.blueprint.ClockElementKeys.smartspaceElementKey
import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.ClockFaceInTransition.Companion.CLOCK_IN_MILLIS
import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.ClockFaceInTransition.Companion.CLOCK_IN_START_DELAY_MILLIS
import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.ClockFaceOutTransition.Companion.CLOCK_OUT_MILLIS
import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.SmartspaceMoveTransition.Companion.STATUS_AREA_MOVE_DOWN_MILLIS
import com.android.systemui.keyguard.ui.view.layout.sections.transitions.ClockSizeTransition.SmartspaceMoveTransition.Companion.STATUS_AREA_MOVE_UP_MILLIS

object ClockTransition {
    val defaultClockTransitions = transitions {
        from(ClockScenes.smallClockScene, to = ClockScenes.largeClockScene) {
            transitioningToLargeClock()
        }
        from(ClockScenes.largeClockScene, to = ClockScenes.smallClockScene) {
            transitioningToSmallClock()
        }
    }

    private fun TransitionBuilder.transitioningToLargeClock() {
        spec = tween(durationMillis = STATUS_AREA_MOVE_UP_MILLIS.toInt())
        timestampRange(
            startMillis = CLOCK_IN_START_DELAY_MILLIS.toInt(),
            endMillis = (CLOCK_IN_START_DELAY_MILLIS + CLOCK_IN_MILLIS).toInt()
        ) {
            fade(largeClockElementKey)
        }

        timestampRange(endMillis = CLOCK_OUT_MILLIS.toInt()) { fade(smallClockElementKey) }
        anchoredTranslate(smallClockElementKey, smartspaceElementKey)
    }

    private fun TransitionBuilder.transitioningToSmallClock() {
        spec = tween(durationMillis = STATUS_AREA_MOVE_DOWN_MILLIS.toInt())
        timestampRange(
            startMillis = CLOCK_IN_START_DELAY_MILLIS.toInt(),
            endMillis = (CLOCK_IN_START_DELAY_MILLIS + CLOCK_IN_MILLIS).toInt()
        ) {
            fade(smallClockElementKey)
        }

        timestampRange(endMillis = CLOCK_OUT_MILLIS.toInt()) { fade(largeClockElementKey) }
        anchoredTranslate(smallClockElementKey, smartspaceElementKey)
    }
}

object ClockScenes {
    val smallClockScene = SceneKey("small-clock-scene")
    val largeClockScene = SceneKey("large-clock-scene")
}

object ClockElementKeys {
    val largeClockElementKey = ElementKey("large-clock")
    val smallClockElementKey = ElementKey("small-clock")
    val smartspaceElementKey = ElementKey("smart-space")
}
+1 −45
Original line number Diff line number Diff line
@@ -17,19 +17,14 @@
package com.android.systemui.keyguard.ui.composable.blueprint

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.IntRect
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
@@ -38,11 +33,8 @@ import com.android.systemui.keyguard.ui.composable.section.LockSection
import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection
import com.android.systemui.keyguard.ui.composable.section.NotificationSection
import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.media.controls.ui.composable.MediaCarousel
import com.android.systemui.res.R
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoSet
@@ -59,14 +51,12 @@ constructor(
    private val viewModel: LockscreenContentViewModel,
    private val statusBarSection: StatusBarSection,
    private val clockSection: DefaultClockSection,
    private val smartSpaceSection: SmartSpaceSection,
    private val notificationSection: NotificationSection,
    private val lockSection: LockSection,
    private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
    private val bottomAreaSection: BottomAreaSection,
    private val settingsMenuSection: SettingsMenuSection,
    private val mediaCarouselSection: MediaCarouselSection,
    private val clockInteractor: KeyguardClockInteractor,
) : ComposableLockscreenSceneBlueprint {

    override val id: String = "default"
@@ -74,7 +64,6 @@ constructor(
    @Composable
    override fun SceneScope.Content(modifier: Modifier) {
        val isUdfpsVisible = viewModel.isUdfpsVisible
        val burnIn = rememberBurnIn(clockInteractor)
        val resources = LocalContext.current.resources

        LockscreenLongPress(
@@ -88,40 +77,7 @@ constructor(
                        modifier = Modifier.fillMaxWidth(),
                    ) {
                        with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
                        with(clockSection) {
                            SmallClock(
                                burnInParams = burnIn.parameters,
                                onTopChanged = burnIn.onSmallClockTopChanged,
                                modifier = Modifier.fillMaxWidth(),
                            )
                        }
                        with(smartSpaceSection) {
                            SmartSpace(
                                burnInParams = burnIn.parameters,
                                onTopChanged = burnIn.onSmartspaceTopChanged,
                                modifier =
                                    Modifier.fillMaxWidth()
                                        .padding(
                                            top = { viewModel.getSmartSpacePaddingTop(resources) },
                                        )
                                        .padding(
                                            bottom =
                                                dimensionResource(
                                                    R.dimen.keyguard_status_view_bottom_margin
                                                ),
                                        ),
                            )
                        }

                        if (viewModel.isLargeClockVisible) {
                            Spacer(modifier = Modifier.weight(weight = 1f))
                            with(clockSection) {
                                LargeClock(
                                    modifier = Modifier.fillMaxWidth(),
                                )
                            }
                        }

                        with(clockSection) { DefaultClockLayout() }
                        with(mediaCarouselSection) { MediaCarousel() }

                        if (viewModel.areNotificationsVisible(resources = resources)) {
+1 −40
Original line number Diff line number Diff line
@@ -17,19 +17,14 @@
package com.android.systemui.keyguard.ui.composable.blueprint

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.IntRect
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
@@ -38,10 +33,8 @@ import com.android.systemui.keyguard.ui.composable.section.LockSection
import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection
import com.android.systemui.keyguard.ui.composable.section.NotificationSection
import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.res.R
import dagger.Binds
import dagger.Module
import dagger.multibindings.IntoSet
@@ -58,14 +51,12 @@ constructor(
    private val viewModel: LockscreenContentViewModel,
    private val statusBarSection: StatusBarSection,
    private val clockSection: DefaultClockSection,
    private val smartSpaceSection: SmartSpaceSection,
    private val notificationSection: NotificationSection,
    private val lockSection: LockSection,
    private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
    private val bottomAreaSection: BottomAreaSection,
    private val settingsMenuSection: SettingsMenuSection,
    private val mediaCarouselSection: MediaCarouselSection,
    private val clockInteractor: KeyguardClockInteractor,
) : ComposableLockscreenSceneBlueprint {

    override val id: String = "shortcuts-besides-udfps"
@@ -73,7 +64,6 @@ constructor(
    @Composable
    override fun SceneScope.Content(modifier: Modifier) {
        val isUdfpsVisible = viewModel.isUdfpsVisible
        val burnIn = rememberBurnIn(clockInteractor)
        val resources = LocalContext.current.resources

        LockscreenLongPress(
@@ -87,36 +77,7 @@ constructor(
                        modifier = Modifier.fillMaxWidth(),
                    ) {
                        with(statusBarSection) { StatusBar(modifier = Modifier.fillMaxWidth()) }
                        with(clockSection) {
                            SmallClock(
                                onTopChanged = burnIn.onSmallClockTopChanged,
                                modifier = Modifier.fillMaxWidth(),
                                burnInParams = burnIn.parameters,
                            )
                        }
                        with(smartSpaceSection) {
                            SmartSpace(
                                burnInParams = burnIn.parameters,
                                onTopChanged = burnIn.onSmartspaceTopChanged,
                                modifier =
                                    Modifier.fillMaxWidth()
                                        .padding(
                                            top = { viewModel.getSmartSpacePaddingTop(resources) }
                                        )
                                        .padding(
                                            bottom =
                                                dimensionResource(
                                                    R.dimen.keyguard_status_view_bottom_margin
                                                )
                                        ),
                            )
                        }

                        if (viewModel.isLargeClockVisible) {
                            Spacer(modifier = Modifier.weight(weight = 1f))
                            with(clockSection) { LargeClock(modifier = Modifier.fillMaxWidth()) }
                        }

                        with(clockSection) { DefaultClockLayout() }
                        with(mediaCarouselSection) { MediaCarousel() }

                        if (viewModel.areNotificationsVisible(resources = resources)) {
+1 −43
Original line number Diff line number Diff line
@@ -18,7 +18,6 @@ package com.android.systemui.keyguard.ui.composable.blueprint

import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth
@@ -27,7 +26,6 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.layout.Layout
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.res.dimensionResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.IntRect
@@ -35,7 +33,6 @@ import androidx.compose.ui.unit.dp
import com.android.compose.animation.scene.SceneScope
import com.android.compose.modifiers.padding
import com.android.systemui.Flags
import com.android.systemui.keyguard.domain.interactor.KeyguardClockInteractor
import com.android.systemui.keyguard.ui.composable.LockscreenLongPress
import com.android.systemui.keyguard.ui.composable.section.AmbientIndicationSection
import com.android.systemui.keyguard.ui.composable.section.BottomAreaSection
@@ -44,7 +41,6 @@ import com.android.systemui.keyguard.ui.composable.section.LockSection
import com.android.systemui.keyguard.ui.composable.section.MediaCarouselSection
import com.android.systemui.keyguard.ui.composable.section.NotificationSection
import com.android.systemui.keyguard.ui.composable.section.SettingsMenuSection
import com.android.systemui.keyguard.ui.composable.section.SmartSpaceSection
import com.android.systemui.keyguard.ui.composable.section.StatusBarSection
import com.android.systemui.keyguard.ui.viewmodel.LockscreenContentViewModel
import com.android.systemui.res.R
@@ -65,14 +61,12 @@ constructor(
    private val viewModel: LockscreenContentViewModel,
    private val statusBarSection: StatusBarSection,
    private val clockSection: DefaultClockSection,
    private val smartSpaceSection: SmartSpaceSection,
    private val notificationSection: NotificationSection,
    private val lockSection: LockSection,
    private val ambientIndicationSectionOptional: Optional<AmbientIndicationSection>,
    private val bottomAreaSection: BottomAreaSection,
    private val settingsMenuSection: SettingsMenuSection,
    private val mediaCarouselSection: MediaCarouselSection,
    private val clockInteractor: KeyguardClockInteractor,
    private val largeScreenHeaderHelper: LargeScreenHeaderHelper,
) : ComposableLockscreenSceneBlueprint {

@@ -81,8 +75,6 @@ constructor(
    @Composable
    override fun SceneScope.Content(modifier: Modifier) {
        val isUdfpsVisible = viewModel.isUdfpsVisible
        val burnIn = rememberBurnIn(clockInteractor)
        val resources = LocalContext.current.resources

        LockscreenLongPress(
            viewModel = viewModel.longPress,
@@ -102,41 +94,7 @@ constructor(
                                modifier = Modifier.fillMaxHeight().weight(weight = 1f),
                                horizontalAlignment = Alignment.CenterHorizontally,
                            ) {
                                with(clockSection) {
                                    SmallClock(
                                        burnInParams = burnIn.parameters,
                                        onTopChanged = burnIn.onSmallClockTopChanged,
                                        modifier = Modifier.fillMaxWidth(),
                                    )
                                }

                                with(smartSpaceSection) {
                                    SmartSpace(
                                        burnInParams = burnIn.parameters,
                                        onTopChanged = burnIn.onSmartspaceTopChanged,
                                        modifier =
                                            Modifier.fillMaxWidth()
                                                .padding(
                                                    top = {
                                                        viewModel.getSmartSpacePaddingTop(resources)
                                                    },
                                                )
                                                .padding(
                                                    bottom =
                                                        dimensionResource(
                                                            R.dimen
                                                                .keyguard_status_view_bottom_margin
                                                        )
                                                ),
                                    )
                                }

                                if (viewModel.isLargeClockVisible) {
                                    Spacer(modifier = Modifier.weight(weight = 1f))
                                    with(clockSection) { LargeClock() }
                                    Spacer(modifier = Modifier.weight(weight = 1f))
                                }

                                with(clockSection) { DefaultClockLayout() }
                                with(mediaCarouselSection) { MediaCarousel() }
                            }
                            with(notificationSection) {
Loading