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

Commit b79e27a3 authored by Sherry Zhou's avatar Sherry Zhou
Browse files

Fix glitchy animation when going from LS to AOD with media

We get continuous topPadding in
requestScrollerTopPaddingUpdate without flag, and only get start and end
value with flag. The fix is to interpolate between start and end notif
bounds with AOD progress.

Test: manual test with media player in notification stack and
smartspace, observing that there's no jump fading out notification stack
when entering AOD from LS
Bug: 340312485
Flag: com.android.systemui.migrate_clocks_to_blueprint

Change-Id: Ib53b917a1f002100a55b004207a216473017351c
parent a79ddcca
Loading
Loading
Loading
Loading
+40 −1
Original line number Original line Diff line number Diff line
@@ -41,6 +41,8 @@ import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepos
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.domain.interactor.keyguardInteractor
import com.android.systemui.keyguard.shared.model.BurnInModel
import com.android.systemui.keyguard.shared.model.BurnInModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.KeyguardState.AOD
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.shared.model.TransitionStep
@@ -53,6 +55,7 @@ import com.android.systemui.kosmos.testScope
import com.android.systemui.res.R
import com.android.systemui.res.R
import com.android.systemui.shade.mockLargeScreenHeaderHelper
import com.android.systemui.shade.mockLargeScreenHeaderHelper
import com.android.systemui.shade.shadeTestUtil
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.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
import com.android.systemui.testKosmos
import com.android.systemui.testKosmos
import com.android.systemui.util.mockito.any
import com.android.systemui.util.mockito.any
@@ -794,11 +797,47 @@ class SharedNotificationContainerViewModelTest(flags: FlagsParameterization) : S
    @DisableSceneContainer
    @DisableSceneContainer
    fun updateBounds_fromKeyguardRoot() =
    fun updateBounds_fromKeyguardRoot() =
        testScope.runTest {
        testScope.runTest {
            val bounds by collectLastValue(underTest.bounds)
            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 top = 123f
            val bottom = 456f
            val bottom = 456f

            kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(startStep)
            runCurrent()
            kosmos.fakeKeyguardTransitionRepository.sendTransitionStep(boundsChangingStep)
            runCurrent()
            keyguardRootViewModel.onNotificationContainerBoundsChanged(top, bottom)
            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))
            assertThat(bounds).isEqualTo(NotificationContainerBounds(top = top, bottom = bottom))
        }
        }


+45 −3
Original line number Original line Diff line number Diff line
@@ -37,6 +37,7 @@ import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
import com.android.systemui.keyguard.shared.model.DozeStateModel
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.DozeStateModel.Companion.isDozeOff
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
import com.android.systemui.keyguard.shared.model.DozeTransitionModel
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.GONE
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.KeyguardState.LOCKSCREEN
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.StatusBarState
@@ -47,8 +48,10 @@ import com.android.systemui.scene.shared.flag.SceneContainerFlag
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.shade.data.repository.ShadeRepository
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.CommandQueue
import com.android.systemui.statusbar.notification.NotificationUtils.interpolate
import com.android.systemui.statusbar.notification.stack.domain.interactor.SharedNotificationContainerInteractor
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.Utils.Companion.sample as sampleCombine
import com.android.systemui.util.kotlin.pairwise
import com.android.systemui.util.kotlin.sample
import com.android.systemui.util.kotlin.sample
import javax.inject.Inject
import javax.inject.Inject
import javax.inject.Provider
import javax.inject.Provider
@@ -66,7 +69,9 @@ import kotlinx.coroutines.flow.combineTransform
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.debounce
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.distinctUntilChanged
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flatMapLatest
import kotlinx.coroutines.flow.flow
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.merge
import kotlinx.coroutines.flow.merge
@@ -96,17 +101,54 @@ constructor(
    // TODO(b/296118689): move to a repository
    // TODO(b/296118689): move to a repository
    private val _notificationPlaceholderBounds = MutableStateFlow(NotificationContainerBounds())
    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) {
                        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. */
    /** Bounds of the notification container. */
    val notificationContainerBounds: StateFlow<NotificationContainerBounds> by lazy {
    val notificationContainerBounds: StateFlow<NotificationContainerBounds> by lazy {
        SceneContainerFlag.assertInLegacyMode()
        SceneContainerFlag.assertInLegacyMode()
        combine(
        combine(
                _notificationPlaceholderBounds,
                _notificationPlaceholderBounds,
                _nonSplitShadeNotifciationPlaceholderBounds,
                sharedNotificationContainerInteractor.get().configurationBasedDimensions,
                sharedNotificationContainerInteractor.get().configurationBasedDimensions,
            ) { bounds, cfg ->
            ) { bounds, nonSplitShadeBounds: NotificationContainerBounds, cfg ->
                // We offset the placeholder bounds by the configured top margin to account for
                // We offset the placeholder bounds by the configured top margin to account for
                // legacy placement behavior within notifications for splitshade.
                // legacy placement behavior within notifications for splitshade.
                if (MigrateClocksToBlueprint.isEnabled && cfg.useSplitShade) {
                if (MigrateClocksToBlueprint.isEnabled) {
                    if (cfg.useSplitShade) {
                        bounds.copy(bottom = bounds.bottom - cfg.keyguardSplitShadeTopMargin)
                        bounds.copy(bottom = bounds.bottom - cfg.keyguardSplitShadeTopMargin)
                    } else {
                        nonSplitShadeBounds
                    }
                } else bounds
                } else bounds
            }
            }
            .stateIn(
            .stateIn(