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

Commit a93d6a77 authored by Michal Brzezinski's avatar Michal Brzezinski
Browse files

Adding velocity threshold for home touchpad gesture

Also creating fake for VelocityTracker and reusing it in recent apps gesture test

Test: HomeGestureRecognizerTest
Test: manual, home gesture is not successful if gesture is done slowly
Fixes: 365787507
Flag: com.android.systemui.shared.new_touchpad_gestures_tutorial
Change-Id: Ibcc92a3562278bff7522f4c096bacbe72a30331f
parent d7864f4f
Loading
Loading
Loading
Loading
+21 −1
Original line number Diff line number Diff line
@@ -20,10 +20,12 @@ import android.view.MotionEvent
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.testKosmos
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.Finished
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NotStarted
import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE
import com.android.systemui.touchpad.ui.gesture.fakeVelocityTracker
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
@@ -33,12 +35,24 @@ import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class HomeGestureRecognizerTest : SysuiTestCase() {

    companion object {
        const val THRESHOLD_VELOCITY_PX_PER_MS = 1f
        const val SLOW = THRESHOLD_VELOCITY_PX_PER_MS - 0.01f
        const val FAST = THRESHOLD_VELOCITY_PX_PER_MS + 0.01f
    }

    private var gestureState: GestureState = GestureState.NotStarted
    private var velocityTracker = testKosmos().fakeVelocityTracker
    private val gestureRecognizer =
        HomeGestureRecognizer(gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt())
        HomeGestureRecognizer(
            gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt(),
            velocityThresholdPxPerMs = THRESHOLD_VELOCITY_PX_PER_MS,
            velocityTracker = velocityTracker,
        )

    @Before
    fun before() {
        velocityTracker.setVelocity(Velocity(FAST))
        gestureRecognizer.addGestureStateCallback { gestureState = it }
    }

@@ -47,6 +61,12 @@ class HomeGestureRecognizerTest : SysuiTestCase() {
        assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = Finished)
    }

    @Test
    fun doesntTriggerGestureFinished_onGestureSpeedTooSlow() {
        velocityTracker.setVelocity(Velocity(SLOW))
        assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = NotStarted)
    }

    @Test
    fun triggersGestureProgressForThreeFingerGestureStarted() {
        assertStateAfterEvents(
+9 −14
Original line number Diff line number Diff line
@@ -17,21 +17,19 @@
package com.android.systemui.touchpad.tutorial.ui.gesture

import android.view.MotionEvent
import androidx.compose.ui.input.pointer.util.VelocityTracker1D
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.SmallTest
import com.android.systemui.SysuiTestCase
import com.android.systemui.testKosmos
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.Finished
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.NotStarted
import com.android.systemui.touchpad.tutorial.ui.gesture.MultiFingerGesture.Companion.SWIPE_DISTANCE
import com.android.systemui.touchpad.ui.gesture.fakeVelocityTracker
import com.google.common.truth.Truth.assertThat
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.doReturn
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever

@SmallTest
@RunWith(AndroidJUnit4::class)
@@ -39,26 +37,23 @@ class RecentAppsGestureRecognizerTest : SysuiTestCase() {

    companion object {
        const val THRESHOLD_VELOCITY_PX_PER_MS = 0.1f
        // multiply by 1000 to get px/ms instead of px/s which is unit used by velocity tracker
        const val SLOW = THRESHOLD_VELOCITY_PX_PER_MS * 1000 - 1
        const val FAST = THRESHOLD_VELOCITY_PX_PER_MS * 1000 + 1
        const val SLOW = THRESHOLD_VELOCITY_PX_PER_MS - 0.01f
        const val FAST = THRESHOLD_VELOCITY_PX_PER_MS + 0.01f
    }

    private var velocityTracker = testKosmos().fakeVelocityTracker

    private var gestureState: GestureState = GestureState.NotStarted
    private val velocityTracker1D =
        mock<VelocityTracker1D> {
            // by default return correct speed for the gesture - as if pointer is slowing down
            on { calculateVelocity() } doReturn SLOW
        }
    private val gestureRecognizer =
        RecentAppsGestureRecognizer(
            gestureDistanceThresholdPx = SWIPE_DISTANCE.toInt(),
            velocityThresholdPxPerMs = THRESHOLD_VELOCITY_PX_PER_MS,
            velocityTracker = VerticalVelocityTracker(velocityTracker1D),
            velocityTracker = velocityTracker,
        )

    @Before
    fun before() {
        velocityTracker.setVelocity(Velocity(SLOW))
        gestureRecognizer.addGestureStateCallback { gestureState = it }
    }

@@ -69,7 +64,7 @@ class RecentAppsGestureRecognizerTest : SysuiTestCase() {

    @Test
    fun doesntTriggerGestureFinished_onGestureSpeedTooHigh() {
        whenever(velocityTracker1D.calculateVelocity()).thenReturn(FAST)
        velocityTracker.setVelocity(Velocity(FAST))
        assertStateAfterEvents(events = ThreeFingerGesture.swipeUp(), expectedState = NotStarted)
    }

+5 −1
Original line number Diff line number Diff line
@@ -1995,12 +1995,16 @@
    <dimen name="backlight_indicator_step_large_radius">28dp</dimen>

    <!-- Touchpad gestures tutorial-->
    <!-- This value is in unit of dp/ms
    <!-- This value is in dp/ms.
        TriggerSwipeUpTouchTracker (which is base for gesture tutorial implementation) uses value
        of 0.5dp but from manual testing it's too high and doesn't really feel like it's forcing
        slowing down. Also for tutorial it should be fine to lean to the side of being more strict
        rather than not strict enough and not teaching user the proper gesture as a result.-->
    <dimen name="touchpad_recent_apps_gesture_velocity_threshold">0.05dp</dimen>
    <!-- This value is in dp/ms.
        As above, it's not tied to system-wide value (defined in launcher's
        quickstep_fling_threshold_speed) because for tutorial it's fine to be more strict. -->
    <dimen name="touchpad_home_gesture_velocity_threshold">0.5dp</dimen>
    <!-- Normal gesture threshold is system_gestures_distance_threshold but for tutorial we can
         exaggerate gesture, which also works much better with live tracking -->
    <dimen name="touchpad_tutorial_gestures_distance_threshold">48dp</dimen>
+2 −1
Original line number Diff line number Diff line
@@ -63,7 +63,8 @@ fun HomeGestureTutorialScreen(onDoneButtonClicked: () -> Unit, onBack: () -> Uni
private fun rememberHomeGestureRecognizer(resources: Resources): GestureRecognizer {
    val distance =
        resources.getDimensionPixelSize(R.dimen.touchpad_tutorial_gestures_distance_threshold)
    return remember(distance) { HomeGestureRecognizer(distance) }
    val velocity = resources.getDimension(R.dimen.touchpad_home_gesture_velocity_threshold)
    return remember(distance) { HomeGestureRecognizer(distance, velocity) }
}

@Composable
+11 −2
Original line number Diff line number Diff line
@@ -19,9 +19,14 @@ package com.android.systemui.touchpad.tutorial.ui.gesture
import android.util.MathUtils
import android.view.MotionEvent
import com.android.systemui.touchpad.tutorial.ui.gesture.GestureState.InProgress
import kotlin.math.abs

/** Recognizes touchpad home gesture, that is - using three fingers on touchpad - swiping up. */
class HomeGestureRecognizer(private val gestureDistanceThresholdPx: Int) : GestureRecognizer {
class HomeGestureRecognizer(
    private val gestureDistanceThresholdPx: Int,
    private val velocityThresholdPxPerMs: Float,
    private val velocityTracker: VelocityTracker = VerticalVelocityTracker(),
) : GestureRecognizer {

    private val distanceTracker = DistanceTracker()
    private var gestureStateChangedCallback: (GestureState) -> Unit = {}
@@ -37,10 +42,14 @@ class HomeGestureRecognizer(private val gestureDistanceThresholdPx: Int) : Gestu
    override fun accept(event: MotionEvent) {
        if (!isThreeFingerTouchpadSwipe(event)) return
        val gestureState = distanceTracker.processEvent(event)
        velocityTracker.accept(event)
        updateGestureState(
            gestureStateChangedCallback,
            gestureState,
            isFinished = { -it.deltaY >= gestureDistanceThresholdPx },
            isFinished = {
                -it.deltaY >= gestureDistanceThresholdPx &&
                    abs(velocityTracker.calculateVelocity().value) >= velocityThresholdPxPerMs
            },
            progress = { InProgress(MathUtils.saturate(-it.deltaY / gestureDistanceThresholdPx)) },
        )
    }
Loading