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

Commit 11e5ec44 authored by Michal Brzezinski's avatar Michal Brzezinski
Browse files

Final refactoring: Removing GestureUiState

GestureUiState was supposed to be middle state between GestureState and TutorialActionState but in practice it ended up very similar to TutorialActionState and made states overly complicated.
Also meant that transformation stateful logic was kept in Composables - that logic is now moved to TouchpadTutorialScreenViewModel and tested in TouchpadTutorialScreenViewModelTest (formerly tested in StateTransitionsTest).

Now there's simply GestureState on domain side and TutorialActionState on UI side and ViewModel is transforming one into another.

Fixes: 384509663
Test: unit tests
Flag: com.android.systemui.shared.new_touchpad_gestures_tutorial
Change-Id: I088ee8a0f77b3595d695041ad23b72bfb30a20d0
parent 150e4597
Loading
Loading
Loading
Loading
+18 −12
Original line number Diff line number Diff line
@@ -23,16 +23,16 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.inputdevice.tutorial.inputDeviceTutorialLogger
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Error
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Finished
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.InProgress
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Error
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Finished
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.InProgress
import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE
import com.android.systemui.touchpad.tutorial.ui.gesture.ThreeFingerGesture
import com.android.systemui.touchpad.ui.gesture.touchpadGestureResources
@@ -71,8 +71,8 @@ class BackGestureScreenViewModelTest : SysuiTestCase() {
                expected =
                    InProgress(
                        progress = 1f,
                        progressStartMarker = "gesture to L",
                        progressEndMarker = "end progress L",
                        startMarker = "gesture to L",
                        endMarker = "end progress L",
                    ),
            )
        }
@@ -85,8 +85,8 @@ class BackGestureScreenViewModelTest : SysuiTestCase() {
                expected =
                    InProgress(
                        progress = 1f,
                        progressStartMarker = "gesture to R",
                        progressEndMarker = "end progress R",
                        startMarker = "gesture to R",
                        endMarker = "end progress R",
                    ),
            )
        }
