Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit f57b8ad0 authored by Matt Pietal's avatar Matt Pietal
Browse files

Keep notif bounds stable on LOCKSCREEN->AOD

This was still a bit unpolished if media was playing
and no other smartspace content existed.

Fixes: 354392838
Test: manual - use media and go to AOD
Test: atest SharedNotificationContainerViewModelTest
Flag: com.android.systemui.migrate_clocks_to_blueprint
Change-Id: Iad2302add25498a297c4ef95c97a899bddda1922
parent 206b6834
Loading
Loading
Loading
Loading
+39 −51
Original line number Diff line number Diff line
@@ -60,7 +60,6 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
import com.android.systemui.shade.mockLargeScreenHeaderHelper
import com.android.systemui.shade.shadeTestUtil
import com.android.systemui.statusbar.notification.NotificationUtils.interpolate
import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
@@ -589,6 +588,43 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
            assertThat(bounds).isEqualTo(NotificationContainerBounds(top = 1f, bottom = 2f))
        }

    @Test
    @DisableSceneContainer
    fun boundsDoNotChangeWhileLockscreenToAodTransitionIsActive() =
        testScope.runTest {
            val bounds by collectLastValue(underTest.bounds)

            // Start on lockscreen
            showLockscreen()

            keyguardInteractor.setNotificationContainerBounds(
                NotificationContainerBounds(top = 1f, bottom = 1f)
            )
            assertThat(bounds).isEqualTo(NotificationContainerBounds(top = 1f, bottom = 1f))

            // Begin transition to AOD
            keyguardTransitionRepository.sendTransitionStep(
                TransitionStep(LOCKSCREEN, AOD, 0f, TransitionState.STARTED)
            )
            runCurrent()
            keyguardTransitionRepository.sendTransitionStep(
                TransitionStep(LOCKSCREEN, AOD, 0.5f, TransitionState.RUNNING)
            )

            // Attempt to update bounds
            keyguardInteractor.setNotificationContainerBounds(
                NotificationContainerBounds(top = 5f, bottom = 5f)
            )
            // Bounds should not have moved
            assertThat(bounds).isEqualTo(NotificationContainerBounds(top = 1f, bottom = 1f))

            // Transition is over, now move
            keyguardTransitionRepository.sendTransitionStep(
                TransitionStep(LOCKSCREEN, AOD, 1f, TransitionState.FINISHED)
            )
            assertThat(bounds).isEqualTo(NotificationContainerBounds(top = 5f, bottom = 5f))
        }

    @Test
    @DisableFlags(FLAG_CENTRALIZED_STATUS_BAR_HEIGHT_FIX)
    @DisableSceneContainer
@@ -818,54 +854,6 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
            assertThat(translationY).isEqualTo(0f)
        }

    @Test
    @DisableSceneContainer
    fun updateBounds_fromKeyguardRoot() =
        testScope.runTest {
            val startProgress = 0f
            val startStep = TransitionStep(LOCKSCREEN, AOD, startProgress, TransitionState.STARTED)
            val boundsChangingProgress = 0.2f
            val boundsChangingStep =
                TransitionStep(LOCKSCREEN, AOD, boundsChangingProgress, TransitionState.RUNNING)
            val boundsInterpolatingProgress = 0.6f
            val boundsInterpolatingStep =
                TransitionStep(
                    LOCKSCREEN,
                    AOD,
                    boundsInterpolatingProgress,
                    TransitionState.RUNNING
                )
            val finishProgress = 1.0f
            val finishStep =
                TransitionStep(LOCKSCREEN, AOD, finishProgress, TransitionState.FINISHED)

            val bounds by collectLastValue(underTest.bounds)
            val top = 123f
            val bottom = 456f

            kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(startStep)
            runCurrent()
            kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(boundsChangingStep)
            runCurrent()
            keyguardRootViewModel.onNotificationContainerBoundsChanged(top, bottom)

            kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(boundsInterpolatingStep)
            runCurrent()
            val adjustedProgress =
                (boundsInterpolatingProgress - boundsChangingProgress) /
                    (1 - boundsChangingProgress)
            val interpolatedTop = interpolate(0f, top, adjustedProgress)
            val interpolatedBottom = interpolate(0f, bottom, adjustedProgress)
            assertThat(bounds)
                .isEqualTo(
                    NotificationContainerBounds(top = interpolatedTop, bottom = interpolatedBottom)
                )

            kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(finishStep)
            runCurrent()
            assertThat(bounds).isEqualTo(NotificationContainerBounds(top = top, bottom = bottom))
        }

    @Test
    @DisableSceneContainer
    fun updateBounds_fromGone_withoutTransitions() =
