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

Commit 77e3baab authored by Josh Tsuji's avatar Josh Tsuji Committed by Android (Google) Code Review
Browse files

Merge changes Ia239ec9b,I7eaf5cda into main

* changes:
  Ignore keyguard transitions FROM an invalid state.
  Add currentTransitionInfo + filterRelevantKeyguardState.
parents c79b5379 ddd79371
Loading
Loading
Loading
Loading
+94 −62
Original line number Diff line number Diff line
@@ -23,6 +23,7 @@ import android.annotation.FloatRange
import android.os.Trace
import android.util.Log
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
@@ -30,12 +31,17 @@ import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import java.util.UUID
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.channels.BufferOverflow
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.asSharedFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.withContext

/**
 * The source of truth for all keyguard transitions.
@@ -65,6 +71,9 @@ interface KeyguardTransitionRepository {
     */
    val transitions: Flow<TransitionStep>

    /** The [TransitionInfo] of the most recent call to [startTransition]. */
    val currentTransitionInfoInternal: StateFlow<TransitionInfo>

    /**
     * Interactors that require information about changes between [KeyguardState]s will call this to
     * register themselves for flowable [TransitionStep]s when that transition occurs.
@@ -77,7 +86,7 @@ interface KeyguardTransitionRepository {
     * Begin a transition from one state to another. Transitions are interruptible, and will issue a
     * [TransitionStep] with state = [TransitionState.CANCELED] before beginning the next one.
     */
    fun startTransition(info: TransitionInfo): UUID?
    suspend fun startTransition(info: TransitionInfo): UUID?

    /**
     * Allows manual control of a transition. When calling [startTransition], the consumer must pass
@@ -95,7 +104,11 @@ interface KeyguardTransitionRepository {
}

@SysUISingleton
class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitionRepository {
class KeyguardTransitionRepositoryImpl
@Inject
constructor(
    @Main val mainDispatcher: CoroutineDispatcher,
) : KeyguardTransitionRepository {
    /*
     * Each transition between [KeyguardState]s will have an associated Flow.
     * In order to collect these events, clients should call [transition].
@@ -110,6 +123,17 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
    private var lastStep: TransitionStep = TransitionStep()
    private var lastAnimator: ValueAnimator? = null

    private val _currentTransitionInfo: MutableStateFlow<TransitionInfo> =
        MutableStateFlow(
            TransitionInfo(
                ownerName = "",
                from = KeyguardState.OFF,
                to = KeyguardState.LOCKSCREEN,
                animator = null
            )
        )
    override var currentTransitionInfoInternal = _currentTransitionInfo.asStateFlow()

    /*
     * When manual control of the transition is requested, a unique [UUID] is used as the handle
     * to permit calls to [updateTransition]
@@ -122,10 +146,14 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
        initialTransitionSteps.forEach(::emitTransition)
    }

    override fun startTransition(info: TransitionInfo): UUID? {
    override suspend fun startTransition(info: TransitionInfo): UUID? {
        _currentTransitionInfo.value = info

        // Animators must be started on the main thread.
        return withContext(mainDispatcher) {
            if (lastStep.from == info.from && lastStep.to == info.to) {
                Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
            return null
                return@withContext null
            }
            val startingValue =
                if (lastStep.transitionState != TransitionState.FINISHED) {
@@ -160,10 +188,13 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
                        )
                    )
                }

                val adapter =
                    object : AnimatorListenerAdapter() {
                        override fun onAnimationStart(animation: Animator) {
                        emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED))
                            emitTransition(
                                TransitionStep(info, startingValue, TransitionState.STARTED)
                            )
                        }

                        override fun onAnimationCancel(animation: Animator) {
@@ -184,14 +215,15 @@ class KeyguardTransitionRepositoryImpl @Inject constructor() : KeyguardTransitio
                animator.addListener(adapter)
                animator.addUpdateListener(updateListener)
                animator.start()
            return@startTransition null
                return@withContext null
            }
                ?: run {
                    emitTransition(TransitionStep(info, startingValue, TransitionState.STARTED))

                    // No animator, so it's manual. Provide a mechanism to callback
                    updateTransitionId = UUID.randomUUID()
                return@startTransition updateTransitionId
                    return@withContext updateTransitionId
                }
        }
    }

+21 −36
Original line number Diff line number Diff line
@@ -100,24 +100,15 @@ constructor(
                .onEach { delay(150L) }
                .sampleCombine(
                    keyguardInteractor.primaryBouncerShowing,
                    startedKeyguardTransitionStep,
                    powerInteractor.isAwake,
                    keyguardInteractor.isAodAvailable,
                    communalInteractor.isIdleOnCommunal
                )
                .collect {
                    (
                        isAlternateBouncerShowing,
                        isPrimaryBouncerShowing,
                        lastStartedTransitionStep,
                        isAwake,
                        isAodAvailable,
                        isIdleOnCommunal) ->
                    if (
                        !isAlternateBouncerShowing &&
                            !isPrimaryBouncerShowing &&
                            lastStartedTransitionStep.to == KeyguardState.ALTERNATE_BOUNCER
                    ) {
                .filterRelevantKeyguardStateAnd {
                    (isAlternateBouncerShowing, isPrimaryBouncerShowing, _, _, _) ->
                    !isAlternateBouncerShowing && !isPrimaryBouncerShowing
                }
                .collect { (_, _, isAwake, isAodAvailable, isIdleOnCommunal) ->
                    val to =
                        if (!isAwake) {
                            if (isAodAvailable) {
@@ -136,7 +127,6 @@ constructor(
                }
        }
    }
    }

    private fun listenForAlternateBouncerToGone() {
        if (KeyguardWmStateRefactor.isEnabled) {
@@ -158,15 +148,10 @@ constructor(
    private fun listenForAlternateBouncerToPrimaryBouncer() {
        scope.launch {
            keyguardInteractor.primaryBouncerShowing
                .sampleUtil(startedKeyguardTransitionStep, ::Pair)
                .collect { (isPrimaryBouncerShowing, startedKeyguardState) ->
                    if (
                        isPrimaryBouncerShowing &&
                            startedKeyguardState.to == KeyguardState.ALTERNATE_BOUNCER
                    ) {
                        startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
                    }
                .filterRelevantKeyguardStateAnd { isPrimaryBouncerShowing ->
                    isPrimaryBouncerShowing
                }
                .collect { startTransitionTo(KeyguardState.PRIMARY_BOUNCER) }
        }
    }

+14 −29
Original line number Diff line number Diff line
@@ -30,14 +30,12 @@ import com.android.systemui.keyguard.shared.model.TransitionModeOnCanceled
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sample
import com.android.systemui.util.kotlin.sample
import java.util.UUID
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch

@SysUISingleton
@@ -97,14 +95,13 @@ constructor(
            scope.launch {
                powerInteractor.detailedWakefulness
                    // React only to wake events.
                    .filter { it.isAwake() }
                    .filterRelevantKeyguardStateAnd { it.isAwake() }
                    .sample(
                        startedKeyguardTransitionStep,
                        keyguardInteractor.biometricUnlockState,
                        keyguardInteractor.primaryBouncerShowing,
                    )
                    // Make sure we've at least STARTED a transition to AOD.
                    .filter { (_, startedStep, _, _) -> startedStep.to == KeyguardState.AOD }
                    .collect { (_, startedStep, biometricUnlockState, primaryBouncerShowing) ->
                        // Check with the superclass to see if an occlusion transition is needed.
                        // Also, don't react to wake and unlock events, as we'll be receiving a call
@@ -122,6 +119,7 @@ constructor(
            scope.launch {
                keyguardInteractor
                    .dozeTransitionTo(DozeStateModel.FINISH)
                    .filterRelevantKeyguardState()
                    .sample(
                        keyguardInteractor.isKeyguardShowing,
                        startedKeyguardTransitionStep,
@@ -138,7 +136,6 @@ constructor(
                            biometricUnlockState,
                            primaryBouncerShowing) ->
                        if (
                            lastStartedStep.to == KeyguardState.AOD &&
                            !occluded &&
                                !isWakeAndUnlock(biometricUnlockState) &&
                                isKeyguardShowing &&
@@ -164,9 +161,8 @@ constructor(

        scope.launch {
            keyguardInteractor.isKeyguardOccluded
                .sample(startedKeyguardTransitionStep, ::Pair)
                .collect { (isOccluded, lastStartedStep) ->
                    if (isOccluded && lastStartedStep.to == KeyguardState.AOD) {
                .filterRelevantKeyguardStateAnd { isOccluded -> isOccluded }
                .collect {
                    startTransitionTo(
                        toState = KeyguardState.OCCLUDED,
                        modeOnCanceled = TransitionModeOnCanceled.RESET
@@ -174,7 +170,6 @@ constructor(
                }
        }
    }
    }

    /**
     * If there is a biometric lockout and FPS is tapped while on AOD, it should go directly to the
@@ -183,12 +178,8 @@ constructor(
    private fun listenForAodToPrimaryBouncer() {
        scope.launch {
            keyguardInteractor.primaryBouncerShowing
                .sample(startedKeyguardTransitionStep, ::Pair)
                .collect { (isBouncerShowing, lastStartedTransitionStep) ->
                    if (isBouncerShowing && lastStartedTransitionStep.to == KeyguardState.AOD) {
                        startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
                    }
                }
                .filterRelevantKeyguardStateAnd { primaryBouncerShowing -> primaryBouncerShowing }
                .collect { startTransitionTo(KeyguardState.PRIMARY_BOUNCER) }
        }
    }

@@ -201,23 +192,17 @@ constructor(
        scope.launch {
            powerInteractor.isAwake
                .debounce(50L)
                .filterRelevantKeyguardState()
                .sample(
                    keyguardInteractor.biometricUnlockState,
                    startedKeyguardTransitionStep,
                    keyguardInteractor.isKeyguardShowing,
                    keyguardInteractor.isKeyguardDismissible,
                )
                .collect {
                    (
                        isAwake,
                        biometricUnlockState,
                        lastStartedTransitionStep,
                        isKeyguardShowing,
                        isKeyguardDismissible) ->
                .collect { (isAwake, biometricUnlockState, isKeyguardShowing, isKeyguardDismissible)
                    ->
                    KeyguardWmStateRefactor.assertInLegacyMode()
                    if (
                        isAwake &&
                            lastStartedTransitionStep.to == KeyguardState.AOD &&
                            (isWakeAndUnlock(biometricUnlockState) ||
                                (!isKeyguardShowing && isKeyguardDismissible))
                    ) {
+3 −12
Original line number Diff line number Diff line
@@ -35,7 +35,6 @@ import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.launch

@SysUISingleton
@@ -83,9 +82,9 @@ constructor(
        scope.launch {
            powerInteractor.isAwake
                .debounce(50L)
                .filterRelevantKeyguardStateAnd { isAwake -> isAwake }
                .sample(
                    keyguardInteractor.biometricUnlockState,
                    startedKeyguardTransitionStep,
                    keyguardInteractor.isKeyguardOccluded,
                    communalInteractor.isIdleOnCommunal,
                    canDismissLockScreen,
@@ -93,16 +92,12 @@ constructor(
                )
                .collect {
                    (
                        isAwake,
                        _,
                        biometricUnlockState,
                        lastStartedTransition,
                        occluded,
                        isIdleOnCommunal,
                        canDismissLockScreen,
                        primaryBouncerShowing) ->
                    if (!(isAwake && lastStartedTransition.to == KeyguardState.DOZING)) {
                        return@collect
                    }
                    startTransitionTo(
                        if (isWakeAndUnlock(biometricUnlockState)) {
                            KeyguardState.GONE
@@ -130,19 +125,15 @@ constructor(

        scope.launch {
            powerInteractor.detailedWakefulness
                .filter { it.isAwake() }
                .filterRelevantKeyguardStateAnd { it.isAwake() }
                .sample(
                    startedKeyguardTransitionStep,
                    communalInteractor.isIdleOnCommunal,
                    keyguardInteractor.biometricUnlockState,
                    canDismissLockScreen,
                    keyguardInteractor.primaryBouncerShowing,
                )
                // If we haven't at least STARTED a transition to DOZING, ignore.
                .filter { (_, startedStep, _, _) -> startedStep.to == KeyguardState.DOZING }
                .collect {
                    (
                        _,
                        _,
                        isIdleOnCommunal,
                        biometricUnlockState,
+18 −61
Original line number Diff line number Diff line
@@ -26,14 +26,12 @@ import com.android.systemui.keyguard.shared.model.BiometricUnlockModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.power.domain.interactor.PowerInteractor
import com.android.systemui.util.kotlin.Utils.Companion.toTriple
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.delay
import kotlinx.coroutines.flow.combine
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch

@@ -73,91 +71,50 @@ constructor(
                // Add a slight delay to prevent transitioning to lockscreen from happening too soon
                // as dozing can arrive in a slight gap after the lockscreen hosted dream stops.
                .onEach { delay(50) }
                .sample(
                    combine(
                        keyguardInteractor.dozeTransitionModel,
                        startedKeyguardTransitionStep,
                        ::Pair
                    ),
                    ::toTriple
                )
                .collect {
                    (isActiveDreamLockscreenHosted, dozeTransitionModel, lastStartedTransition) ->
                    if (
                .sample(keyguardInteractor.dozeTransitionModel, ::Pair)
                .filterRelevantKeyguardStateAnd {
                    (isActiveDreamLockscreenHosted, dozeTransitionModel) ->
                    !isActiveDreamLockscreenHosted &&
                            DozeStateModel.isDozeOff(dozeTransitionModel.to) &&
                            lastStartedTransition.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED
                    ) {
                        startTransitionTo(KeyguardState.LOCKSCREEN)
                    }
                        DozeStateModel.isDozeOff(dozeTransitionModel.to)
                }
                .collect { startTransitionTo(KeyguardState.LOCKSCREEN) }
        }
    }

    private fun listenForDreamingLockscreenHostedToOccluded() {
        scope.launch {
            keyguardInteractor.isActiveDreamLockscreenHosted
                .sample(
                    combine(
                        keyguardInteractor.isKeyguardOccluded,
                        startedKeyguardTransitionStep,
                        ::Pair,
                    ),
                    ::toTriple
                )
                .collect { (isActiveDreamLockscreenHosted, isOccluded, lastStartedTransition) ->
                    if (
                        isOccluded &&
                            !isActiveDreamLockscreenHosted &&
                            lastStartedTransition.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED
                    ) {
                        startTransitionTo(KeyguardState.OCCLUDED)
                    }
                .sample(keyguardInteractor.isKeyguardOccluded, ::Pair)
                .filterRelevantKeyguardStateAnd { (isActiveDreamLockscreenHosted, isOccluded) ->
                    isOccluded && !isActiveDreamLockscreenHosted
                }
                .collect { startTransitionTo(KeyguardState.OCCLUDED) }
        }
    }

    private fun listenForDreamingLockscreenHostedToPrimaryBouncer() {
        scope.launch {
            keyguardInteractor.primaryBouncerShowing
                .sample(startedKeyguardTransitionStep, ::Pair)
                .collect { (isBouncerShowing, lastStartedTransitionStep) ->
                    if (
                        isBouncerShowing &&
                            lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED
                    ) {
                        startTransitionTo(KeyguardState.PRIMARY_BOUNCER)
                    }
                }
                .filterRelevantKeyguardStateAnd { isBouncerShowing -> isBouncerShowing }
                .collect { startTransitionTo(KeyguardState.PRIMARY_BOUNCER) }
        }
    }

    private fun listenForDreamingLockscreenHostedToGone() {
        scope.launch {
            keyguardInteractor.biometricUnlockState
                .sample(startedKeyguardTransitionStep, ::Pair)
                .collect { (biometricUnlockState, lastStartedTransitionStep) ->
                    if (
                        lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED &&
                .filterRelevantKeyguardStateAnd { biometricUnlockState ->
                    biometricUnlockState == BiometricUnlockModel.WAKE_AND_UNLOCK_FROM_DREAM
                    ) {
                        startTransitionTo(KeyguardState.GONE)
                    }
                }
                .collect { startTransitionTo(KeyguardState.GONE) }
        }
    }

    private fun listenForDreamingLockscreenHostedToDozing() {
        scope.launch {
            combine(keyguardInteractor.dozeTransitionModel, startedKeyguardTransitionStep, ::Pair)
                .collect { (dozeTransitionModel, lastStartedTransitionStep) ->
                    if (
                        dozeTransitionModel.to == DozeStateModel.DOZE &&
                            lastStartedTransitionStep.to == KeyguardState.DREAMING_LOCKSCREEN_HOSTED
                    ) {
                        startTransitionTo(KeyguardState.DOZING)
                    }
                }
            keyguardInteractor.dozeTransitionModel
                .filterRelevantKeyguardStateAnd { it.to == DozeStateModel.DOZE }
                .collect { startTransitionTo(KeyguardState.DOZING) }
        }
    }

Loading