@@ -114,7 +114,7 @@ class BackGestureScreenViewModelTest : SysuiTestCase() {
        kosmos.runTest {
            fun performBackGesture() =
                ThreeFingerGesture.swipeLeft().forEach { viewModel.handleEvent(it) }
            val state by collectLastValue(viewModel.gestureUiState)
            val state by collectLastValue(viewModel.tutorialState)
            performBackGesture()
            assertThat(state).isInstanceOf(Finished::class.java)

@@ -134,15 +134,21 @@ class BackGestureScreenViewModelTest : SysuiTestCase() {
        fakeConfigRepository.onAnyConfigurationChange()
    }

    private fun Kosmos.assertProgressWhileMovingFingers(deltaX: Float, expected: GestureUiState) {
    private fun Kosmos.assertProgressWhileMovingFingers(
        deltaX: Float,
        expected: TutorialActionState,
    ) {
        assertStateAfterEvents(
            events = ThreeFingerGesture.eventsForGestureInProgress { move(deltaX = deltaX) },
            expected = expected,
        )
    }

    private fun Kosmos.assertStateAfterEvents(events: List<MotionEvent>, expected: GestureUiState) {
        val state by collectLastValue(viewModel.gestureUiState)
    private fun Kosmos.assertStateAfterEvents(
        events: List<MotionEvent>,
        expected: TutorialActionState,
    ) {
        val state by collectLastValue(viewModel.tutorialState)
        events.forEach { viewModel.handleEvent(it) }
        assertThat(state).isEqualTo(expected)
    }
+13 −10
Original line number Diff line number Diff line
@@ -23,16 +23,16 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.inputdevice.tutorial.inputDeviceTutorialLogger
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Error
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Finished
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.InProgress
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Error
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Finished
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.InProgress
import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE
import com.android.systemui.touchpad.tutorial.ui.gesture.ThreeFingerGesture
import com.android.systemui.touchpad.tutorial.ui.gesture.Velocity
@@ -86,8 +86,8 @@ class HomeGestureScreenViewModelTest : SysuiTestCase() {
                expected =
                    InProgress(
                        progress = 1f,
                        progressStartMarker = "drag with gesture",
                        progressEndMarker = "release playback realtime",
                        startMarker = "drag with gesture",
                        endMarker = "release playback realtime",
                    ),
            )
        }
@@ -108,7 +108,7 @@ class HomeGestureScreenViewModelTest : SysuiTestCase() {
    @Test
    fun gestureRecognitionTakesLatestDistanceThresholdIntoAccount() =
        kosmos.runTest {
            val state by collectLastValue(viewModel.gestureUiState)
            val state by collectLastValue(viewModel.tutorialState)
            performHomeGesture()
            assertThat(state).isInstanceOf(Finished::class.java)

@@ -121,7 +121,7 @@ class HomeGestureScreenViewModelTest : SysuiTestCase() {
    @Test
    fun gestureRecognitionTakesLatestVelocityThresholdIntoAccount() =
        kosmos.runTest {
            val state by collectLastValue(viewModel.gestureUiState)
            val state by collectLastValue(viewModel.tutorialState)
            performHomeGesture()
            assertThat(state).isInstanceOf(Finished::class.java)

@@ -147,8 +147,11 @@ class HomeGestureScreenViewModelTest : SysuiTestCase() {
        fakeConfigRepository.onAnyConfigurationChange()
    }

    private fun Kosmos.assertStateAfterEvents(events: List<MotionEvent>, expected: GestureUiState) {
        val state by collectLastValue(viewModel.gestureUiState)
    private fun Kosmos.assertStateAfterEvents(
        events: List<MotionEvent>,
        expected: TutorialActionState,
    ) {
        val state by collectLastValue(viewModel.tutorialState)
        events.forEach { viewModel.handleEvent(it) }
        assertThat(state).isEqualTo(expected)
    }
+13 −10
Original line number Diff line number Diff line
@@ -23,16 +23,16 @@ import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.common.ui.data.repository.fakeConfigurationRepository
import com.android.systemui.inputdevice.tutorial.inputDeviceTutorialLogger
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Error
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Finished
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.InProgress
import com.android.systemui.kosmos.Kosmos
import com.android.systemui.kosmos.collectLastValue
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.res.R
import com.android.systemui.testKosmos
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Error
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.Finished
import com.android.systemui.touchpad.tutorial.ui.composable.GestureUiState.InProgress
import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE
import com.android.systemui.touchpad.tutorial.ui.gesture.ThreeFingerGesture
import com.android.systemui.touchpad.tutorial.ui.gesture.Velocity
@@ -89,8 +89,8 @@ class RecentAppsGestureScreenViewModelTest : SysuiTestCase() {
                expected =
                    InProgress(
                        progress = 1f,
                        progressStartMarker = "drag with gesture",
                        progressEndMarker = "onPause",
                        startMarker = "drag with gesture",
                        endMarker = "onPause",
                    ),
            )
        }
@@ -111,7 +111,7 @@ class RecentAppsGestureScreenViewModelTest : SysuiTestCase() {
    @Test
    fun gestureRecognitionTakesLatestDistanceThresholdIntoAccount() =
        kosmos.runTest {
            val state by collectLastValue(viewModel.gestureUiState)
            val state by collectLastValue(viewModel.tutorialState)
            performRecentAppsGesture()
            assertThat(state).isInstanceOf(Finished::class.java)

@@ -124,7 +124,7 @@ class RecentAppsGestureScreenViewModelTest : SysuiTestCase() {
    @Test
    fun gestureRecognitionTakesLatestVelocityThresholdIntoAccount() =
        kosmos.runTest {
            val state by collectLastValue(viewModel.gestureUiState)
            val state by collectLastValue(viewModel.tutorialState)
            performRecentAppsGesture()
            assertThat(state).isInstanceOf(Finished::class.java)

@@ -150,8 +150,11 @@ class RecentAppsGestureScreenViewModelTest : SysuiTestCase() {
        fakeConfigRepository.onAnyConfigurationChange()
    }

    private fun Kosmos.assertStateAfterEvents(events: List<MotionEvent>, expected: GestureUiState) {
        val state by collectLastValue(viewModel.gestureUiState)
    private fun Kosmos.assertStateAfterEvents(
        events: List<MotionEvent>,
        expected: TutorialActionState,
    ) {
        val state by collectLastValue(viewModel.tutorialState)
        events.forEach { viewModel.handleEvent(it) }
        assertThat(state).isEqualTo(expected)
    }
+117 −0
Original line number Diff line number Diff line
@@ -14,27 +14,31 @@
 * limitations under the License.
 */

package com.android.systemui.touchpad.tutorial.ui
package com.android.systemui.touchpad.tutorial.ui.viewmodel

import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Error
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.Finished
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.InProgress
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.InProgressAfterError
import com.android.systemui.inputdevice.tutorial.ui.composable.TutorialActionState.NotStarted
import com.android.systemui.touchpad.tutorial.ui.composable.toGestureUiState
import com.android.systemui.touchpad.tutorial.ui.composable.toTutorialActionState
import com.android.systemui.kosmos.collectValues
import com.android.systemui.kosmos.runTest
import com.android.systemui.kosmos.useUnconfinedTestDispatcher
import com.android.systemui.testKosmos
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState
import com.google.common.truth.Truth.assertThat
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.asFlow
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith

@SmallTest
@RunWith(AndroidJUnit4::class)
class StateTransitionsTest : SysuiTestCase() {
class TouchpadTutorialScreenViewModelTest : SysuiTestCase() {

    companion object {
        private const val START_MARKER = "startMarker"
@@ -42,24 +46,23 @@ class StateTransitionsTest : SysuiTestCase() {
        private const val SUCCESS_ANIMATION = 0
    }

    // needed to simulate caching last state as it's used to create new state
    private var lastState: TutorialActionState = NotStarted

    private fun GestureState.toTutorialActionState(): TutorialActionState {
        val newState =
            this.toGestureUiState(
    private val kosmos = testKosmos()
    private val animationProperties =
        TutorialAnimationProperties(
            progressStartMarker = START_MARKER,
            progressEndMarker = END_MARKER,
            successAnimation = SUCCESS_ANIMATION,
        )
                .toTutorialActionState(lastState)
        lastState = newState
        return lastState

    @Before
    fun before() {
        kosmos.useUnconfinedTestDispatcher()
    }

    @Test
    fun gestureStateProducesEquivalentTutorialActionStateInHappyPath() {
        val happyPath =
    fun gestureStateProducesEquivalentTutorialActionStateInHappyPath() =
        kosmos.runTest {
            val happyPath: Flow<Pair<GestureState, TutorialAnimationProperties>> =
                listOf(
                        GestureState.NotStarted,
                        GestureState.InProgress(0f),
@@ -67,9 +70,10 @@ class StateTransitionsTest : SysuiTestCase() {
                        GestureState.InProgress(1f),
                        GestureState.Finished,
                    )
                    .map { it to animationProperties }
                    .asFlow()

        val resultingStates = mutableListOf<TutorialActionState>()
        happyPath.forEach { resultingStates.add(it.toTutorialActionState()) }
            val resultingStates by collectValues(happyPath.mapToTutorialState())

            assertThat(resultingStates)
                .containsExactly(
@@ -83,8 +87,9 @@ class StateTransitionsTest : SysuiTestCase() {
        }

    @Test
    fun gestureStateProducesEquivalentTutorialActionStateInErrorPath() {
        val errorPath =
    fun gestureStateProducesEquivalentTutorialActionStateInErrorPath() =
        kosmos.runTest {
            val errorPath: Flow<Pair<GestureState, TutorialAnimationProperties>> =
                listOf(
                        GestureState.NotStarted,
                        GestureState.InProgress(0f),
@@ -93,9 +98,10 @@ class StateTransitionsTest : SysuiTestCase() {
                        GestureState.InProgress(1f),
                        GestureState.Finished,
                    )
                    .map { it to animationProperties }
                    .asFlow()

        val resultingStates = mutableListOf<TutorialActionState>()
        errorPath.forEach { resultingStates.add(it.toTutorialActionState()) }
            val resultingStates by collectValues(errorPath.mapToTutorialState())

            assertThat(resultingStates)
                .containsExactly(
+1 −1
Original line number Diff line number Diff line
@@ -50,7 +50,7 @@ fun BackGestureTutorialScreen(
        )
    GestureTutorialScreen(
        screenConfig = screenConfig,
        gestureUiStateFlow = viewModel.gestureUiState,
        tutorialStateFlow = viewModel.tutorialState,
        motionEventConsumer = {
            easterEggGestureViewModel.accept(it)
            viewModel.handleEvent(it)
Loading