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

Commit 7a24648a authored by Matt Pietal's avatar Matt Pietal
Browse files

Fix keyguard y translation while swiping

The swipe up signal comes from legacy shade expansion,
which can be unreliable. It will emit values of 0f and 1f,
at certain times as it resets, which can cause confusion
in the code and result in janky transitions.

Test: atest KeyguardInteractorTest
Fixes: 330189292
Flag: ACONFIG com.android.systemui.migrate_clocks_to_blueprint
TEAMFOOD

Change-Id: If9611004ee4692a21988466a3aa2558f904ade1f
parent a79d1acc
Loading
Loading
Loading
Loading
+93 −31
Original line number Diff line number Diff line
@@ -24,23 +24,23 @@ import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.Flags.FLAG_KEYGUARD_WM_STATE_REFACTOR
import com.android.systemui.SysuiTestCase
import com.android.systemui.bouncer.data.repository.FakeKeyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.FakeConfigurationRepository
import com.android.systemui.common.ui.domain.interactor.ConfigurationInteractor
import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.coroutines.collectLastValue
import com.android.systemui.flags.EnableSceneContainer
import com.android.systemui.keyguard.data.repository.FakeCommandQueue
import com.android.systemui.keyguard.data.repository.fakeCommandQueue
import com.android.systemui.keyguard.data.repository.fakeKeyguardRepository
import com.android.systemui.keyguard.data.repository.fakeKeyguardTransitionRepository
import com.android.systemui.keyguard.shared.model.CameraLaunchSourceModel
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.StatusBarState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.PowerInteractorFactory
import com.android.systemui.res.R
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.scene.shared.model.Scenes
import com.android.systemui.shade.data.repository.FakeShadeRepository
import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.testKosmos
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -60,33 +60,17 @@ class KeyguardInteractorTest : SysuiTestCase() {

    private val kosmos = testKosmos()
    private val testScope = kosmos.testScope
    private val repository by lazy { kosmos.fakeKeyguardRepository }
    private val sceneInteractor by lazy { kosmos.sceneInteractor }
    private val fromGoneTransitionInteractor by lazy { kosmos.fromGoneTransitionInteractor }
    private val commandQueue by lazy { FakeCommandQueue() }
    private val bouncerRepository = FakeKeyguardBouncerRepository()
    private val shadeRepository = FakeShadeRepository()
    private val repository = kosmos.fakeKeyguardRepository
    private val sceneInteractor = kosmos.sceneInteractor
    private val fromGoneTransitionInteractor = kosmos.fromGoneTransitionInteractor
    private val commandQueue = kosmos.fakeCommandQueue
    private val configRepository = kosmos.fakeConfigurationRepository
    private val bouncerRepository = kosmos.keyguardBouncerRepository
    private val shadeRepository = kosmos.shadeRepository
    private val keyguardTransitionRepository = kosmos.fakeKeyguardTransitionRepository
    private val transitionState: MutableStateFlow<ObservableTransitionState> =
        MutableStateFlow(ObservableTransitionState.Idle(Scenes.Gone))

    private val underTest by lazy {
        KeyguardInteractor(
            repository = repository,
            commandQueue = commandQueue,
            powerInteractor = PowerInteractorFactory.create().powerInteractor,
            bouncerRepository = bouncerRepository,
            configurationInteractor = ConfigurationInteractor(FakeConfigurationRepository()),
            shadeRepository = shadeRepository,
            keyguardTransitionInteractor = kosmos.keyguardTransitionInteractor,
            sceneInteractorProvider = { sceneInteractor },
            fromGoneTransitionInteractor = { fromGoneTransitionInteractor },
            sharedNotificationContainerInteractor = {
                kosmos.sharedNotificationContainerInteractor
            },
            applicationScope = testScope,
        )
    }
    private val underTest = kosmos.keyguardInteractor

    @Before
    fun setUp() {
@@ -246,6 +230,84 @@ class KeyguardInteractorTest : SysuiTestCase() {
            assertThat(dismissAlpha).isNull()
        }

    @Test
    fun keyguardTranslationY_whenGoneEmitsZero() =
        testScope.runTest {
            val keyguardTranslationY by collectLastValue(underTest.keyguardTranslationY)

            configRepository.setDimensionPixelSize(
                R.dimen.keyguard_translate_distance_on_swipe_up,
                100
            )
            configRepository.onAnyConfigurationChange()

            shadeRepository.setLegacyShadeExpansion(0f)

            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.AOD,
                to = KeyguardState.GONE,
                testScope,
            )

            assertThat(keyguardTranslationY).isEqualTo(0f)
        }

    @Test
    fun keyguardTranslationY_whenNotGoneAndShadeIsFullyCollapsedEmitsZero() =
        testScope.runTest {
            val keyguardTranslationY by collectLastValue(underTest.keyguardTranslationY)

            configRepository.setDimensionPixelSize(
                R.dimen.keyguard_translate_distance_on_swipe_up,
                100
            )
            configRepository.onAnyConfigurationChange()

            shadeRepository.setLegacyShadeExpansion(0f)

            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.AOD,
                to = KeyguardState.LOCKSCREEN,
                testScope,
            )

            assertThat(keyguardTranslationY).isEqualTo(0f)
        }

    @Test
    fun keyguardTranslationY_whenTransitioningToGoneAndShadeIsExpandingEmitsNonZero() =
        testScope.runTest {
            val keyguardTranslationY by collectLastValue(underTest.keyguardTranslationY)

            configRepository.setDimensionPixelSize(
                R.dimen.keyguard_translate_distance_on_swipe_up,
                100
            )
            configRepository.onAnyConfigurationChange()

            shadeRepository.setLegacyShadeExpansion(0.5f)

            keyguardTransitionRepository.sendTransitionSteps(
                listOf(
                    TransitionStep(
                        from = KeyguardState.AOD,
                        to = KeyguardState.GONE,
                        value = 0f,
                        transitionState = TransitionState.STARTED,
                    ),
                    TransitionStep(
                        from = KeyguardState.AOD,
                        to = KeyguardState.GONE,
                        value = 0.1f,
                        transitionState = TransitionState.RUNNING,
                    ),
                ),
                testScope,
            )

            assertThat(keyguardTranslationY).isGreaterThan(0f)
        }

    @Test
    @EnableSceneContainer
    fun animationDozingTransitions() =
