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

Commit de0c58bc authored by Andreas Miko's avatar Andreas Miko Committed by Android (Google) Code Review
Browse files

Merge "Fix new lightreveal transition" into udc-qpr-dev

parents 3e467247 3871e2d3
Loading
Loading
Loading
Loading
+33 −6
Original line number Diff line number Diff line
@@ -20,10 +20,13 @@ package com.android.systemui.keyguard.data.repository

import android.content.Context
import android.graphics.Point
import androidx.core.animation.Animator
import androidx.core.animation.ValueAnimator
import com.android.systemui.R
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.BiometricUnlockSource
import com.android.systemui.keyguard.shared.model.WakeSleepReason.TAP
import com.android.systemui.statusbar.CircleReveal
import com.android.systemui.statusbar.LiftReveal
import com.android.systemui.statusbar.LightRevealEffect
@@ -31,9 +34,12 @@ import com.android.systemui.statusbar.PowerButtonReveal
import javax.inject.Inject
import kotlin.math.max
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
@@ -52,6 +58,10 @@ interface LightRevealScrimRepository {
     * at the current screen position of the appropriate sensor.
     */
    val revealEffect: Flow<LightRevealEffect>

    val revealAmount: Flow<Float>

    fun startRevealAmountAnimator(reveal: Boolean)
}

