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

Commit e37c87a7 authored by Justin Weir's avatar Justin Weir
Browse files

Add scene based isUserInteracting flow implementations

Bug: 300254715
Test: Added new tests
Test: Manual
Change-Id: I03605687c4e3f6fb337074e92c86d28698f91985
parent 35c1b072
Loading
Loading
Loading
Loading
+24 −3
Original line number Diff line number Diff line
@@ -59,6 +59,7 @@ constructor(
    @Application scope: CoroutineScope,
    disableFlagsRepository: DisableFlagsRepository,
    sceneContainerFlags: SceneContainerFlags,
    // TODO(b/300258424) convert to direct reference instead of provider
    sceneInteractorProvider: Provider<SceneInteractor>,
    keyguardRepository: KeyguardRepository,
    userSetupRepository: UserSetupRepository,
@@ -141,15 +142,22 @@ constructor(
     * if the user's input gesture has ended but a transition they initiated is animating.
     */
    val isUserInteractingWithShade: Flow<Boolean> =
        if (sceneContainerFlags.isEnabled()) {
            sceneBasedInteracting(sceneInteractorProvider.get(), SceneKey.Shade)
        } else {
            userInteractingFlow(repository.legacyShadeTracking, repository.legacyShadeExpansion)

        }
    /**
     * Whether the user is expanding or collapsing quick settings with user input. This will be true
     * even if the user's input gesture has ended but a transition they initiated is still
     * animating.
     */
    val isUserInteractingWithQs: Flow<Boolean> =
        if (sceneContainerFlags.isEnabled()) {
            sceneBasedInteracting(sceneInteractorProvider.get(), SceneKey.QuickSettings)
        } else {
            userInteractingFlow(repository.legacyQsTracking, repository.qsExpansion)
        }

    /**
     * Whether the user is expanding or collapsing either the shade or quick settings with user
@@ -158,6 +166,7 @@ constructor(
     */
    val isUserInteracting: Flow<Boolean> =
        combine(isUserInteractingWithShade, isUserInteractingWithShade) { shade, qs -> shade || qs }
            .distinctUntilChanged()

    /** Emits true if the shade can be expanded from QQS to QS and false otherwise. */
    val isExpandToQsEnabled: Flow<Boolean> =
@@ -198,6 +207,18 @@ constructor(
            }
            .distinctUntilChanged()

    fun sceneBasedInteracting(sceneInteractor: SceneInteractor, sceneKey: SceneKey) =
        sceneInteractor.transitionState
            .map { state ->
                when (state) {
                    is ObservableTransitionState.Idle -> false
                    is ObservableTransitionState.Transition ->
                        state.isUserInputDriven &&
                            (state.toScene == sceneKey || state.fromScene == sceneKey)
                }
            }
            .distinctUntilChanged()

    /**
     * Return a flow for whether a user is interacting with an expandable shade component using
     * tracking and expansion flows. NOTE: expansion must be a `StateFlow` to guarantee that
+188 −0
Original line number Diff line number Diff line
@@ -939,4 +939,192 @@ class ShadeInteractorTest : SysuiTestCase() {
            // THEN user is not interacting
            assertThat(actual).isFalse()
        }
    @Test
    fun userInteracting_idle() =
        testScope.runTest() {
            // GIVEN an interacting flow based on transitions to and from a scene
            val key = SceneKey.Shade
            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
            val interacting by collectLastValue(interactingFlow)

            // WHEN transition state is idle
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(ObservableTransitionState.Idle(key))
            sceneInteractor.setTransitionState(transitionState)

            // THEN interacting is false
            assertThat(interacting).isFalse()
        }

    @Test
    fun userInteracting_transitioning_toScene_programmatic() =
        testScope.runTest() {
            // GIVEN an interacting flow based on transitions to and from a scene
            val key = SceneKey.QuickSettings
            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
            val interacting by collectLastValue(interactingFlow)

            // WHEN transition state is starting to move to the scene
            val progress = MutableStateFlow(0f)
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(
                    ObservableTransitionState.Transition(
                        fromScene = SceneKey.Lockscreen,
                        toScene = key,
                        progress = progress,
                        isUserInputDriven = false,
                    )
                )
            sceneInteractor.setTransitionState(transitionState)

            // THEN interacting is false
            assertThat(interacting).isFalse()

            // WHEN transition state is partially to the scene
            progress.value = .4f

            // THEN interacting is false
            assertThat(interacting).isFalse()

            // WHEN transition completes
            progress.value = 1f

            // THEN interacting is false
            assertThat(interacting).isFalse()
        }

    @Test
    fun userInteracting_transitioning_toScene_userInputDriven() =
        testScope.runTest() {
            // GIVEN an interacting flow based on transitions to and from a scene
            val key = SceneKey.QuickSettings
            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
            val interacting by collectLastValue(interactingFlow)

            // WHEN transition state is starting to move to the scene
            val progress = MutableStateFlow(0f)
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(
                    ObservableTransitionState.Transition(
                        fromScene = SceneKey.Lockscreen,
                        toScene = key,
                        progress = progress,
                        isUserInputDriven = true,
                    )
                )
            sceneInteractor.setTransitionState(transitionState)

            // THEN interacting is true
            assertThat(interacting).isTrue()

            // WHEN transition state is partially to the scene
            progress.value = .4f

            // THEN interacting is true
            assertThat(interacting).isTrue()

            // WHEN transition completes
            progress.value = 1f

            // THEN interacting is true
            assertThat(interacting).isTrue()
        }

    @Test
    fun userInteracting_transitioning_fromScene_programmatic() =
        testScope.runTest() {
            // GIVEN an interacting flow based on transitions to and from a scene
            val key = SceneKey.QuickSettings
            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
            val interacting by collectLastValue(interactingFlow)

            // WHEN transition state is starting to move to the scene
            val progress = MutableStateFlow(0f)
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(
                    ObservableTransitionState.Transition(
                        fromScene = key,
                        toScene = SceneKey.Lockscreen,
                        progress = progress,
                        isUserInputDriven = false,
                    )
                )
            sceneInteractor.setTransitionState(transitionState)

            // THEN interacting is false
            assertThat(interacting).isFalse()

            // WHEN transition state is partially to the scene
            progress.value = .4f

            // THEN interacting is false
            assertThat(interacting).isFalse()

            // WHEN transition completes
            progress.value = 1f

            // THEN interacting is false
            assertThat(interacting).isFalse()
        }

    @Test
    fun userInteracting_transitioning_fromScene_userInputDriven() =
        testScope.runTest() {
            // GIVEN an interacting flow based on transitions to and from a scene
            val key = SceneKey.QuickSettings
            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, key)
            val interacting by collectLastValue(interactingFlow)

            // WHEN transition state is starting to move to the scene
            val progress = MutableStateFlow(0f)
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(
                    ObservableTransitionState.Transition(
                        fromScene = key,
                        toScene = SceneKey.Lockscreen,
                        progress = progress,
                        isUserInputDriven = true,
                    )
                )
            sceneInteractor.setTransitionState(transitionState)

            // THEN interacting is true
            assertThat(interacting).isTrue()

            // WHEN transition state is partially to the scene
            progress.value = .4f

            // THEN interacting is true
            assertThat(interacting).isTrue()

            // WHEN transition completes
            progress.value = 1f

            // THEN interacting is true
            assertThat(interacting).isTrue()
        }

    @Test
    fun userInteracting_transitioning_toAndFromDifferentScenes() =
        testScope.runTest() {
            // GIVEN an interacting flow based on transitions to and from a scene
            val interactingFlow = underTest.sceneBasedInteracting(sceneInteractor, SceneKey.Shade)
            val interacting by collectLastValue(interactingFlow)

            // WHEN transition state is starting to between different scenes
            val progress = MutableStateFlow(0f)
            val transitionState =
                MutableStateFlow<ObservableTransitionState>(
                    ObservableTransitionState.Transition(
                        fromScene = SceneKey.Lockscreen,
                        toScene = SceneKey.QuickSettings,
                        progress = progress,
                        isUserInputDriven = true,
                    )
                )
            sceneInteractor.setTransitionState(transitionState)

            // THEN interacting is false
            assertThat(interacting).isFalse()
        }
}