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

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

Merge "Remove MutableStateFlow for transition current info" into main

parents e3d7e86a 93678d42
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -1559,6 +1559,16 @@ flag {
  bug: "362719719"
  bug: "362719719"
}
}


flag {
  name: "transition_race_condition"
  namespace: "systemui"
  description: "Thread-safe keyguard transitions"
  bug: "358533338"
  metadata {
       purpose: PURPOSE_BUGFIX
  }
}

flag {
flag {
   name: "media_projection_request_attribution_fix"
   name: "media_projection_request_attribution_fix"
   namespace: "systemui"
   namespace: "systemui"
+3 −3
Original line number Original line Diff line number Diff line
@@ -73,7 +73,7 @@ constructor(
    private var progressJob: Job? = null
    private var progressJob: Job? = null


    private val currentToState: KeyguardState
    private val currentToState: KeyguardState
        get() = internalTransitionInteractor.currentTransitionInfoInternal.value.to
        get() = internalTransitionInteractor.currentTransitionInfoInternal().to


    /**
    /**
     * The next keyguard state to trigger when exiting [CommunalScenes.Communal]. This is only used
     * The next keyguard state to trigger when exiting [CommunalScenes.Communal]. This is only used
@@ -197,7 +197,7 @@ constructor(
        val newTransition =
        val newTransition =
            TransitionInfo(
            TransitionInfo(
                ownerName = this::class.java.simpleName,
                ownerName = this::class.java.simpleName,
                from = internalTransitionInteractor.currentTransitionInfoInternal.value.to,
                from = internalTransitionInteractor.currentTransitionInfoInternal().to,
                to = state,
                to = state,
                animator = null,
                animator = null,
                modeOnCanceled = TransitionModeOnCanceled.REVERSE,
                modeOnCanceled = TransitionModeOnCanceled.REVERSE,
@@ -273,7 +273,7 @@ constructor(
    }
    }


    private suspend fun startTransitionToGlanceableHub() {
    private suspend fun startTransitionToGlanceableHub() {
        val currentState = internalTransitionInteractor.currentTransitionInfoInternal.value.to
        val currentState = internalTransitionInteractor.currentTransitionInfoInternal().to
        val newTransition =
        val newTransition =
            TransitionInfo(
            TransitionInfo(
                ownerName = this::class.java.simpleName,
                ownerName = this::class.java.simpleName,
+40 −13
Original line number Original line Diff line number Diff line
@@ -25,6 +25,7 @@ import android.os.Trace
import android.util.Log
import android.util.Log
import com.android.app.animation.Interpolators
import com.android.app.animation.Interpolators
import com.android.app.tracing.coroutines.withContextTraced as withContext
import com.android.app.tracing.coroutines.withContextTraced as withContext
import com.android.systemui.Flags.transitionRaceCondition
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.dagger.qualifiers.Main
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState
@@ -77,6 +78,8 @@ interface KeyguardTransitionRepository {


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


    /**
    /**
     * Interactors that require information about changes between [KeyguardState]s will call this to
     * Interactors that require information about changes between [KeyguardState]s will call this to
@@ -132,7 +135,7 @@ constructor(@Main val mainDispatcher: CoroutineDispatcher) : KeyguardTransitionR
    private var lastStep: TransitionStep = TransitionStep()
    private var lastStep: TransitionStep = TransitionStep()
    private var lastAnimator: ValueAnimator? = null
    private var lastAnimator: ValueAnimator? = null


    private val _currentTransitionMutex = Mutex()
    private val withContextMutex = Mutex()
    private val _currentTransitionInfo: MutableStateFlow<TransitionInfo> =
    private val _currentTransitionInfo: MutableStateFlow<TransitionInfo> =
        MutableStateFlow(
        MutableStateFlow(
            TransitionInfo(
            TransitionInfo(
@@ -144,6 +147,16 @@ constructor(@Main val mainDispatcher: CoroutineDispatcher) : KeyguardTransitionR
        )
        )
    override var currentTransitionInfoInternal = _currentTransitionInfo.asStateFlow()
    override var currentTransitionInfoInternal = _currentTransitionInfo.asStateFlow()


    @Volatile
    override var currentTransitionInfo: TransitionInfo =
        TransitionInfo(
            ownerName = "",
            from = KeyguardState.OFF,
            to = KeyguardState.OFF,
            animator = null,
        )
        private set

    /*
    /*
     * When manual control of the transition is requested, a unique [UUID] is used as the handle
     * When manual control of the transition is requested, a unique [UUID] is used as the handle
     * to permit calls to [updateTransition]
     * to permit calls to [updateTransition]
@@ -163,13 +176,17 @@ constructor(@Main val mainDispatcher: CoroutineDispatcher) : KeyguardTransitionR
    }
    }


    override suspend fun startTransition(info: TransitionInfo): UUID? {
    override suspend fun startTransition(info: TransitionInfo): UUID? {
        if (transitionRaceCondition()) {
            currentTransitionInfo = info
        } else {
            _currentTransitionInfo.value = info
            _currentTransitionInfo.value = info
        }
        Log.d(TAG, "(Internal) Setting current transition info: $info")
        Log.d(TAG, "(Internal) Setting current transition info: $info")


        // There is no fairness guarantee with 'withContext', which means that transitions could
        // There is no fairness guarantee with 'withContext', which means that transitions could
        // be processed out of order. Use a Mutex to guarantee ordering. [updateTransition]
        // be processed out of order. Use a Mutex to guarantee ordering. [updateTransition]
        // requires the same lock
        // requires the same lock
        _currentTransitionMutex.lock()
        withContextMutex.lock()
        // Only used in a test environment
        // Only used in a test environment
        if (forceDelayForRaceConditionTest) {
        if (forceDelayForRaceConditionTest) {
            delay(50L)
            delay(50L)
@@ -177,7 +194,7 @@ constructor(@Main val mainDispatcher: CoroutineDispatcher) : KeyguardTransitionR


        // Animators must be started on the main thread.
        // Animators must be started on the main thread.
        return withContext("$TAG#startTransition", mainDispatcher) {
        return withContext("$TAG#startTransition", mainDispatcher) {
            _currentTransitionMutex.unlock()
            withContextMutex.unlock()
            if (lastStep.from == info.from && lastStep.to == info.to) {
            if (lastStep.from == info.from && lastStep.to == info.to) {
                Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
                Log.i(TAG, "Duplicate call to start the transition, rejecting: $info")
                return@withContext null
                return@withContext null
@@ -265,9 +282,9 @@ constructor(@Main val mainDispatcher: CoroutineDispatcher) : KeyguardTransitionR
        // There is no fairness guarantee with 'withContext', which means that transitions could
        // There is no fairness guarantee with 'withContext', which means that transitions could
        // be processed out of order. Use a Mutex to guarantee ordering. [startTransition]
        // be processed out of order. Use a Mutex to guarantee ordering. [startTransition]
        // requires the same lock
        // requires the same lock
        _currentTransitionMutex.lock()
        withContextMutex.lock()
        withContext("$TAG#updateTransition", mainDispatcher) {
        withContext("$TAG#updateTransition", mainDispatcher) {
            _currentTransitionMutex.unlock()
            withContextMutex.unlock()


            updateTransitionInternal(transitionId, value, state)
            updateTransitionInternal(transitionId, value, state)
        }
        }
@@ -302,6 +319,15 @@ constructor(@Main val mainDispatcher: CoroutineDispatcher) : KeyguardTransitionR
        // Tests runs on testDispatcher, which is not the main thread, causing the animator thread
        // Tests runs on testDispatcher, which is not the main thread, causing the animator thread
        // check to fail
        // check to fail
        if (testSetup) {
        if (testSetup) {
            if (transitionRaceCondition()) {
                currentTransitionInfo =
                    TransitionInfo(
                        ownerName = ownerName,
                        from = KeyguardState.OFF,
                        to = to,
                        animator = null,
                    )
            } else {
                _currentTransitionInfo.value =
                _currentTransitionInfo.value =
                    TransitionInfo(
                    TransitionInfo(
                        ownerName = ownerName,
                        ownerName = ownerName,
@@ -309,6 +335,7 @@ constructor(@Main val mainDispatcher: CoroutineDispatcher) : KeyguardTransitionR
                        to = to,
                        to = to,
                        animator = null,
                        animator = null,
                    )
                    )
            }
            emitTransition(
            emitTransition(
                TransitionStep(
                TransitionStep(
                    KeyguardState.OFF,
                    KeyguardState.OFF,
+7 −7
Original line number Original line Diff line number Diff line
@@ -40,6 +40,7 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
import com.android.systemui.util.kotlin.sample
import java.util.UUID
import java.util.UUID
import javax.inject.Inject
import javax.inject.Inject
import kotlin.time.Duration.Companion.milliseconds
import kotlin.time.Duration.Companion.milliseconds
@@ -132,11 +133,10 @@ constructor(
        scope.launch("$TAG#listenForLockscreenToDreaming") {
        scope.launch("$TAG#listenForLockscreenToDreaming") {
            keyguardInteractor.isAbleToDream
            keyguardInteractor.isAbleToDream
                .filterRelevantKeyguardState()
                .filterRelevantKeyguardState()
                .sampleCombine(
                .sample(transitionInteractor.isFinishedIn(KeyguardState.LOCKSCREEN), ::Pair)
                    internalTransitionInteractor.currentTransitionInfoInternal,
                .collect { (isAbleToDream, isOnLockscreen) ->
                    transitionInteractor.isFinishedIn(KeyguardState.LOCKSCREEN),
                    val transitionInfo =
                )
                        internalTransitionInteractor.currentTransitionInfoInternal()
                .collect { (isAbleToDream, transitionInfo, isOnLockscreen) ->
                    val isTransitionInterruptible =
                    val isTransitionInterruptible =
                        transitionInfo.to == KeyguardState.LOCKSCREEN &&
                        transitionInfo.to == KeyguardState.LOCKSCREEN &&
                            !invalidFromStates.contains(transitionInfo.from)
                            !invalidFromStates.contains(transitionInfo.from)
@@ -179,7 +179,6 @@ constructor(
            shadeRepository.legacyShadeExpansion
            shadeRepository.legacyShadeExpansion
                .sampleCombine(
                .sampleCombine(
                    transitionInteractor.startedKeyguardTransitionStep,
                    transitionInteractor.startedKeyguardTransitionStep,
                    internalTransitionInteractor.currentTransitionInfoInternal,
                    keyguardInteractor.statusBarState,
                    keyguardInteractor.statusBarState,
                    keyguardInteractor.isKeyguardDismissible,
                    keyguardInteractor.isKeyguardDismissible,
                    keyguardInteractor.isKeyguardOccluded,
                    keyguardInteractor.isKeyguardOccluded,
@@ -188,11 +187,12 @@ constructor(
                    (
                    (
                        shadeExpansion,
                        shadeExpansion,
                        startedStep,
                        startedStep,
                        currentTransitionInfo,
                        statusBarState,
                        statusBarState,
                        isKeyguardUnlocked,
                        isKeyguardUnlocked,
                        isKeyguardOccluded) ->
                        isKeyguardOccluded) ->
                    val id = transitionId
                    val id = transitionId
                    val currentTransitionInfo =
                        internalTransitionInteractor.currentTransitionInfoInternal()
                    if (id != null) {
                    if (id != null) {
                        if (startedStep.to == KeyguardState.PRIMARY_BOUNCER) {
                        if (startedStep.to == KeyguardState.PRIMARY_BOUNCER) {
                            // An existing `id` means a transition is started, and calls to
                            // An existing `id` means a transition is started, and calls to
+10 −7
Original line number Original line Diff line number Diff line
@@ -17,13 +17,13 @@
package com.android.systemui.keyguard.domain.interactor
package com.android.systemui.keyguard.domain.interactor


import android.annotation.FloatRange
import android.annotation.FloatRange
import com.android.systemui.Flags.transitionRaceCondition
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.dagger.SysUISingleton
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.data.repository.KeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionInfo
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionState
import java.util.UUID
import java.util.UUID
import javax.inject.Inject
import javax.inject.Inject
import kotlinx.coroutines.flow.StateFlow


/**
/**
 * This interactor provides direct access to [KeyguardTransitionRepository] internals and exposes
 * This interactor provides direct access to [KeyguardTransitionRepository] internals and exposes
@@ -32,9 +32,7 @@ import kotlinx.coroutines.flow.StateFlow
@SysUISingleton
@SysUISingleton
class InternalKeyguardTransitionInteractor
class InternalKeyguardTransitionInteractor
@Inject
@Inject
constructor(
constructor(private val repository: KeyguardTransitionRepository) {
    private val repository: KeyguardTransitionRepository,
) {


    /**
    /**
     * The [TransitionInfo] of the most recent call to
     * The [TransitionInfo] of the most recent call to
@@ -58,14 +56,19 @@ constructor(
     * *will* be emitted, and therefore that it can safely request an AOD -> LOCKSCREEN transition
     * *will* be emitted, and therefore that it can safely request an AOD -> LOCKSCREEN transition
     * which will subsequently cancel GONE -> AOD.
     * which will subsequently cancel GONE -> AOD.
     */
     */
    internal val currentTransitionInfoInternal: StateFlow<TransitionInfo> =
    internal fun currentTransitionInfoInternal(): TransitionInfo {
        repository.currentTransitionInfoInternal
        return if (transitionRaceCondition()) {
            repository.currentTransitionInfo
        } else {
            repository.currentTransitionInfoInternal.value
        }
    }


    suspend fun startTransition(info: TransitionInfo) = repository.startTransition(info)
    suspend fun startTransition(info: TransitionInfo) = repository.startTransition(info)


    suspend fun updateTransition(
    suspend fun updateTransition(
        transitionId: UUID,
        transitionId: UUID,
        @FloatRange(from = 0.0, to = 1.0) value: Float,
        @FloatRange(from = 0.0, to = 1.0) value: Float,
        state: TransitionState
        state: TransitionState,
    ) = repository.updateTransition(transitionId, value, state)
    ) = repository.updateTransition(transitionId, value, state)
}
}
Loading