diff options
3 files changed, 141 insertions, 246 deletions
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 3f97f0b7a67d..425f16ec7da1 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 @@ -312,7 +312,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                          from = LOCKSCREEN,                          to = GLANCEABLE_HUB,                          value = 0f, -                    ) +                    ),              )              runCurrent() @@ -321,7 +321,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                      Transition(                          from = Scenes.Lockscreen,                          to = Scenes.Communal, -                        progress = flowOf(progress) +                        progress = flowOf(progress),                      ),                  stateTransition =                      TransitionStep( @@ -329,7 +329,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                          from = LOCKSCREEN,                          to = GLANCEABLE_HUB,                          value = progress, -                    ) +                    ),              )              runCurrent() @@ -344,7 +344,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                          from = LOCKSCREEN,                          to = GLANCEABLE_HUB,                          value = 1f, -                    ) +                    ),              )              assertThat(alpha).isEqualTo(0f) @@ -378,7 +378,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                          from = DREAMING,                          to = GLANCEABLE_HUB,                          value = 0f, -                    ) +                    ),              )              runCurrent()              kosmos.setTransition( @@ -386,7 +386,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                      Transition(                          from = Scenes.Lockscreen,                          to = Scenes.Communal, -                        progress = flowOf(progress) +                        progress = flowOf(progress),                      ),                  stateTransition =                      TransitionStep( @@ -394,7 +394,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                          from = DREAMING,                          to = GLANCEABLE_HUB,                          value = progress, -                    ) +                    ),              )              runCurrent()              // Keep notifications hidden during the transition from dream to hub @@ -409,7 +409,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                          from = DREAMING,                          to = GLANCEABLE_HUB,                          value = 1f, -                    ) +                    ),              )              assertThat(alpha).isEqualTo(0f)          } @@ -435,13 +435,13 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S              kosmos.setTransition(                  sceneTransition = Idle(Scenes.Gone), -                stateTransition = TransitionStep(from = LOCKSCREEN, to = GONE) +                stateTransition = TransitionStep(from = LOCKSCREEN, to = GONE),              )              assertThat(isOnLockscreen).isFalse()              kosmos.setTransition(                  sceneTransition = Idle(Scenes.Lockscreen), -                stateTransition = TransitionStep(from = GONE, to = LOCKSCREEN) +                stateTransition = TransitionStep(from = GONE, to = LOCKSCREEN),              )              assertThat(isOnLockscreen).isTrue()              // While progressing from lockscreen, should still be true @@ -452,28 +452,20 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                          from = LOCKSCREEN,                          to = GONE,                          value = 0.8f, -                        transitionState = TransitionState.RUNNING -                    ) +                        transitionState = TransitionState.RUNNING, +                    ),              )              assertThat(isOnLockscreen).isTrue()              kosmos.setTransition(                  sceneTransition = Idle(Scenes.Lockscreen), -                stateTransition = -                    TransitionStep( -                        from = GONE, -                        to = LOCKSCREEN, -                    ) +                stateTransition = TransitionStep(from = GONE, to = LOCKSCREEN),              )              assertThat(isOnLockscreen).isTrue()              kosmos.setTransition(                  sceneTransition = Idle(Scenes.Bouncer), -                stateTransition = -                    TransitionStep( -                        from = LOCKSCREEN, -                        to = PRIMARY_BOUNCER, -                    ) +                stateTransition = TransitionStep(from = LOCKSCREEN, to = PRIMARY_BOUNCER),              )              assertThat(isOnLockscreen).isTrue()          } @@ -527,11 +519,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S              // Move to glanceable hub              kosmos.setTransition(                  sceneTransition = Idle(Scenes.Communal), -                stateTransition = -                    TransitionStep( -                        from = LOCKSCREEN, -                        to = GLANCEABLE_HUB, -                    ) +                stateTransition = TransitionStep(from = LOCKSCREEN, to = GLANCEABLE_HUB),              )              assertThat(isOnGlanceableHubWithoutShade).isTrue() @@ -553,11 +541,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S              shadeTestUtil.setLockscreenShadeExpansion(0f)              kosmos.setTransition(                  sceneTransition = Idle(Scenes.Communal), -                stateTransition = -                    TransitionStep( -                        from = LOCKSCREEN, -                        to = GLANCEABLE_HUB, -                    ) +                stateTransition = TransitionStep(from = LOCKSCREEN, to = GLANCEABLE_HUB),              )              assertThat(isOnGlanceableHubWithoutShade).isTrue()          } @@ -779,7 +763,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S              configurationRepository.setDimensionPixelSize(                  R.dimen.keyguard_translate_distance_on_swipe_up, -                -100 +                -100,              )              configurationRepository.onAnyConfigurationChange() @@ -800,7 +784,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S              configurationRepository.setDimensionPixelSize(                  R.dimen.keyguard_translate_distance_on_swipe_up, -                -100 +                -100,              )              configurationRepository.onAnyConfigurationChange() @@ -839,7 +823,8 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S      fun alphaOnFullQsExpansion() =          testScope.runTest {              val viewState = ViewStateAccessor() -            val alpha by collectLastValue(underTest.keyguardAlpha(viewState)) +            val alpha by +                collectLastValue(underTest.keyguardAlpha(viewState, testScope.backgroundScope))              showLockscreenWithQSExpanded() @@ -856,12 +841,15 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S      @Test      @BrokenWithSceneContainer(330311871) -    fun alphaDoesNotUpdateWhileGoneTransitionIsRunning() = +    fun alphaWhenGoneIsSetToOne() =          testScope.runTest {              val viewState = ViewStateAccessor() -            val alpha by collectLastValue(underTest.keyguardAlpha(viewState)) +            val alpha by +                collectLastValue(underTest.keyguardAlpha(viewState, testScope.backgroundScope))              showLockscreen() +            assertThat(alpha).isEqualTo(1f) +              // GONE transition gets to 90% complete              keyguardTransitionRepository.sendTransitionStep(                  TransitionStep( @@ -881,65 +869,23 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                  )              )              runCurrent() +            // Change in state should not immediately set value to 1f. Should wait for +            // transition to complete +            keyguardRepository.setStatusBarState(StatusBarState.SHADE) -            // At this point, alpha should be zero -            assertThat(alpha).isEqualTo(0f) - -            // An attempt to override by the shade should be ignored -            shadeTestUtil.setQsExpansion(0.5f) -            assertThat(alpha).isEqualTo(0f) -        } - -    @Test -    fun alphaDoesNotUpdateWhileOcclusionTransitionIsRunning() = -        testScope.runTest { -            val viewState = ViewStateAccessor() -            val alpha by collectLastValue(underTest.keyguardAlpha(viewState)) +            // Transition is active, and NSSL should be nearly faded out +            assertThat(alpha).isLessThan(0.5f) -            showLockscreen() -            // OCCLUDED transition gets to 90% complete              keyguardTransitionRepository.sendTransitionStep(                  TransitionStep(                      from = LOCKSCREEN, -                    to = OCCLUDED, -                    transitionState = TransitionState.STARTED, -                    value = 0f, -                ) -            ) -            runCurrent() -            keyguardTransitionRepository.sendTransitionStep( -                TransitionStep( -                    from = LOCKSCREEN, -                    to = OCCLUDED, -                    transitionState = TransitionState.RUNNING, -                    value = 0.9f, +                    to = GONE, +                    transitionState = TransitionState.FINISHED, +                    value = 1f,                  )              )              runCurrent() - -            // At this point, alpha should be zero -            assertThat(alpha).isEqualTo(0f) - -            // An attempt to override by the shade should be ignored -            shadeTestUtil.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 = LOCKSCREEN, -                to = GONE, -                testScope -            ) -            keyguardRepository.setStatusBarState(StatusBarState.SHADE) - +            // Should reset to 1f              assertThat(alpha).isEqualTo(1f)          } @@ -978,11 +924,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S              assertThat(fadeIn[0]).isEqualTo(false)              // ... then user hits power to go to AOD -            keyguardTransitionRepository.sendTransitionSteps( -                from = LOCKSCREEN, -                to = AOD, -                testScope, -            ) +            keyguardTransitionRepository.sendTransitionSteps(from = LOCKSCREEN, to = AOD, testScope)              // ... followed by a shade collapse              showLockscreen()              // ... does not trigger a fade in @@ -994,7 +936,8 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S      fun alpha_isZero_fromPrimaryBouncerToGoneWhileCommunalSceneVisible() =          testScope.runTest {              val viewState = ViewStateAccessor() -            val alpha by collectLastValue(underTest.keyguardAlpha(viewState)) +            val alpha by +                collectLastValue(underTest.keyguardAlpha(viewState, testScope.backgroundScope))              showPrimaryBouncer()              showCommunalScene() @@ -1039,7 +982,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                      from = PRIMARY_BOUNCER,                      to = GONE,                      transitionState = TransitionState.FINISHED, -                    value = 1f +                    value = 1f,                  )              )              runCurrent() @@ -1052,7 +995,8 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S      fun alpha_fromPrimaryBouncerToGoneWhenCommunalSceneNotVisible() =          testScope.runTest {              val viewState = ViewStateAccessor() -            val alpha by collectLastValue(underTest.keyguardAlpha(viewState)) +            val alpha by +                collectLastValue(underTest.keyguardAlpha(viewState, testScope.backgroundScope))              showPrimaryBouncer()              hideCommunalScene() @@ -1095,7 +1039,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                      from = PRIMARY_BOUNCER,                      to = GONE,                      transitionState = TransitionState.FINISHED, -                    value = 1f +                    value = 1f,                  )              )              runCurrent() @@ -1107,7 +1051,8 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S      fun alpha_isZero_fromAlternateBouncerToGoneWhileCommunalSceneVisible() =          testScope.runTest {              val viewState = ViewStateAccessor() -            val alpha by collectLastValue(underTest.keyguardAlpha(viewState)) +            val alpha by +                collectLastValue(underTest.keyguardAlpha(viewState, testScope.backgroundScope))              showAlternateBouncer()              showCommunalScene() @@ -1152,7 +1097,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                      from = ALTERNATE_BOUNCER,                      to = GONE,                      transitionState = TransitionState.FINISHED, -                    value = 1f +                    value = 1f,                  )              )              runCurrent() @@ -1165,7 +1110,8 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S      fun alpha_fromAlternateBouncerToGoneWhenCommunalSceneNotVisible() =          testScope.runTest {              val viewState = ViewStateAccessor() -            val alpha by collectLastValue(underTest.keyguardAlpha(viewState)) +            val alpha by +                collectLastValue(underTest.keyguardAlpha(viewState, testScope.backgroundScope))              showAlternateBouncer()              hideCommunalScene() @@ -1208,7 +1154,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S                      from = ALTERNATE_BOUNCER,                      to = GONE,                      transitionState = TransitionState.FINISHED, -                    value = 1f +                    value = 1f,                  )              )              runCurrent() @@ -1221,11 +1167,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S          runCurrent()          keyguardRepository.setStatusBarState(StatusBarState.KEYGUARD)          runCurrent() -        keyguardTransitionRepository.sendTransitionSteps( -            from = AOD, -            to = LOCKSCREEN, -            testScope, -        ) +        keyguardTransitionRepository.sendTransitionSteps(from = AOD, to = LOCKSCREEN, testScope)      }      private suspend fun TestScope.showDream() { @@ -1247,11 +1189,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S          runCurrent()          keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)          runCurrent() -        keyguardTransitionRepository.sendTransitionSteps( -            from = AOD, -            to = LOCKSCREEN, -            testScope, -        ) +        keyguardTransitionRepository.sendTransitionSteps(from = AOD, to = LOCKSCREEN, testScope)      }      private suspend fun TestScope.showLockscreenWithQSExpanded() { @@ -1260,11 +1198,7 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S          runCurrent()          keyguardRepository.setStatusBarState(StatusBarState.SHADE_LOCKED)          runCurrent() -        keyguardTransitionRepository.sendTransitionSteps( -            from = AOD, -            to = LOCKSCREEN, -            testScope, -        ) +        keyguardTransitionRepository.sendTransitionSteps(from = AOD, to = LOCKSCREEN, testScope)      }      private suspend fun TestScope.showPrimaryBouncer() { diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt index aa1911e4cd2a..5ae5a3213954 100644 --- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt +++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/ui/viewbinder/SharedNotificationContainerBinder.kt @@ -62,7 +62,6 @@ constructor(          viewModel: SharedNotificationContainerViewModel,      ): DisposableHandle {          val disposables = DisposableHandles() -          disposables +=              view.repeatWhenAttached {                  repeatOnLifecycle(Lifecycle.State.CREATED) { @@ -87,10 +86,7 @@ constructor(              }          val burnInParams = MutableStateFlow(BurnInParameters()) -        val viewState = -            ViewStateAccessor( -                alpha = { controller.getAlpha() }, -            ) +        val viewState = ViewStateAccessor(alpha = { controller.getAlpha() })          /*           * For animation sensitive coroutines, immediately run just like applicationScope does @@ -108,7 +104,7 @@ constructor(                                          addUpdateListener { animation ->                                              controller.setMaxAlphaForKeyguard(                                                  animation.animatedFraction, -                                                "SharedNotificationContainerVB (collapseFadeIn)" +                                                "SharedNotificationContainerVB (collapseFadeIn)",                                              )                                          }                                          start() @@ -153,7 +149,7 @@ constructor(                      launch { viewModel.translationX.collect { x -> controller.translationX = x } }                      launch { -                        viewModel.keyguardAlpha(viewState).collect { +                        viewModel.keyguardAlpha(viewState, this).collect {                              controller.setMaxAlphaForKeyguard(it, "SharedNotificationContainerVB")                          }                      } 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 aed00d8cd5be..e34eb61c5cbd 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 @@ -20,7 +20,6 @@  package com.android.systemui.statusbar.notification.stack.ui.viewmodel  import androidx.annotation.VisibleForTesting -import com.android.compose.animation.scene.SceneKey  import com.android.systemui.common.shared.model.NotificationContainerBounds  import com.android.systemui.communal.domain.interactor.CommunalSceneInteractor  import com.android.systemui.dagger.SysUISingleton @@ -29,7 +28,6 @@ import com.android.systemui.dump.DumpManager  import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor  import com.android.systemui.keyguard.domain.interactor.KeyguardTransitionInteractor  import com.android.systemui.keyguard.shared.model.Edge -import com.android.systemui.keyguard.shared.model.KeyguardState  import com.android.systemui.keyguard.shared.model.KeyguardState.ALTERNATE_BOUNCER  import com.android.systemui.keyguard.shared.model.KeyguardState.AOD  import com.android.systemui.keyguard.shared.model.KeyguardState.DOZING @@ -41,7 +39,6 @@ import com.android.systemui.keyguard.shared.model.KeyguardState.OCCLUDED  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.RUNNING  import com.android.systemui.keyguard.ui.viewmodel.AlternateBouncerToGoneTransitionViewModel  import com.android.systemui.keyguard.ui.viewmodel.AodBurnInViewModel  import com.android.systemui.keyguard.ui.viewmodel.AodToGoneTransitionViewModel @@ -73,7 +70,6 @@ import com.android.systemui.shade.domain.interactor.ShadeInteractor  import com.android.systemui.statusbar.notification.stack.domain.interactor.NotificationStackAppearanceInteractor  import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor  import com.android.systemui.unfold.domain.interactor.UnfoldTransitionInteractor -import com.android.systemui.util.kotlin.BooleanFlowOperators.allOf  import com.android.systemui.util.kotlin.BooleanFlowOperators.anyOf  import com.android.systemui.util.kotlin.FlowDumperImpl  import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine @@ -166,10 +162,9 @@ constructor(       * before the other.       */      private val isShadeLocked: Flow<Boolean> = -        combine( -                keyguardInteractor.statusBarState.map { it == SHADE_LOCKED }, -                isAnyExpanded, -            ) { isShadeLocked, isAnyExpanded -> +        combine(keyguardInteractor.statusBarState.map { it == SHADE_LOCKED }, isAnyExpanded) { +                isShadeLocked, +                isAnyExpanded ->                  isShadeLocked && isAnyExpanded              }              .stateIn( @@ -220,23 +215,20 @@ constructor(                  keyguardTransitionInteractor.isFinishedIn(ALTERNATE_BOUNCER),                  keyguardTransitionInteractor.isFinishedIn(                      scene = Scenes.Bouncer, -                    stateWithoutSceneContainer = PRIMARY_BOUNCER +                    stateWithoutSceneContainer = PRIMARY_BOUNCER,                  ),                  keyguardTransitionInteractor.transitionValue(LOCKSCREEN).map { it > 0f },              )              .stateIn(                  scope = applicationScope,                  started = SharingStarted.Eagerly, -                initialValue = false +                initialValue = false,              )              .dumpValue("isOnLockscreen")      /** Are we purely on the keyguard without the shade/qs? */      val isOnLockscreenWithoutShade: Flow<Boolean> = -        combine( -                isOnLockscreen, -                isAnyExpanded, -            ) { isKeyguard, isAnyExpanded -> +        combine(isOnLockscreen, isAnyExpanded) { isKeyguard, isAnyExpanded ->                  isKeyguard && !isAnyExpanded              }              .stateIn( @@ -251,16 +243,16 @@ constructor(          combine(                  keyguardTransitionInteractor.isFinishedIn(                      scene = Scenes.Communal, -                    stateWithoutSceneContainer = GLANCEABLE_HUB +                    stateWithoutSceneContainer = GLANCEABLE_HUB,                  ),                  anyOf(                      keyguardTransitionInteractor.isInTransition(                          edge = Edge.create(to = Scenes.Communal), -                        edgeWithoutSceneContainer = Edge.create(to = GLANCEABLE_HUB) +                        edgeWithoutSceneContainer = Edge.create(to = GLANCEABLE_HUB),                      ),                      keyguardTransitionInteractor.isInTransition(                          edge = Edge.create(from = Scenes.Communal), -                        edgeWithoutSceneContainer = Edge.create(from = GLANCEABLE_HUB) +                        edgeWithoutSceneContainer = Edge.create(from = GLANCEABLE_HUB),                      ),                  ),              ) { isOnGlanceableHub, transitioningToOrFromHub -> @@ -271,10 +263,7 @@ constructor(      /** Are we purely on the glanceable hub without the shade/qs? */      val isOnGlanceableHubWithoutShade: Flow<Boolean> = -        combine( -                isOnGlanceableHub, -                isAnyExpanded, -            ) { isGlanceableHub, isAnyExpanded -> +        combine(isOnGlanceableHub, isAnyExpanded) { isGlanceableHub, isAnyExpanded ->                  isGlanceableHub && !isAnyExpanded              }              .stateIn( @@ -286,10 +275,9 @@ constructor(      /** Are we on the dream without the shade/qs? */      private val isDreamingWithoutShade: Flow<Boolean> = -        combine( -                keyguardTransitionInteractor.isFinishedIn(DREAMING), -                isAnyExpanded, -            ) { isDreaming, isAnyExpanded -> +        combine(keyguardTransitionInteractor.isFinishedIn(DREAMING), isAnyExpanded) { +                isDreaming, +                isAnyExpanded ->                  isDreaming && !isAnyExpanded              }              .stateIn( @@ -310,7 +298,7 @@ constructor(                  keyguardTransitionInteractor.isInTransition(                      edge = Edge.create(from = LOCKSCREEN, to = AOD)                  ), -                ::Pair +                ::Pair,              )              .transformWhile { (isOnLockscreenWithoutShade, aodTransitionIsRunning) ->                  // Wait until the AOD transition is complete before terminating @@ -375,7 +363,7 @@ constructor(                          keyguardTransitionInteractor.isInTransition,                          shadeInteractor.qsExpansion,                      ) -                    .onStart { emit(Triple(0f, false, 0f)) } +                    .onStart { emit(Triple(0f, false, 0f)) },              ) { onLockscreen, bounds, paddingTop, (top, isInTransitionToAnyState, qsExpansion) ->                  if (onLockscreen) {                      bounds.copy(top = bounds.top - paddingTop) @@ -383,10 +371,7 @@ constructor(                      // When QS expansion > 0, it should directly set the top padding so do not                      // animate it                      val animate = qsExpansion == 0f && !isInTransitionToAnyState -                    bounds.copy( -                        top = top, -                        isAnimated = animate, -                    ) +                    bounds.copy(top = top, isAnimated = animate)                  }              }              .stateIn( @@ -404,10 +389,9 @@ constructor(      private val alphaForShadeAndQsExpansion: Flow<Float> =          interactor.configurationBasedDimensions              .flatMapLatest { configurationBasedDimensions -> -                combineTransform( -                    shadeInteractor.shadeExpansion, -                    shadeInteractor.qsExpansion, -                ) { shadeExpansion, qsExpansion -> +                combineTransform(shadeInteractor.shadeExpansion, shadeInteractor.qsExpansion) { +                    shadeExpansion, +                    qsExpansion ->                      if (shadeExpansion > 0f || qsExpansion > 0f) {                          if (configurationBasedDimensions.useSplitShade) {                              emit(1f) @@ -424,47 +408,6 @@ constructor(              .onStart { emit(1f) }              .dumpWhileCollecting("alphaForShadeAndQsExpansion") -    private val isTransitioningToHiddenKeyguard: Flow<Boolean> = -        flow { -                while (currentCoroutineContext().isActive) { -                    emit(false) -                    // Ensure states are inactive to start -                    allOf(isNotOnState(OCCLUDED), isNotOnState(GONE, Scenes.Gone)).first { it } -                    // Wait for a qualifying transition to begin -                    anyOf( -                            transitionToIsRunning(Edge.create(to = OCCLUDED)), -                            transitionToIsRunning( -                                edge = Edge.create(to = Scenes.Gone), -                                edgeWithoutSceneContainer = Edge.create(to = GONE) -                            ) -                        ) -                        .first { it } -                    emit(true) -                    // Now await the signal that SHADE state has been reached or the transition was -                    // reversed. Until SHADE state has been replaced it is the only source of when -                    // it is considered safe to reset alpha to 1f for HUNs. -                    combine( -                            keyguardInteractor.statusBarState, -                            allOf(isNotOnState(OCCLUDED), isNotOnState(GONE, Scenes.Gone)) -                        ) { statusBarState, stateIsReversed -> -                            statusBarState == SHADE || stateIsReversed -                        } -                        .first { it } -                } -            } -            .dumpWhileCollecting("isTransitioningToHiddenKeyguard") - -    private fun isNotOnState(stateWithoutSceneContainer: KeyguardState, scene: SceneKey? = null) = -        keyguardTransitionInteractor -            .transitionValue(scene = scene, stateWithoutSceneContainer = stateWithoutSceneContainer) -            .map { it == 0f } - -    private fun transitionToIsRunning(edge: Edge, edgeWithoutSceneContainer: Edge? = null) = -        keyguardTransitionInteractor -            .transition(edge = edge, edgeWithoutSceneContainer = edgeWithoutSceneContainer) -            .map { it.value > 0f && it.transitionState == RUNNING } -            .onStart { emit(false) } -      val panelAlpha = keyguardInteractor.panelAlpha      private fun bouncerToGoneNotificationAlpha(viewState: ViewStateAccessor): Flow<Float> = @@ -478,49 +421,72 @@ constructor(              }              .dumpWhileCollecting("bouncerToGoneNotificationAlpha") -    fun keyguardAlpha(viewState: ViewStateAccessor): Flow<Float> { -        // All transition view models are mututally exclusive, and safe to merge -        val alphaTransitions = -            merge( -                keyguardInteractor.dismissAlpha.dumpWhileCollecting( -                    "keyguardInteractor.dismissAlpha" +    private fun alphaForTransitions(viewState: ViewStateAccessor): Flow<Float> { +        return merge( +            keyguardInteractor.dismissAlpha.dumpWhileCollecting("keyguardInteractor.dismissAlpha"), +            // All transition view models are mututally exclusive, and safe to merge +            bouncerToGoneNotificationAlpha(viewState), +            aodToGoneTransitionViewModel.notificationAlpha(viewState), +            aodToLockscreenTransitionViewModel.notificationAlpha, +            aodToOccludedTransitionViewModel.lockscreenAlpha(viewState), +            dozingToLockscreenTransitionViewModel.lockscreenAlpha, +            dozingToOccludedTransitionViewModel.lockscreenAlpha(viewState), +            dreamingToLockscreenTransitionViewModel.lockscreenAlpha, +            goneToAodTransitionViewModel.notificationAlpha, +            goneToDreamingTransitionViewModel.lockscreenAlpha, +            goneToDozingTransitionViewModel.notificationAlpha, +            goneToLockscreenTransitionViewModel.lockscreenAlpha, +            lockscreenToDreamingTransitionViewModel.lockscreenAlpha, +            lockscreenToGoneTransitionViewModel.notificationAlpha(viewState), +            lockscreenToOccludedTransitionViewModel.lockscreenAlpha, +            lockscreenToPrimaryBouncerTransitionViewModel.lockscreenAlpha, +            occludedToAodTransitionViewModel.lockscreenAlpha, +            occludedToGoneTransitionViewModel.notificationAlpha(viewState), +            occludedToLockscreenTransitionViewModel.lockscreenAlpha, +            primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha(viewState), +            glanceableHubToLockscreenTransitionViewModel.keyguardAlpha, +            lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha, +        ) +    } + +    fun keyguardAlpha(viewState: ViewStateAccessor, scope: CoroutineScope): Flow<Float> { +        // Transitions are not (yet) authoritative for NSSL; they still rely on StatusBarState to +        // help determine when the device has fully moved to GONE or OCCLUDED state. Once SHADE +        // state has been set, let shade alpha take over +        val isKeyguardNotVisible = +            combine( +                anyOf( +                    keyguardTransitionInteractor.transitionValue(OCCLUDED).map { it == 1f }, +                    keyguardTransitionInteractor +                        .transitionValue(scene = Scenes.Gone, stateWithoutSceneContainer = GONE) +                        .map { it == 1f },                  ), -                bouncerToGoneNotificationAlpha(viewState), -                aodToGoneTransitionViewModel.notificationAlpha(viewState), -                aodToLockscreenTransitionViewModel.notificationAlpha, -                aodToOccludedTransitionViewModel.lockscreenAlpha(viewState), -                dozingToLockscreenTransitionViewModel.lockscreenAlpha, -                dozingToOccludedTransitionViewModel.lockscreenAlpha(viewState), -                dreamingToLockscreenTransitionViewModel.lockscreenAlpha, -                goneToAodTransitionViewModel.notificationAlpha, -                goneToDreamingTransitionViewModel.lockscreenAlpha, -                goneToDozingTransitionViewModel.notificationAlpha, -                goneToLockscreenTransitionViewModel.lockscreenAlpha, -                lockscreenToDreamingTransitionViewModel.lockscreenAlpha, -                lockscreenToGoneTransitionViewModel.notificationAlpha(viewState), -                lockscreenToOccludedTransitionViewModel.lockscreenAlpha, -                lockscreenToPrimaryBouncerTransitionViewModel.lockscreenAlpha, -                occludedToAodTransitionViewModel.lockscreenAlpha, -                occludedToGoneTransitionViewModel.notificationAlpha(viewState), -                occludedToLockscreenTransitionViewModel.lockscreenAlpha, -                primaryBouncerToLockscreenTransitionViewModel.lockscreenAlpha(viewState), -                glanceableHubToLockscreenTransitionViewModel.keyguardAlpha, -                lockscreenToGlanceableHubTransitionViewModel.keyguardAlpha, -            ) +                keyguardInteractor.statusBarState, +            ) { isKeyguardNotVisibleInState, statusBarState -> +                isKeyguardNotVisibleInState && statusBarState == SHADE +            } -        return merge( -                alphaTransitions, -                // These remaining cases handle alpha changes within an existing state, such as -                // shade expansion or swipe to dismiss -                combineTransform( -                    isTransitioningToHiddenKeyguard, -                    alphaForShadeAndQsExpansion, -                ) { isTransitioningToHiddenKeyguard, alphaForShadeAndQsExpansion -> -                    if (!isTransitioningToHiddenKeyguard) { -                        emit(alphaForShadeAndQsExpansion) -                    } -                }, -            ) +        // This needs to continue collecting the current value so that when it is selected in the +        // flatMapLatest below, the last value gets emitted, to avoid the randomness of `merge`. +        val alphaForTransitionsAndShade = +            merge(alphaForTransitions(viewState), alphaForShadeAndQsExpansion) +                .stateIn( +                    // Use view-level scope instead of ApplicationScope, to prevent collection that +                    // never stops +                    scope = scope, +                    started = SharingStarted.Eagerly, +                    initialValue = 1f, +                ) +                .dumpValue("alphaForTransitionsAndShade") + +        return isKeyguardNotVisible +            .flatMapLatest { isKeyguardNotVisible -> +                if (isKeyguardNotVisible) { +                    alphaForShadeAndQsExpansion +                } else { +                    alphaForTransitionsAndShade +                } +            }              .distinctUntilChanged()              .dumpWhileCollecting("keyguardAlpha")      } @@ -543,9 +509,8 @@ constructor(                      )                      // Manually emit on start because [notificationAlpha] only starts emitting                      // when transitions start. -                    .onStart { emit(1f) } -            ) { isOnGlanceableHubWithoutShade, isOnLockscreen, isDreamingWithoutShade, alpha, -                -> +                    .onStart { emit(1f) }, +            ) { isOnGlanceableHubWithoutShade, isOnLockscreen, isDreamingWithoutShade, alpha ->                  if ((isOnGlanceableHubWithoutShade || isDreamingWithoutShade) && !isOnLockscreen) {                      // Notifications should not be visible on the glanceable hub.                      // TODO(b/321075734): implement a way to actually set the notifications to @@ -580,7 +545,7 @@ constructor(                  merge(                      keyguardInteractor.keyguardTranslationY,                      occludedToLockscreenTransitionViewModel.lockscreenTranslationY, -                ) +                ),              ) { burnInY, isOnLockscreenWithoutShade, translationY ->                  if (isOnLockscreenWithoutShade) {                      burnInY + translationY @@ -604,7 +569,7 @@ constructor(                      unfoldTransitionInteractor.unfoldTranslationX(isOnStartSide = false)                  } else {                      emptyFlow() -                } +                },              )              .dumpWhileCollecting("translationX") @@ -634,7 +599,7 @@ constructor(                          primaryBouncerToGoneTransitionViewModel.showAllNotifications,                          alternateBouncerToGoneTransitionViewModel.showAllNotifications,                      ) -                    .onStart { emit(false) } +                    .onStart { emit(false) },              ) { isOnLockscreen, statusBarState, showAllNotifications ->                  statusBarState == SHADE_LOCKED || !isOnLockscreen || showAllNotifications              }  |