@@ -878,9 +866,9 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
            val top = 123f
            val bottom = 456f

            kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(runningStep)
            keyguardTransitionRepository.sendTransitionStep(runningStep)
            runCurrent()
            kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(finishStep)
            keyguardTransitionRepository.sendTransitionStep(finishStep)
            runCurrent()
            keyguardRootViewModel.onNotificationContainerBoundsChanged(top, bottom)
            runCurrent()
+22 −46
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import com.android.systemui.keyguard.shared.model.CameraLaunchType
import com.android.systemui.keyguard.shared.model.DozeStateModel
import com.android.systemui.keyguard.shared.model.DozeStateModel.Companion.isDozeOff
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.Edge
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
@@ -46,10 +47,8 @@ import com.android.systemui.scene.domain.interactor.SceneInteractor
import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.notification.NotificationUtils.interpolate
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
import com.android.systemui.util.kotlin.Utils.Companion.sample as sampleCombine
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import javax.inject.Provider
@@ -66,9 +65,7 @@ import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
@@ -98,55 +95,34 @@ constructor(
    // TODO(b/296118689): move to a repository
    private val _notificationPlaceholderBounds = MutableStateFlow(NotificationContainerBounds())

    // When going to AOD, we interpolate bounds when receiving the new bounds
    // When going back to LS, we'll apply new bounds directly
    private val _nonSplitShadeNotifciationPlaceholderBounds =
        _notificationPlaceholderBounds.pairwise().flatMapLatest { (oldBounds, newBounds) ->
            val lastChangeStep = keyguardTransitionInteractor.transitionState.first()
            if (lastChangeStep.to == AOD) {
                keyguardTransitionInteractor.transitionState.map { step ->
                    val startingProgress = lastChangeStep.value
                    val progress = step.value
                    if (step.to == AOD && progress >= startingProgress && startingProgress < 1f) {
                        val adjustedProgress =
                            ((progress - startingProgress) / (1F - startingProgress)).coerceIn(
                                0F,
                                1F
                            )
                        val top = interpolate(oldBounds.top, newBounds.top, adjustedProgress)
                        val bottom =
                            interpolate(
                                oldBounds.bottom,
                                newBounds.bottom,
                                adjustedProgress.coerceIn(0F, 1F)
                            )
                        NotificationContainerBounds(top = top, bottom = bottom)
                    } else {
                        newBounds
                    }
                }
            } else {
                flow { emit(newBounds) }
            }
        }

    /** Bounds of the notification container. */
    val notificationContainerBounds: StateFlow<NotificationContainerBounds> by lazy {
        SceneContainerFlag.assertInLegacyMode()
        combine(
        combineTransform(
                _notificationPlaceholderBounds,
                _nonSplitShadeNotifciationPlaceholderBounds,
                sharedNotificationContainerInteractor.get().configurationBasedDimensions,
            ) { bounds, nonSplitShadeBounds: NotificationContainerBounds, cfg ->
                keyguardTransitionInteractor.isInTransition(
                    edge = Edge.create(from = LOCKSCREEN, to = AOD)
                ),
            ) { bounds, cfg, isTransitioningToAod ->
                if (isTransitioningToAod) {
                    // Keep bounds stable during this transition, to prevent cases like smartspace
                    // popping in and adjusting the bounds. A prime example would be media playing,
                    // which then updates smartspace on transition to AOD
                    return@combineTransform
                }

                // We offset the placeholder bounds by the configured top margin to account for
                // legacy placement behavior within notifications for splitshade.
                emit(
                    if (MigrateClocksToBlueprint.isEnabled) {
                        if (cfg.useSplitShade) {
                            bounds.copy(bottom = bounds.bottom - cfg.keyguardSplitShadeTopMargin)
                        } else {
                        nonSplitShadeBounds
                            bounds
                        }
                    } else bounds
                )
            }
            .stateIn(
                scope = applicationScope,