Fix NSSL flicker when going to/from OCCLUDED
There was a small flicker as the alpha would be set to 1 briefly
during the transitions. It turns out the legacy shade interactor may
send an event indicating the shade is fully expanded when it
resets. This is followed by an event that says it's now collapsed but
the damage is done. Prevent this by never interrupting the transitions
from KeyguardTransitionRepository.
Fixes: 314290249
Test: Manual - observe the one frame flicker no longer happens during
OCCLUDED<->LOCKSCREEN
Flag: ACONFIG com.android.systemui.keyguard_shade_migration_nssl
DEVELOPMENT
Change-Id: I460dfc11a55d94d07db9a94b00c58b9fdfda2979
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 17eb3c8..6f1f9a3 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -1160,9 +1160,9 @@
// Occluded->Lockscreen
collectFlow(mView, mKeyguardTransitionInteractor.getOccludedToLockscreenTransition(),
mOccludedToLockscreenTransition, mMainDispatcher);
- if (!KeyguardShadeMigrationNssl.isEnabled()) {
- collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
+ collectFlow(mView, mOccludedToLockscreenTransitionViewModel.getLockscreenAlpha(),
setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
+ if (!KeyguardShadeMigrationNssl.isEnabled()) {
collectFlow(mView,
mOccludedToLockscreenTransitionViewModel.getLockscreenTranslationY(),
setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
@@ -1192,8 +1192,10 @@
mLockscreenToOccludedTransition, mMainDispatcher);
collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenAlpha(),
setTransitionAlpha(mNotificationStackScrollLayoutController), mMainDispatcher);
- collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenTranslationY(),
- setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
+ if (!KeyguardShadeMigrationNssl.isEnabled()) {
+ collectFlow(mView, mLockscreenToOccludedTransitionViewModel.getLockscreenTranslationY(),
+ setTransitionY(mNotificationStackScrollLayoutController), mMainDispatcher);
+ }
// Primary bouncer->Gone (ensures lockscreen content is not visible on successful auth)
collectFlow(mView, mPrimaryBouncerToGoneTransitionViewModel.getLockscreenAlpha(),
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 eff91e5..5ee38be 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
@@ -25,6 +25,8 @@
import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState.SHADE_LOCKED
+import com.android.systemui.keyguard.shared.model.TransitionState.RUNNING
+import com.android.systemui.keyguard.shared.model.TransitionState.STARTED
import com.android.systemui.keyguard.ui.viewmodel.LockscreenToOccludedTransitionViewModel
import com.android.systemui.keyguard.ui.viewmodel.OccludedToLockscreenTransitionViewModel
import com.android.systemui.shade.domain.interactor.ShadeInteractor
@@ -71,6 +73,20 @@
KeyguardState.PRIMARY_BOUNCER
)
+ private val lockscreenToOccludedRunning =
+ keyguardTransitionInteractor
+ .transition(KeyguardState.LOCKSCREEN, KeyguardState.OCCLUDED)
+ .map { it.transitionState == STARTED || it.transitionState == RUNNING }
+ .distinctUntilChanged()
+ .onStart { emit(false) }
+
+ private val occludedToLockscreenRunning =
+ keyguardTransitionInteractor
+ .transition(KeyguardState.OCCLUDED, KeyguardState.LOCKSCREEN)
+ .map { it.transitionState == STARTED || it.transitionState == RUNNING }
+ .distinctUntilChanged()
+ .onStart { emit(false) }
+
val shadeCollapseFadeInComplete = MutableStateFlow(false)
val configurationBasedDimensions: Flow<ConfigurationBasedDimensions> =
@@ -122,7 +138,11 @@
) { isKeyguard, isShadeVisible, qsExpansion ->
isKeyguard && !(isShadeVisible || qsExpansion)
}
- .distinctUntilChanged()
+ .stateIn(
+ scope = applicationScope,
+ started = SharingStarted.Eagerly,
+ initialValue = false,
+ )
/** Fade in only for use after the shade collapses */
val shadeCollpaseFadeIn: Flow<Boolean> =
@@ -182,26 +202,37 @@
)
val alpha: Flow<Float> =
- isOnLockscreenWithoutShade
- .flatMapLatest { isOnLockscreenWithoutShade ->
- combineTransform(
- merge(
- occludedToLockscreenTransitionViewModel.lockscreenAlpha,
- lockscreenToOccludedTransitionViewModel.lockscreenAlpha,
- keyguardInteractor.keyguardAlpha,
- ),
- shadeCollpaseFadeIn,
- ) { alpha, shadeCollpaseFadeIn ->
- if (isOnLockscreenWithoutShade) {
- if (!shadeCollpaseFadeIn) {
- emit(alpha)
- }
+ // Due to issues with the legacy shade, some shade expansion events are sent incorrectly,
+ // such as when the shade resets. This can happen while the LOCKSCREEN<->OCCLUDED transition
+ // is running. Therefore use a series of flatmaps to prevent unwanted interruptions while
+ // those transitions are in progress. Without this, the alpha value will produce a visible
+ // flicker.
+ lockscreenToOccludedRunning.flatMapLatest { isLockscreenToOccludedRunning ->
+ if (isLockscreenToOccludedRunning) {
+ lockscreenToOccludedTransitionViewModel.lockscreenAlpha
+ } else {
+ occludedToLockscreenRunning.flatMapLatest { isOccludedToLockscreenRunning ->
+ if (isOccludedToLockscreenRunning) {
+ occludedToLockscreenTransitionViewModel.lockscreenAlpha.onStart { emit(0f) }
} else {
- emit(1f)
+ isOnLockscreenWithoutShade.flatMapLatest { isOnLockscreenWithoutShade ->
+ combineTransform(
+ keyguardInteractor.keyguardAlpha,
+ shadeCollpaseFadeIn,
+ ) { alpha, shadeCollpaseFadeIn ->
+ if (isOnLockscreenWithoutShade) {
+ if (!shadeCollpaseFadeIn) {
+ emit(alpha)
+ }
+ } else {
+ emit(1f)
+ }
+ }
+ }
}
}
}
- .distinctUntilChanged()
+ }
/**
* Under certain scenarios, such as swiping up on the lockscreen, the container will need to be
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
index 36a4712..20020f2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/ui/viewmodel/SharedNotificationContainerViewModelTest.kt
@@ -43,6 +43,7 @@
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
+import kotlinx.coroutines.test.TestScope
import kotlinx.coroutines.test.runCurrent
import kotlinx.coroutines.test.runTest
import org.junit.Before
@@ -418,13 +419,13 @@
}
@Test
- fun shadeCollpaseFadeIn() =
+ fun shadeCollapseFadeIn() =
testScope.runTest {
+ val fadeIn by collectLastValue(underTest.shadeCollpaseFadeIn)
+
// Start on lockscreen without the shade
underTest.setShadeCollapseFadeInComplete(false)
showLockscreen()
-
- val fadeIn by collectLastValue(underTest.shadeCollpaseFadeIn)
assertThat(fadeIn).isEqualTo(false)
// ... then the shade expands
@@ -440,10 +441,12 @@
assertThat(fadeIn).isEqualTo(false)
}
- private suspend fun showLockscreen() {
+ private suspend fun TestScope.showLockscreen() {
shadeRepository.setLockscreenShadeExpansion(0f)
shadeRepository.setQsExpansion(0f)
+ runCurrent()
keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)
+ runCurrent()
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,
@@ -451,10 +454,12 @@
)
}
- private suspend fun showLockscreenWithShadeExpanded() {
+ private suspend fun TestScope.showLockscreenWithShadeExpanded() {
shadeRepository.setLockscreenShadeExpansion(1f)
shadeRepository.setQsExpansion(0f)
+ runCurrent()
keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
+ runCurrent()
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,
@@ -462,10 +467,12 @@
)
}
- private suspend fun showLockscreenWithQSExpanded() {
+ private suspend fun TestScope.showLockscreenWithQSExpanded() {
shadeRepository.setLockscreenShadeExpansion(0f)
shadeRepository.setQsExpansion(1f)
+ runCurrent()
keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)
+ runCurrent()
keyguardTransitionRepository.sendTransitionSteps(
from = KeyguardState.AOD,
to = KeyguardState.LOCKSCREEN,