@SysUISingleton
@@ -108,14 +118,31 @@ constructor(

    /** The reveal effect we'll use for the next non-biometric unlock (tap, power button, etc). */
    private val nonBiometricRevealEffect: Flow<LightRevealEffect?> =
        keyguardRepository.wakefulness.flatMapLatest { wakefulnessModel ->
        keyguardRepository.wakefulness
            .filter { it.isStartingToWake() || it.isStartingToSleep() }
            .flatMapLatest { wakefulnessModel ->
                when {
                    wakefulnessModel.isTransitioningFromPowerButton() -> powerButtonRevealEffect
                wakefulnessModel.isAwakeFromTap() -> tapRevealEffect
                    wakefulnessModel.isWakingFrom(TAP) -> tapRevealEffect
                    else -> flowOf(LiftReveal)
                }
            }

    private val revealAmountAnimator = ValueAnimator.ofFloat(0f, 1f).apply { duration = 500 }

    override val revealAmount: Flow<Float> = callbackFlow {
        val updateListener =
            Animator.AnimatorUpdateListener {
                trySend((it as ValueAnimator).animatedValue as Float)
            }
        revealAmountAnimator.addUpdateListener(updateListener)
        awaitClose { revealAmountAnimator.removeUpdateListener(updateListener) }
    }

    override fun startRevealAmountAnimator(reveal: Boolean) {
        if (reveal) revealAmountAnimator.start() else revealAmountAnimator.reverse()
    }

    override val revealEffect =
        combine(
                keyguardRepository.biometricUnlockState,
+24 −18
Original line number Diff line number Diff line
@@ -17,28 +17,44 @@
package com.android.systemui.keyguard.domain.interactor

import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.dagger.qualifiers.Application
import com.android.systemui.keyguard.data.repository.LightRevealScrimRepository
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.statusbar.LightRevealEffect
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.launch

@ExperimentalCoroutinesApi
@SysUISingleton
class LightRevealScrimInteractor
@Inject
constructor(
    transitionRepository: KeyguardTransitionRepository,
    transitionInteractor: KeyguardTransitionInteractor,
    lightRevealScrimRepository: LightRevealScrimRepository,
    private val transitionInteractor: KeyguardTransitionInteractor,
    private val lightRevealScrimRepository: LightRevealScrimRepository,
    @Application private val scope: CoroutineScope,
) {

    init {
        listenForStartedKeyguardTransitionStep()
    }

    private fun listenForStartedKeyguardTransitionStep() {
        scope.launch {
            transitionInteractor.startedKeyguardTransitionStep.collect {
                if (willTransitionChangeEndState(it)) {
                    lightRevealScrimRepository.startRevealAmountAnimator(
                        willBeRevealedInState(it.to)
                    )
                }
            }
        }
    }

    /**
     * Whenever a keyguard transition starts, sample the latest reveal effect from the repository
     * and use that for the starting transition.
@@ -54,17 +70,7 @@ constructor(
            lightRevealScrimRepository.revealEffect
        )

    /**
     * The reveal amount to use for the light reveal scrim, which is derived from the keyguard
     * transition steps.
     */
    val revealAmount: Flow<Float> =
        transitionRepository.transitions
            // Only listen to transitions that change the reveal amount.
            .filter { willTransitionAffectRevealAmount(it) }
            // Use the transition amount as the reveal amount, inverting it if we're transitioning
            // to a non-revealed (hidden) state.
            .map { step -> if (willBeRevealedInState(step.to)) step.value else 1f - step.value }
    val revealAmount = lightRevealScrimRepository.revealAmount

    companion object {

@@ -72,7 +78,7 @@ constructor(
         * Whether the transition requires a change in the reveal amount of the light reveal scrim.
         * If not, we don't care about the transition and don't need to listen to it.
         */
        fun willTransitionAffectRevealAmount(transition: TransitionStep): Boolean {
        fun willTransitionChangeEndState(transition: TransitionStep): Boolean {
            return willBeRevealedInState(transition.from) != willBeRevealedInState(transition.to)
        }

+20 −15
Original line number Diff line number Diff line
@@ -16,6 +16,13 @@
package com.android.systemui.keyguard.shared.model

import com.android.systemui.keyguard.WakefulnessLifecycle
import com.android.systemui.keyguard.shared.model.WakeSleepReason.GESTURE
import com.android.systemui.keyguard.shared.model.WakeSleepReason.POWER_BUTTON
import com.android.systemui.keyguard.shared.model.WakeSleepReason.TAP
import com.android.systemui.keyguard.shared.model.WakefulnessState.ASLEEP
import com.android.systemui.keyguard.shared.model.WakefulnessState.AWAKE
import com.android.systemui.keyguard.shared.model.WakefulnessState.STARTING_TO_SLEEP
import com.android.systemui.keyguard.shared.model.WakefulnessState.STARTING_TO_WAKE

/** Model device wakefulness states. */
data class WakefulnessModel(
@@ -23,33 +30,31 @@ data class WakefulnessModel(
    val lastWakeReason: WakeSleepReason,
    val lastSleepReason: WakeSleepReason,
) {
    fun isStartingToWake() = state == WakefulnessState.STARTING_TO_WAKE
    fun isStartingToWake() = state == STARTING_TO_WAKE

    fun isStartingToSleep() = state == WakefulnessState.STARTING_TO_SLEEP
    fun isStartingToSleep() = state == STARTING_TO_SLEEP

    private fun isAsleep() = state == WakefulnessState.ASLEEP
    private fun isAsleep() = state == ASLEEP

    private fun isAwake() = state == AWAKE

    fun isStartingToWakeOrAwake() = isStartingToWake() || isAwake()

    fun isStartingToSleepOrAsleep() = isStartingToSleep() || isAsleep()

    fun isDeviceInteractive() = !isAsleep()

    fun isStartingToWakeOrAwake() = isStartingToWake() || state == WakefulnessState.AWAKE
    fun isWakingFrom(wakeSleepReason: WakeSleepReason) =
        isStartingToWake() && lastWakeReason == wakeSleepReason

    fun isStartingToSleepFromPowerButton() =
        isStartingToSleep() && lastWakeReason == WakeSleepReason.POWER_BUTTON

    fun isWakingFromPowerButton() =
        isStartingToWake() && lastWakeReason == WakeSleepReason.POWER_BUTTON
    fun isStartingToSleepFrom(wakeSleepReason: WakeSleepReason) =
        isStartingToSleep() && lastSleepReason == wakeSleepReason

    fun isTransitioningFromPowerButton() =
        isStartingToSleepFromPowerButton() || isWakingFromPowerButton()

    fun isAwakeFromTap() =
        state == WakefulnessState.STARTING_TO_WAKE && lastWakeReason == WakeSleepReason.TAP
        isStartingToSleepFrom(POWER_BUTTON) || isWakingFrom(POWER_BUTTON)

    fun isDeviceInteractiveFromTapOrGesture(): Boolean {
        return isDeviceInteractive() &&
            (lastWakeReason == WakeSleepReason.TAP || lastWakeReason == WakeSleepReason.GESTURE)
        return isDeviceInteractive() && (lastWakeReason == TAP || lastWakeReason == GESTURE)
    }

    companion object {
+2 −4
Original line number Diff line number Diff line
@@ -20,20 +20,18 @@ import com.android.systemui.doze.util.BurnInHelperWrapper
import com.android.systemui.keyguard.domain.interactor.KeyguardBottomAreaInteractor
import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.map

/** View-model for the keyguard indication area view */
@OptIn(ExperimentalCoroutinesApi::class)
class KeyguardIndicationAreaViewModel
@Inject
constructor(
    private val keyguardInteractor: KeyguardInteractor,
    private val bottomAreaInteractor: KeyguardBottomAreaInteractor,
    private val keyguardBottomAreaViewModel: KeyguardBottomAreaViewModel,
    bottomAreaInteractor: KeyguardBottomAreaInteractor,
    keyguardBottomAreaViewModel: KeyguardBottomAreaViewModel,
    private val burnInHelperWrapper: BurnInHelperWrapper,
) {

+2 −0
Original line number Diff line number Diff line
@@ -19,12 +19,14 @@ package com.android.systemui.keyguard.ui.viewmodel
import com.android.systemui.keyguard.domain.interactor.LightRevealScrimInteractor
import com.android.systemui.statusbar.LightRevealEffect
import javax.inject.Inject
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow

/**
 * Models UI state for the light reveal scrim, which is used during screen on and off animations to
 * draw a gradient that reveals/hides the contents of the screen.
 */
@OptIn(ExperimentalCoroutinesApi::class)
class LightRevealScrimViewModel @Inject constructor(interactor: LightRevealScrimInteractor) {
    val lightRevealEffect: Flow<LightRevealEffect> = interactor.lightRevealEffect
    val revealAmount: Flow<Float> = interactor.revealAmount
Loading