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

Commit 252cd499 authored by Matt Pietal's avatar Matt Pietal Committed by Android (Google) Code Review
Browse files

Merge "Build in shade support into KeyguardTransitionAnimationFlow" into main

parents e0d44fbd db0f0d36
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlin.time.Duration.Companion.milliseconds
@@ -46,6 +47,7 @@ class KeyguardTransitionAnimationFlowTest : SysuiTestCase() {
    val testScope = kosmos.testScope
    val animationFlow = kosmos.keyguardTransitionAnimationFlow
    val repository = kosmos.fakeKeyguardTransitionRepository
    val shadeTestUtil by lazy { kosmos.shadeTestUtil }

    private lateinit var underTest: KeyguardTransitionAnimationFlow.FlowBuilder

@@ -290,6 +292,78 @@ class KeyguardTransitionAnimationFlowTest : SysuiTestCase() {
            assertThat(values[0]).isEqualTo(0.3f)
        }

    @Test
    fun sharedFlowWithShadeExpanded() =
        testScope.runTest {
            val flow =
                underTest.sharedFlowWithShade(
                    duration = 1000.milliseconds,
                    onStep = { step, isShadeExpanded -> if (isShadeExpanded) 0f else 1f },
                )
            val values by collectValues(flow)
            shadeTestUtil.setQsExpansion(1f)

            repository.sendTransitionStep(step(0.0f, TransitionState.STARTED))
            repository.sendTransitionStep(step(0.3f, TransitionState.RUNNING))

            assertThat(values.size).isEqualTo(2)
            assertThat(values[0]).isEqualTo(0f)
            assertThat(values[0]).isEqualTo(0f)
        }

    @Test
    fun sharedFlowWithShadeNotExpanded() =
        testScope.runTest {
            val flow =
                underTest.sharedFlowWithShade(
                    duration = 1000.milliseconds,
                    onStep = { step, isShadeExpanded -> if (isShadeExpanded) 0f else 1f },
                )
            val values by collectValues(flow)
            shadeTestUtil.setQsExpansion(0f)

            repository.sendTransitionStep(step(0.0f, TransitionState.STARTED))
            repository.sendTransitionStep(step(0.3f, TransitionState.RUNNING))

            assertThat(values.size).isEqualTo(2)
            assertThat(values[0]).isEqualTo(1f)
            assertThat(values[0]).isEqualTo(1f)
        }

    @Test
    fun sharedFlowWithShadeExpanded_onCancelRunsWhenSpecified() =
        testScope.runTest {
            val flow =
                underTest.sharedFlowWithShade(
                    duration = 100.milliseconds,
                    onStep = { step, _ -> step },
                    onCancel = { isShadeExpanded -> if (isShadeExpanded) 100f else 200f },
                )
            val animationValues by collectLastValue(flow)
            shadeTestUtil.setQsExpansion(1f)

            repository.sendTransitionStep(step(0.0f, TransitionState.STARTED))
            repository.sendTransitionStep(step(0.5f, TransitionState.CANCELED))
            assertThat(animationValues).isEqualTo(100f)
        }

    @Test
    fun sharedFlowWithShadeNotExpanded_onCancelRunsWhenSpecified() =
        testScope.runTest {
            val flow =
                underTest.sharedFlowWithShade(
                    duration = 100.milliseconds,
                    onStep = { step, _ -> step },
                    onCancel = { isShadeExpanded -> if (isShadeExpanded) 100f else 200f },
                )
            val animationValues by collectLastValue(flow)
            shadeTestUtil.setQsExpansion(0f)

            repository.sendTransitionStep(step(0.0f, TransitionState.STARTED))
            repository.sendTransitionStep(step(0.5f, TransitionState.CANCELED))
            assertThat(animationValues).isEqualTo(200f)
        }

    private fun assertFloat(actual: Float?, expected: Float) {
        assertThat(actual!!).isWithin(0.01f).of(expected)
    }
+0 −1
Original line number Diff line number Diff line
@@ -211,7 +211,6 @@ class LockscreenToOccludedTransitionViewModelTest(flags: FlagsParameterization)
        testScope.runTest {
            val actual by collectLastValue(underTest.deviceEntryParentViewAlpha)
            shadeExpanded(false)
            runCurrent()

            // fade out
            repository.sendTransitionStep(step(0f, TransitionState.STARTED))
+55 −0
Original line number Diff line number Diff line
@@ -29,6 +29,8 @@ import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.shade.domain.interactor.ShadeInteractor
import dagger.Lazy
import javax.inject.Inject
import kotlin.math.max
import kotlin.math.min
@@ -38,6 +40,8 @@ import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.mapNotNull

typealias IsShadeExpanded = Boolean

/**
 * Assists in creating sub-flows for a KeyguardTransition. Call [setup] once for a transition, and
 * then [sharedFlow] for each sub animation that should be trigged when the overall transition runs.
@@ -48,6 +52,7 @@ class KeyguardTransitionAnimationFlow
constructor(
    private val transitionInteractor: KeyguardTransitionInteractor,
    private val logger: KeyguardTransitionAnimationLogger,
    private val shadeInteractor: Lazy<ShadeInteractor>,
) {
    /** Invoke once per transition between FROM->TO states to get access to a shared flow. */
    fun setup(duration: Duration, edge: Edge): FlowBuilder {
@@ -94,6 +99,56 @@ constructor(
                .mapNotNull { stateToValue -> stateToValue.value }
        }

        /**
         * Transitions will occur over a [transitionDuration] with [TransitionStep]s being emitted
         * in the range of [0, 1]. View animations should begin and end within a subset of this
         * range. This function maps the [startTime] and [duration] into [0, 1], when this subset is
         * valid.
         *
         * This overload provides additional information about the shade expansion state as recorded
         * when STARTED was emitted.
         *
         * Note that [onStep] accepts a null return value. When null, no animation information will
         * be emitted, effectively saying "do not change the value on this frame"
         *
         * Note that [onCancel] isn't used when the scene framework is enabled.
         */
        fun sharedFlowWithShade(
            duration: Duration = transitionDuration,
            onStep: (Float, IsShadeExpanded) -> Float?,
            startTime: Duration = 0.milliseconds,
            onStart: (() -> Unit)? = null,
            onCancel: ((IsShadeExpanded) -> Float)? = null,
            onFinish: ((IsShadeExpanded) -> Float)? = null,
            interpolator: Interpolator = LINEAR,
            name: String? = null,
        ): Flow<Float> {
            var isShadeExpanded = false
            return sharedFlow(
                duration = duration,
                onStep = { step -> onStep(step, isShadeExpanded) },
                startTime = startTime,
                onStart = {
                    isShadeExpanded = shadeInteractor.get().isAnyFullyExpanded.value
                    if (onStart != null) onStart()
                },
                onCancel =
                    if (onCancel != null) {
                        { onCancel(isShadeExpanded) }
                    } else {
                        null
                    },
                onFinish =
                    if (onFinish != null) {
                        { onFinish(isShadeExpanded) }
                    } else {
                        null
                    },
                interpolator = interpolator,
                name = name,
            )
        }

        /**
         * Transitions will occur over a [transitionDuration] with [TransitionStep]s being emitted
         * in the range of [0, 1]. View animations should begin and end within a subset of this
+42 −30
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Overlays
import com.android.systemui.scene.ui.composable.transitions.TO_BOUNCER_FADE_FRACTION
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.emptyFlow

@@ -40,11 +41,8 @@ import kotlinx.coroutines.flow.emptyFlow
@SysUISingleton
class AlternateBouncerToPrimaryBouncerTransitionViewModel
@Inject
constructor(
    animationFlow: KeyguardTransitionAnimationFlow,
    blurConfig: BlurConfig,
    shadeDependentFlows: ShadeDependentFlows,
) : DeviceEntryIconTransition, PrimaryBouncerTransition {
constructor(animationFlow: KeyguardTransitionAnimationFlow, blurConfig: BlurConfig) :
    DeviceEntryIconTransition, PrimaryBouncerTransition {
    private val transitionAnimation =
        animationFlow
            .setup(
@@ -73,9 +71,17 @@ constructor(

    val notificationAlpha: Flow<Float> =
        if (Flags.bouncerUiRevamp()) {
            shadeDependentFlows.transitionFlow(
                flowWhenShadeIsNotExpanded = lockscreenAlpha,
                flowWhenShadeIsExpanded = transitionAnimation.immediatelyTransitionTo(1f),
            transitionAnimation.sharedFlowWithShade(
                duration = FromAlternateBouncerTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION,
                onStep = { step, isShadeExpanded ->
                    if (isShadeExpanded) {
                        1f
                    } else if (Flags.bouncerUiRevamp()) {
                        alphaForAnimationStep(step)
                    } else {
                        null
                    }
                },
            )
        } else {
            alphaFlow
@@ -83,10 +89,11 @@ constructor(

    override val notificationBlurRadius: Flow<Float> =
        if (Flags.bouncerUiRevamp()) {
            shadeDependentFlows.transitionFlow(
                flowWhenShadeIsNotExpanded = emptyFlow(),
                flowWhenShadeIsExpanded =
                    transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx),
            transitionAnimation.sharedFlowWithShade(
                duration = 1.milliseconds,
                onStep = { _, isShadeExpanded ->
                    if (isShadeExpanded) blurConfig.maxBlurRadiusPx else null
                },
            )
        } else {
            emptyFlow<Float>()
@@ -96,24 +103,29 @@ constructor(
        transitionAnimation.immediatelyTransitionTo(0f)

    override val windowBlurRadius: Flow<Float> =
        shadeDependentFlows.transitionFlow(
            flowWhenShadeIsExpanded =
        transitionAnimation.sharedFlowWithShade(
            duration = FromAlternateBouncerTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION,
            onStep = { step, isShadeExpanded ->
                if (isShadeExpanded) {
                    if (Flags.notificationShadeBlur()) {
                    transitionAnimation.immediatelyTransitionTo(blurConfig.maxBlurRadiusPx)
                        blurConfig.maxBlurRadiusPx
                    } else {
                        blurConfig.minBlurRadiusPx
                    }
                } else {
                    transitionAnimation.immediatelyTransitionTo(blurConfig.minBlurRadiusPx)
                },
            flowWhenShadeIsNotExpanded =
                transitionAnimation.sharedFlow(
                    duration = FromAlternateBouncerTransitionInteractor.TO_PRIMARY_BOUNCER_DURATION,
                    onStep = { step ->
                    transitionProgressToBlurRadius(
                        starBlurRadius = blurConfig.minBlurRadiusPx,
                        endBlurRadius = blurConfig.maxBlurRadiusPx,
                        transitionProgress = step,
                    )
                }
            },
            onFinish = { isShadeExpanded ->
                if (isShadeExpanded && !Flags.notificationShadeBlur()) {
                    blurConfig.minBlurRadiusPx
                } else {
                    blurConfig.maxBlurRadiusPx
                }
            },
                    onFinish = { blurConfig.maxBlurRadiusPx },
                ),
        )
}
+25 −47
Original line number Diff line number Diff line
@@ -29,7 +29,6 @@ import com.android.systemui.keyguard.ui.StateToValue
import com.android.systemui.keyguard.ui.transitions.DeviceEntryIconTransition
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.power.shared.model.WakeSleepReason.FOLD
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.flow.Flow
@@ -45,7 +44,6 @@ class LockscreenToAodTransitionViewModel
constructor(
    deviceEntryUdfpsInteractor: DeviceEntryUdfpsInteractor,
    private val powerInteractor: PowerInteractor,
    shadeDependentFlows: ShadeDependentFlows,
    animationFlow: KeyguardTransitionAnimationFlow,
) : DeviceEntryIconTransition {

@@ -62,15 +60,11 @@ constructor(
        )

    val deviceEntryBackgroundViewAlpha: Flow<Float> =
        shadeDependentFlows.transitionFlow(
            flowWhenShadeIsExpanded = transitionAnimation.immediatelyTransitionTo(0f),
            flowWhenShadeIsNotExpanded =
                transitionAnimation.sharedFlow(
        transitionAnimation.sharedFlowWithShade(
            duration = 300.milliseconds,
                    onStep = { 1 - it },
            onStep = { step, isShadeExpanded -> if (isShadeExpanded) 0f else 1 - step },
            onCancel = { 0f },
            onFinish = { 0f },
                ),
        )

    val shortcutsAlpha: Flow<Float> =
@@ -89,8 +83,8 @@ constructor(
                onStart = { startAlpha = viewState.alpha() },
                onStep = { MathUtils.lerp(startAlpha, 1f, it) },
            )
            .sample(powerInteractor.detailedWakefulness, ::Pair)
            .transform { (alpha, wakefulness) ->
            .transform { alpha ->
                val wakefulness = powerInteractor.detailedWakefulness.value
                if (wakefulness.lastSleepReason != FOLD) {
                    emit(alpha)
                }
@@ -99,13 +93,9 @@ constructor(

    val lockscreenAlphaOnFold: Flow<Float> =
        transitionAnimationOnFold
            .sharedFlow(
                startTime = 600.milliseconds,
                duration = 500.milliseconds,
                onStep = { it },
            )
            .sample(powerInteractor.detailedWakefulness, ::Pair)
            .transform { (alpha, wakefulness) ->
            .sharedFlow(startTime = 600.milliseconds, duration = 500.milliseconds, onStep = { it })
            .transform { alpha ->
                val wakefulness = powerInteractor.detailedWakefulness.value
                if (wakefulness.lastSleepReason == FOLD) {
                    emit(alpha)
                }
@@ -113,13 +103,9 @@ constructor(

    val notificationAlphaOnFold: Flow<Float> =
        transitionAnimationOnFold
            .sharedFlow(
                duration = 1100.milliseconds,
                onStep = { 0f },
                onFinish = { 1f },
            )
            .sample(powerInteractor.detailedWakefulness, ::Pair)
            .transform { (alpha, wakefulness) ->
            .sharedFlow(duration = 1100.milliseconds, onStep = { 0f }, onFinish = { 1f })
            .transform { alpha ->
                val wakefulness = powerInteractor.detailedWakefulness.value
                if (wakefulness.lastSleepReason == FOLD) {
                    emit(alpha)
                }
@@ -135,8 +121,8 @@ constructor(
                onFinish = { 0f },
                interpolator = EMPHASIZED_DECELERATE,
            )
            .sample(powerInteractor.detailedWakefulness, ::Pair)
            .transform { (stateToValue, wakefulness) ->
            .transform { stateToValue ->
                val wakefulness = powerInteractor.detailedWakefulness.value
                if (wakefulness.lastSleepReason == FOLD) {
                    emit(stateToValue)
                }
@@ -147,26 +133,18 @@ constructor(
        deviceEntryUdfpsInteractor.isUdfpsEnrolledAndEnabled.flatMapLatest {
            isUdfpsEnrolledAndEnabled ->
            if (isUdfpsEnrolledAndEnabled) {
                shadeDependentFlows.transitionFlow(
                    flowWhenShadeIsExpanded = // fade in
                    transitionAnimation.sharedFlow(
                transitionAnimation.sharedFlowWithShade(
                    duration = 300.milliseconds,
                            onStep = { it },
                    onStep = { step, isShadeExpanded -> if (isShadeExpanded) step else 1f },
                    onCancel = { 1f },
                    onFinish = { 1f },
                        ),
                    flowWhenShadeIsNotExpanded = transitionAnimation.immediatelyTransitionTo(1f),
                )
            } else {
                shadeDependentFlows.transitionFlow(
                    flowWhenShadeIsExpanded = transitionAnimation.immediatelyTransitionTo(0f),
                    flowWhenShadeIsNotExpanded = // fade out
                    transitionAnimation.sharedFlow(
                transitionAnimation.sharedFlowWithShade(
                    duration = 200.milliseconds,
                            onStep = { 1f - it },
                    onStep = { step, isShadeExpanded -> if (isShadeExpanded) 0f else 1f - step },
                    onCancel = { 0f },
                    onFinish = { 0f },
                        ),
                )
            }
        }
Loading