Prevent notif flicker during entirety of swipe to unlock
The current shade relies of status bar state, and so we still
need to check this to confirm that the user has completely
unlocked their device.
Also, remove redundant transition and update shadeExpansion to
be state flow (which matches the rest of the shade flows).
Test: atest SharedNotificationViewModelTest
Fixes: 329236043
Flag: ACONFIG com.android.systemui.migrate_clocks_to_blueprint
TEAMFOOD
Change-Id: I0af12eed5046b9238f66646f9752f48f18aae560
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt
index e7aaddd..857b9f8 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/keyguard/ui/viewmodel/LockscreenToGoneTransitionViewModelTest.kt
@@ -68,9 +68,7 @@
repository.sendTransitionStep(step(0f))
assertThat(alpha).isEqualTo(0.5f)
- repository.sendTransitionStep(step(0.25f))
- assertThat(alpha).isEqualTo(0.25f)
-
+ // Before the halfway point, it will have reached zero
repository.sendTransitionStep(step(.5f))
assertThat(alpha).isEqualTo(0f)
}
diff --git a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 53a8e5d..5256bb9 100644
--- a/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/multivalentTests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -720,6 +720,59 @@
}
@Test
+ fun alphaDoesNotUpdateWhileGoneTransitionIsRunning() =
+ testScope.runTest {
+ val viewState = ViewStateAccessor()
+ val alpha by collectLastValue(underTest.keyguardAlpha(viewState))
+
+ showLockscreen()
+ // GONE transition gets to 90% complete
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.STARTED,
+ value = 0f,
+ )
+ )
+ runCurrent()
+ keyguardTransitionRepository.sendTransitionStep(
+ TransitionStep(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ transitionState = TransitionState.RUNNING,
+ value = 0.9f,
+ )
+ )
+ runCurrent()
+
+ // At this point, alpha should be zero
+ assertThat(alpha).isEqualTo(0f)
+
+ // An attempt to override by the shade should be ignored
+ shadeRepository.setQsExpansion(0.5f)
+ assertThat(alpha).isEqualTo(0f)
+ }
+
+ @Test
+ fun alphaWhenGoneIsSetToOne() =
+ testScope.runTest {
+ val viewState = ViewStateAccessor()
+ val alpha by collectLastValue(underTest.keyguardAlpha(viewState))
+
+ showLockscreen()
+
+ keyguardTransitionRepository.sendTransitionSteps(
+ from = KeyguardState.LOCKSCREEN,
+ to = KeyguardState.GONE,
+ testScope
+ )
+ keyguardRepository.setStatusBarState(StatusBarState.SHADE)
+
+ assertThat(alpha).isEqualTo(1f)
+ }
+
+ @Test
fun shadeCollapseFadeIn() =
testScope.runTest {
val fadeIn by collectValues(underTest.shadeCollapseFadeIn)
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
index 12b27eb..2649d43 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/FromLockscreenTransitionInteractor.kt
@@ -289,7 +289,10 @@
.collect { pair ->
val (isKeyguardGoingAway, lastStartedStep) = pair
if (isKeyguardGoingAway && lastStartedStep.to == KeyguardState.LOCKSCREEN) {
- startTransitionTo(KeyguardState.GONE)
+ startTransitionTo(
+ KeyguardState.GONE,
+ modeOnCanceled = TransitionModeOnCanceled.RESET,
+ )
}
}
}
@@ -303,20 +306,6 @@
startTransitionTo(KeyguardState.GONE)
}
}
-
- return
- }
-
- scope.launch {
- keyguardInteractor.isKeyguardGoingAway
- .sample(startedKeyguardTransitionStep, ::Pair)
- .collect { pair ->
- KeyguardWmStateRefactor.assertInLegacyMode()
- val (isKeyguardGoingAway, lastStartedStep) = pair
- if (isKeyguardGoingAway && lastStartedStep.to == KeyguardState.LOCKSCREEN) {
- startTransitionTo(KeyguardState.GONE)
- }
- }
}
}
@@ -413,7 +402,7 @@
val TO_OCCLUDED_DURATION = 450.milliseconds
val TO_AOD_DURATION = 500.milliseconds
val TO_PRIMARY_BOUNCER_DURATION = DEFAULT_DURATION
- val TO_GONE_DURATION = DEFAULT_DURATION
+ val TO_GONE_DURATION = 633.milliseconds
val TO_GLANCEABLE_HUB_DURATION = 1.seconds
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
index e6655ee..546db3a 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardTransitionInteractor.kt
@@ -86,6 +86,7 @@
return transitionValueCache.getOrPut(state) {
MutableSharedFlow<Float>(
extraBufferCapacity = 2,
+ replay = 1,
onBufferOverflow = BufferOverflow.DROP_OLDEST
)
}
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
index c409028..cbbb820 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/viewmodel/AodToLockscreenTransitionViewModel.kt
@@ -30,8 +30,6 @@
import kotlin.time.Duration.Companion.milliseconds
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.Flow
-import kotlinx.coroutines.flow.combine
-import kotlinx.coroutines.flow.map
/**
* Breaks down AOD->LOCKSCREEN transition into discrete steps for corresponding views to consume.
@@ -53,6 +51,8 @@
to = KeyguardState.LOCKSCREEN,
)
+ private var isShadeExpanded = false
+
/**
* Begin the transition from wherever the y-translation value is currently. This helps ensure a
* smooth transition if a transition in canceled.
@@ -77,22 +77,21 @@
}
val notificationAlpha: Flow<Float> =
- combine(
- shadeInteractor.shadeExpansion.map { it > 0f },
- shadeInteractor.qsExpansion.map { it > 0f },
- transitionAnimation.sharedFlow(
- duration = 500.milliseconds,
- onStep = { it },
- onCancel = { 1f },
- ),
- ) { isShadeExpanded, isQsExpanded, alpha ->
- if (isShadeExpanded || isQsExpanded) {
- // One example of this happening is dragging a notification while pulsing on AOD
- 1f
- } else {
- alpha
- }
- }
+ transitionAnimation.sharedFlow(
+ duration = 500.milliseconds,
+ onStart = {
+ isShadeExpanded =
+ shadeInteractor.shadeExpansion.value > 0f ||
+ shadeInteractor.qsExpansion.value > 0f
+ },
+ onStep = {
+ if (isShadeExpanded) {
+ 1f
+ } else {
+ it
+ }
+ },
+ )
val shortcutsAlpha: Flow<Float> =
transitionAnimation.sharedFlow(
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
index bc60c83..cde45f2 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractor.kt
@@ -66,7 +66,7 @@
val isAnyExpanded: StateFlow<Boolean>
/** The amount [0-1] that the shade has been opened. */
- val shadeExpansion: Flow<Float>
+ val shadeExpansion: StateFlow<Float>
/**
* The amount [0-1] QS has been opened. Normal shade with notifications (QQS) visible will
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
index e9bb4c6..5fbd2cf 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorEmptyImpl.kt
@@ -29,7 +29,7 @@
private val inactiveFlowBoolean = MutableStateFlow(false)
private val inactiveFlowFloat = MutableStateFlow(0f)
override val isShadeEnabled: StateFlow<Boolean> = inactiveFlowBoolean
- override val shadeExpansion: Flow<Float> = inactiveFlowFloat
+ override val shadeExpansion: StateFlow<Float> = inactiveFlowFloat
override val qsExpansion: StateFlow<Float> = inactiveFlowFloat
override val isQsExpanded: StateFlow<Boolean> = inactiveFlowBoolean
override val isQsBypassingShade: Flow<Boolean> = inactiveFlowBoolean
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
index 421a761..ac881b5 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorLegacyImpl.kt
@@ -50,7 +50,7 @@
* The amount [0-1] that the shade has been opened. Uses stateIn to avoid redundant calculations
* in downstream flows.
*/
- override val shadeExpansion: Flow<Float> =
+ override val shadeExpansion: StateFlow<Float> =
combine(
repository.lockscreenShadeExpansion,
keyguardRepository.statusBarState,
diff --git a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
index 7785eda..7f35f17 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/domain/interactor/ShadeInteractorSceneContainerImpl.kt
@@ -49,7 +49,9 @@
sharedNotificationContainerInteractor: SharedNotificationContainerInteractor,
shadeRepository: ShadeRepository,
) : BaseShadeInteractor {
- override val shadeExpansion: Flow<Float> = sceneBasedExpansion(sceneInteractor, Scenes.Shade)
+ override val shadeExpansion: StateFlow<Float> =
+ sceneBasedExpansion(sceneInteractor, Scenes.Shade)
+ .stateIn(scope, SharingStarted.Eagerly, 0f)
private val sceneBasedQsExpansion = sceneBasedExpansion(sceneInteractor, Scenes.QuickSettings)
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
index ab6c148..6d0b873 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModel.kt
@@ -35,7 +35,7 @@
import com.android.systemui.keyguard.shared.model.KeyguardState.PRIMARY_BOUNCER
import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE
import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
-import com.android.systemui.keyguard.shared.model.TransitionState.FINISHED
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel
import com.android.systemui.keyguard.ui.viewmodel.AodToLockscreenTransitionViewModel
@@ -366,21 +366,33 @@
}
}
}
- .onStart { emit(0f) }
+ .onStart { emit(1f) }
.dumpWhileCollecting("alphaForShadeAndQsExpansion")
- private val alphaWhenGoneAndShadeState: Flow<Float> =
- combineTransform(
- keyguardTransitionInteractor.transitions
- .map { step -> step.to == GONE && step.transitionState == FINISHED }
- .distinctUntilChanged(),
- keyguardInteractor.statusBarState,
- ) { isGoneTransitionFinished, statusBarState ->
- if (isGoneTransitionFinished && statusBarState == SHADE) {
- emit(1f)
+ private val isGoneTransitionRunning: Flow<Boolean> =
+ flow {
+ while (currentCoroutineContext().isActive) {
+ emit(false)
+ // Ensure start where GONE is inactive
+ keyguardTransitionInteractor.transitionValue(GONE).first { it == 0f }
+ // Wait for a GONE transition to begin
+ keyguardTransitionInteractor.transitionStepsToState(GONE).first {
+ it.value > 0f && it.transitionState == RUNNING
+ }
+ emit(true)
+ // Now await the signal that SHADE state has been reached or the GONE transition
+ // was reversed. Until SHADE state has been replaced and merged with GONE, it is
+ // the only source of when it is considered safe to reset alpha to 1f for HUNs
+ combine(
+ keyguardInteractor.statusBarState,
+ keyguardTransitionInteractor.transitionValue(GONE),
+ ) { statusBarState, goneValue ->
+ statusBarState == SHADE || goneValue == 0f
+ }
+ .first { it }
}
}
- .dumpWhileCollecting("alphaWhenGoneAndShadeState")
+ .dumpWhileCollecting("goneTransitionInProgress")
fun keyguardAlpha(viewState: ViewStateAccessor): Flow<Float> {
// All transition view models are mututally exclusive, and safe to merge
@@ -407,12 +419,11 @@
return merge(
alphaTransitions,
- // Sends a final alpha value of 1f when truly gone, to make sure HUNs appear
- alphaWhenGoneAndShadeState,
// These remaining cases handle alpha changes within an existing state, such as
// shade expansion or swipe to dismiss
combineTransform(
isOnLockscreenWithoutShade,
+ isGoneTransitionRunning,
shadeCollapseFadeIn,
alphaForShadeAndQsExpansion,
keyguardInteractor.dismissAlpha.dumpWhileCollecting(
@@ -420,6 +431,7 @@
),
) {
isOnLockscreenWithoutShade,
+ isGoneTransitionRunning,
shadeCollapseFadeIn,
alphaForShadeAndQsExpansion,
dismissAlpha ->
@@ -427,7 +439,7 @@
if (!shadeCollapseFadeIn && dismissAlpha != null) {
emit(dismissAlpha)
}
- } else {
+ } else if (!isGoneTransitionRunning) {
emit(alphaForShadeAndQsExpansion)
}
},