+17 −9
Original line number Diff line number Diff line
@@ -307,19 +307,27 @@ constructor(
        configurationInteractor
            .dimensionPixelSize(R.dimen.keyguard_translate_distance_on_swipe_up)
            .flatMapLatest { translationDistance ->
                combine(
                combineTransform(
                    shadeRepository.legacyShadeExpansion.onStart { emit(0f) },
                    keyguardTransitionInteractor.transitionValue(GONE).onStart { emit(0f) },
                ) { legacyShadeExpansion, goneValue ->
                    if (goneValue == 1f || legacyShadeExpansion == 0f) {
                    if (goneValue == 1f || (goneValue == 0f && legacyShadeExpansion == 0f)) {
                        // Reset the translation value
                        0f
                    } else {
                        // On swipe up, translate the keyguard to reveal the bouncer
                        emit(0f)
                    } else if (legacyShadeExpansion > 0f && legacyShadeExpansion < 1f) {
                        // On swipe up, translate the keyguard to reveal the bouncer, OR a GONE
                        // transition is running, which means this is a swipe to dismiss. Values of
                        // 0f and 1f need to be ignored in the legacy shade expansion. These can
                        // flip arbitrarily as the legacy shade is reset, and would cause the
                        // translation value to jump around unexpectedly.
                        emit(
                            MathUtils.lerp(
                                translationDistance,
                                0,
                            Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(legacyShadeExpansion)
                                Interpolators.FAST_OUT_LINEAR_IN.getInterpolation(
                                    legacyShadeExpansion
                                ),
                            )
                        )
                    }
                }
+2 −2
Original line number Diff line number Diff line
@@ -18,20 +18,20 @@ package com.android.systemui.keyguard.domain.interactor

import com.android.systemui.bouncer.data.repository.keyguardBouncerRepository
import com.android.systemui.common.ui.domain.interactor.configurationInteractor
import com.android.systemui.keyguard.data.repository.fakeCommandQueue
import com.android.systemui.keyguard.data.repository.keyguardRepository
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.testScope
import com.android.systemui.power.domain.interactor.powerInteractor
import com.android.systemui.scene.domain.interactor.sceneInteractor
import com.android.systemui.shade.data.repository.shadeRepository
import com.android.systemui.statusbar.commandQueue
import com.android.systemui.statusbar.notification.stack.domain.interactor.sharedNotificationContainerInteractor

val Kosmos.keyguardInteractor: KeyguardInteractor by
    Kosmos.Fixture {
        KeyguardInteractor(
            repository = keyguardRepository,
            commandQueue = commandQueue,
            commandQueue = fakeCommandQueue,
            powerInteractor = powerInteractor,
            bouncerRepository = keyguardBouncerRepository,
            configurationInteractor = configurationInteractor,