Loading packages/SystemUI/aconfig/systemui.aconfig +10 −0 Original line number Original line Diff line number Diff line Loading @@ -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" Loading packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt +3 −3 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading Loading @@ -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, Loading packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt +40 −13 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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( Loading @@ -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] Loading @@ -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) Loading @@ -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 Loading Loading @@ -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) } } Loading Loading @@ -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, Loading @@ -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, Loading packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +7 −7 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) Loading Loading @@ -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, Loading @@ -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 Loading packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/InternalKeyguardTransitionInteractor.kt +10 −7 Original line number Original line Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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
packages/SystemUI/aconfig/systemui.aconfig +10 −0 Original line number Original line Diff line number Diff line Loading @@ -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" Loading
packages/SystemUI/src/com/android/systemui/communal/domain/interactor/CommunalSceneTransitionInteractor.kt +3 −3 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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, Loading Loading @@ -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, Loading
packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardTransitionRepository.kt +40 −13 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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 Loading Loading @@ -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( Loading @@ -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] Loading @@ -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) Loading @@ -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 Loading Loading @@ -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) } } Loading Loading @@ -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, Loading @@ -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, Loading
packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt +7 −7 Original line number Original line Diff line number Diff line Loading @@ -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 Loading Loading @@ -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) Loading Loading @@ -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, Loading @@ -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 Loading
packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/InternalKeyguardTransitionInteractor.kt +10 −7 Original line number Original line Diff line number Diff line Loading @@ -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 Loading @@ -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 Loading @@ -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) } }