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

Commit be1e1c94 authored by Coco Duan's avatar Coco Duan
Browse files

Motion update for swiping between lockscreen and hub

When swiping into and out of hub, apply depth push animation to
keyguard elements and wallpaper.

Bug: 404535174
Test: verify lockscreen<->hub, hub->bouncer->gone->lockscreen->hub
Test: atest KeyguardRootViewModelTest
Test: atest CommunalSceneInteractorTest
Flag: com.android.systemui.gesture_between_hub_and_lockscreen_motion
Change-Id: Iac36a3fb9f1e319fe5394afc843e1099de428374
parent 85621a03
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -2050,6 +2050,16 @@ flag {
    }
}

flag {
    name: "gesture_between_hub_and_lockscreen_motion"
    namespace: "systemui"
    description: "Motion update when gestures into and out of glanceable hub from lockscreen."
    bug: "404535174"
    metadata {
      purpose: PURPOSE_BUGFIX
    }
}

flag {
   name: "clear_shortcut_icon_tint"
   namespace: "systemui"
+19 −8
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ import com.android.compose.animation.scene.MutableSceneTransitionLayoutState
import com.android.compose.animation.scene.SceneKey
import com.android.compose.animation.scene.SceneTransitionLayout
import com.android.compose.animation.scene.Swipe
import com.android.compose.animation.scene.UserActionDistance
import com.android.compose.animation.scene.UserActionResult
import com.android.compose.animation.scene.observableTransitionState
import com.android.compose.animation.scene.rememberMutableSceneTransitionLayoutState
@@ -115,8 +116,16 @@ val sceneTransitionsV2 = transitions {
    to(CommunalScenes.Communal, key = CommunalTransitionKeys.Swipe) {
        spec = tween(durationMillis = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS)
        translate(Communal.Elements.Grid, Edge.End)
        if (Flags.gestureBetweenHubAndLockscreenMotion()) {
            distance = UserActionDistance { fromContent, _, _ ->
                val fromContentSize = checkNotNull(fromContent.targetSize())
                fromContentSize.width * 0.5f
            }
            timestampRange(startMillis = 167, endMillis = 334) { fade(Communal.Elements.StatusBar) }
        } else {
            timestampRange(startMillis = 167, endMillis = 334) { fade(AllElements) }
        }
    }
    to(CommunalScenes.Blank) {
        spec = tween(durationMillis = TO_GONE_DURATION.toInt(DurationUnit.MILLISECONDS))
        fade(AllElements)
@@ -139,6 +148,7 @@ val sceneTransitionsV2 = transitions {
    to(CommunalScenes.Blank, key = CommunalTransitionKeys.Swipe) {
        spec = tween(durationMillis = TransitionDuration.TO_GLANCEABLE_HUB_DURATION_MS)
        translate(Communal.Elements.Grid, Edge.End)
        if (!Flags.gestureBetweenHubAndLockscreenMotion()) {
            timestampRange(endMillis = 167) {
                fade(Communal.Elements.Grid)
                fade(Communal.Elements.IndicationArea)
@@ -149,6 +159,7 @@ val sceneTransitionsV2 = transitions {
            }
            timestampRange(startMillis = 167, endMillis = 334) { fade(Communal.Elements.Scrim) }
        }
    }
    to(CommunalScenes.Blank, key = CommunalTransitionKeys.ToEditMode) {
        spec = tween(durationMillis = TransitionDuration.BETWEEN_HUB_AND_EDIT_MODE_MS)
        fade(AllElements)
+51 −0
Original line number Diff line number Diff line
@@ -296,6 +296,57 @@ class CommunalSceneInteractorTest(flags: FlagsParameterization) : SysuiTestCase(
            assertThat(isIdleOnCommunal).isEqualTo(false)
        }

    @DisableSceneContainer
    @Test
    fun isCommunalSceneTransitioning_isFalse_idleOnCommunalScene() =
        testScope.runTest {
            val isCommunalSceneTransitioning by
                collectLastValue(underTest.isCommunalSceneTransitioning)
            val transitionState: MutableStateFlow<ObservableTransitionState> =
                MutableStateFlow(ObservableTransitionState.Idle(CommunalScenes.Communal))

            repository.setTransitionState(transitionState)

            assertThat(isCommunalSceneTransitioning).isEqualTo(false)
        }

    @DisableSceneContainer
    @Test
    fun isCommunalSceneTransitioning_isFalse_idleOnBlankScene() =
        testScope.runTest {
            val isCommunalSceneTransitioning by
                collectLastValue(underTest.isCommunalSceneTransitioning)
            val transitionState: MutableStateFlow<ObservableTransitionState> =
                MutableStateFlow(ObservableTransitionState.Idle(CommunalScenes.Blank))

            repository.setTransitionState(transitionState)

            assertThat(isCommunalSceneTransitioning).isEqualTo(false)
        }

    @DisableSceneContainer
    @Test
    fun isCommunalSceneTransitioning_isTrue_userInitiatedTransition() =
        testScope.runTest {
            val isCommunalSceneTransitioning by
                collectLastValue(underTest.isCommunalSceneTransitioning)
            val transitionState: MutableStateFlow<ObservableTransitionState> =
                MutableStateFlow(ObservableTransitionState.Idle(CommunalScenes.Blank))

            repository.setTransitionState(transitionState)
            transitionState.value =
                ObservableTransitionState.Transition(
                    fromScene = CommunalScenes.Blank,
                    toScene = CommunalScenes.Communal,
                    currentScene = flowOf(CommunalScenes.Blank),
                    progress = flowOf(0.1f),
                    isInitiatedByUserInput = true,
                    isUserInputOngoing = flowOf(false),
                )

            assertThat(isCommunalSceneTransitioning).isEqualTo(true)
        }

    @DisableSceneContainer
    @Test
    fun isTransitioningToOrIdleOnCommunal() =
+142 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.platform.test.flag.junit.FlagsParameterization
import android.view.View
import androidx.test.filters.SmallTest
import com.android.compose.animation.scene.ObservableTransitionState
import com.android.systemui.Flags.FLAG_GESTURE_BETWEEN_HUB_AND_LOCKSCREEN_MOTION
import com.android.systemui.Flags.FLAG_GLANCEABLE_HUB_V2
import com.android.systemui.SysuiTestCase
import com.android.systemui.communal.data.repository.communalSceneRepository
@@ -43,6 +44,8 @@ import com.android.systemui.keyguard.domain.interactor.pulseExpansionInteractor
import com.android.systemui.keyguard.shared.model.KeyguardState
import com.android.systemui.keyguard.shared.model.TransitionState
import com.android.systemui.keyguard.shared.model.TransitionStep
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel.Companion.DEPTH_PUSH_WALLPAPER_FROM_GLANCEABLE_HUB
import com.android.systemui.keyguard.ui.viewmodel.KeyguardRootViewModel.Companion.PUSHBACK_SCALE_FOR_LOCKSCREEN
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runCurrent
import com.android.systemui.kosmos.runTest
@@ -546,6 +549,145 @@ class KeyguardRootViewModelTest(flags: FlagsParameterization) : SysuiTestCase()
            assertThat(alpha).isEqualTo(1.0f)
        }

    @Test
    @EnableFlags(FLAG_GESTURE_BETWEEN_HUB_AND_LOCKSCREEN_MOTION)
    @DisableSceneContainer
    fun wallpaperZoomOut_transitionFromLockscreenToHubAndBack() =
        testScope.runTest {
            val zoomOut by collectLastValue(underTest.wallpaperZoomOut)

            val transitionState: MutableStateFlow<ObservableTransitionState> =
                MutableStateFlow(
                    ObservableTransitionState.Transition(
                        fromScene = CommunalScenes.Blank,
                        toScene = CommunalScenes.Communal,
                        currentScene = flowOf(CommunalScenes.Communal),
                        progress = flowOf(0f),
                        isInitiatedByUserInput = true,
                        isUserInputOngoing = flowOf(false),
                    )
                )

            // Start transition to communal
            communalRepository.setTransitionState(transitionState)

            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.GLANCEABLE_HUB,
                testScope,
            )
            // Finish transition to communal
            transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Communal)

            assertThat(zoomOut).isEqualTo(DEPTH_PUSH_WALLPAPER_FROM_GLANCEABLE_HUB)

            // Start transitioning back.
            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.GLANCEABLE_HUB,
                to = KeyguardState.LOCKSCREEN,
                testScope,
            )
            transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Blank)

            assertThat(zoomOut).isEqualTo(0f)
        }

    @Test
    @DisableSceneContainer
    @EnableFlags(FLAG_GESTURE_BETWEEN_HUB_AND_LOCKSCREEN_MOTION)
    fun wallpaperZoomOut_reset_transitionedAwayFromHub() =
        testScope.runTest {
            val zoomOut by collectLastValue(underTest.wallpaperZoomOut)
            val transitionState: MutableStateFlow<ObservableTransitionState> =
                MutableStateFlow(ObservableTransitionState.Idle(CommunalScenes.Blank))

            // Transition to the glanceable hub and then to bouncer.
            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.GLANCEABLE_HUB,
                testScope,
            )
            transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Communal)

            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.GLANCEABLE_HUB,
                to = KeyguardState.PRIMARY_BOUNCER,
                testScope,
            )
            transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Blank)

            assertThat(zoomOut).isEqualTo(0f)
        }

    @Test
    @DisableSceneContainer
    @EnableFlags(FLAG_GESTURE_BETWEEN_HUB_AND_LOCKSCREEN_MOTION)
    fun scaleFromGlanceableHub_transitionFromLockscreenToHubAndBack() =
        testScope.runTest {
            val scaleToApply by collectLastValue(underTest.scaleFromZoomOut)
            val transitionState: MutableStateFlow<ObservableTransitionState> =
                MutableStateFlow(
                    ObservableTransitionState.Transition(
                        fromScene = CommunalScenes.Blank,
                        toScene = CommunalScenes.Communal,
                        currentScene = flowOf(CommunalScenes.Blank),
                        progress = flowOf(0f),
                        isInitiatedByUserInput = true,
                        isUserInputOngoing = flowOf(false),
                    )
                )

            // Start transition to communal.
            communalRepository.setTransitionState(transitionState)

            // Transition to the glanceable hub and back.
            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.GLANCEABLE_HUB,
                testScope,
            )
            transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Communal)

            assertThat(scaleToApply).isEqualTo(1 - PUSHBACK_SCALE_FOR_LOCKSCREEN)

            // Start transitioning back.
            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.GLANCEABLE_HUB,
                to = KeyguardState.LOCKSCREEN,
                testScope,
            )
            transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Blank)

            assertThat(scaleToApply).isEqualTo(1f)
        }

    @Test
    @DisableSceneContainer
    @EnableFlags(FLAG_GESTURE_BETWEEN_HUB_AND_LOCKSCREEN_MOTION)
    fun scaleFromGlanceableHub_reset_transitionedAwayFromHub() =
        testScope.runTest {
            val scaleToApply by collectLastValue(underTest.scaleFromZoomOut)
            val transitionState: MutableStateFlow<ObservableTransitionState> =
                MutableStateFlow(ObservableTransitionState.Idle(CommunalScenes.Blank))

            // Transition to the glanceable hub and then to bouncer.
            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.LOCKSCREEN,
                to = KeyguardState.GLANCEABLE_HUB,
                testScope,
            )
            transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Communal)

            keyguardTransitionRepository.sendTransitionSteps(
                from = KeyguardState.GLANCEABLE_HUB,
                to = KeyguardState.PRIMARY_BOUNCER,
                testScope,
            )
            transitionState.value = ObservableTransitionState.Idle(CommunalScenes.Blank)

            assertThat(scaleToApply).isEqualTo(1f)
        }

    @Test
    fun alpha_emitsOnShadeExpansion() =
        testScope.runTest {
+6 −0
Original line number Diff line number Diff line
@@ -369,6 +369,12 @@ constructor(
                initialValue = false,
            )

    /** Flow that emits a boolean if user is swiping between two scenes. */
    val isCommunalSceneTransitioning: Flow<Boolean> =
        transitionState
            .map { it is ObservableTransitionState.Transition && it.isInitiatedByUserInput }
            .distinctUntilChanged()

    private companion object {
        const val TAG = "CommunalSceneInteractor"
    }
Loading