Merge "Revert^2 "Prevent notif flicker during entirety of swipe to unlock"" into main
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/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..d112edb 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,34 @@
                     }
                 }
             }
-            .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,
+                            // Emit -1f on start to make sure the flow runs
+                            keyguardTransitionInteractor.transitionValue(GONE).onStart { emit(-1f) }
+                        ) { 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 +420,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 +432,7 @@
                     ),
                 ) {
                     isOnLockscreenWithoutShade,
+                    isGoneTransitionRunning,
                     shadeCollapseFadeIn,
                     alphaForShadeAndQsExpansion,
                     dismissAlpha ->
@@ -427,7 +440,7 @@
                         if (!shadeCollapseFadeIn && dismissAlpha != null) {
                             emit(dismissAlpha)
                         }
-                    } else {
+                    } else if (!isGoneTransitionRunning) {
                         emit(alphaForShadeAndQsExpansion)
                     }
                 },