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

Commit 9d250972 authored by Ameer Armaly's avatar Ameer Armaly
Browse files

Reduce touch exploration sensitivity.

This change alters touch exploration behavior by requiring that the finger move a number of pixels defined by the system's scaled touch slop value  before it sends a hover event.
Fix: 303677860
Test: atest CtsAccessibilityServiceTestCases:TouchExplorerTest FrameworksServicesTests:TouchExplorerTest

Change-Id: Ib8dd4de60d5c71f38f8873b9c5c2af1d0c6e6010
parent 6fe98599
Loading
Loading
Loading
Loading
+7 −0
Original line number Original line Diff line number Diff line
@@ -55,3 +55,10 @@ flag {
    description: "Scans packages for accessibility service/activity info without holding the A11yMS lock"
    description: "Scans packages for accessibility service/activity info without holding the A11yMS lock"
    bug: "295969873"
    bug: "295969873"
}
}

flag {
    name: "reduce_touch_exploration_sensitivity"
    namespace: "accessibility"
    description: "Reduces touch exploration sensitivity by only sending a hover event when the ifnger has moved the amount of pixels defined by the system's touch slop."
    bug: "303677860"
}
+15 −3
Original line number Original line Diff line number Diff line
@@ -884,8 +884,20 @@ public class TouchExplorer extends BaseEventStreamTransformation
            case 1:
            case 1:
                // Touch exploration.
                // Touch exploration.
                sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
                sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
                if (Flags.reduceTouchExplorationSensitivity()
                        && mState.getLastInjectedHoverEvent() != null) {
                    final MotionEvent lastEvent = mState.getLastInjectedHoverEvent();
                    final float deltaX = lastEvent.getX() - rawEvent.getX();
                    final float deltaY = lastEvent.getY() - rawEvent.getY();
                    final double moveDelta = Math.hypot(deltaX, deltaY);
                    if (moveDelta > mTouchSlop) {
                        mDispatcher.sendMotionEvent(
                                event, ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags);
                    }
                } else {
                    mDispatcher.sendMotionEvent(
                    mDispatcher.sendMotionEvent(
                            event, ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags);
                            event, ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags);
                }
                break;
                break;
            case 2:
            case 2:
                if (mGestureDetector.isMultiFingerGesturesEnabled()
                if (mGestureDetector.isMultiFingerGesturesEnabled()
+52 −9
Original line number Original line Diff line number Diff line
@@ -44,6 +44,10 @@ import android.content.Context;
import android.graphics.PointF;
import android.graphics.PointF;
import android.os.Looper;
import android.os.Looper;
import android.os.SystemClock;
import android.os.SystemClock;
import android.platform.test.annotations.RequiresFlagsDisabled;
import android.platform.test.annotations.RequiresFlagsEnabled;
import android.platform.test.flag.junit.CheckFlagsRule;
import android.platform.test.flag.junit.DeviceFlagsValueProvider;
import android.testing.DexmakerShareClassLoaderRule;
import android.testing.DexmakerShareClassLoaderRule;
import android.view.InputDevice;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.MotionEvent;
@@ -56,6 +60,7 @@ import androidx.test.runner.AndroidJUnit4;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.accessibility.EventStreamTransformation;
import com.android.server.accessibility.EventStreamTransformation;
import com.android.server.accessibility.Flags;
import com.android.server.accessibility.utils.GestureLogParser;
import com.android.server.accessibility.utils.GestureLogParser;
import com.android.server.testutils.OffsettableClock;
import com.android.server.testutils.OffsettableClock;


@@ -76,6 +81,7 @@ import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.ArrayList;
import java.util.List;
import java.util.List;



@RunWith(AndroidJUnit4.class)
@RunWith(AndroidJUnit4.class)
public class TouchExplorerTest {
public class TouchExplorerTest {


@@ -119,6 +125,9 @@ public class TouchExplorerTest {
    public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
    public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
            new DexmakerShareClassLoaderRule();
            new DexmakerShareClassLoaderRule();


    @Rule
    public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();

    /**
    /**
     * {@link TouchExplorer#sendDownForAllNotInjectedPointers} injecting events with the same object
     * {@link TouchExplorer#sendDownForAllNotInjectedPointers} injecting events with the same object
     * is resulting {@link ArgumentCaptor} to capture events with last state. Before implementation
     * is resulting {@link ArgumentCaptor} to capture events with last state. Before implementation
@@ -161,11 +170,16 @@ public class TouchExplorerTest {
        goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
        goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
        // Wait for transiting to touch exploring state.
        // Wait for transiting to touch exploring state.
        mHandler.fastForward(2 * USER_INTENT_TIMEOUT);
        mHandler.fastForward(2 * USER_INTENT_TIMEOUT);
        moveEachPointers(mLastEvent, p(10, 10));
        assertState(STATE_TOUCH_EXPLORING);
        send(mLastEvent);
        // Manually construct the next move event. Using moveEachPointers() will batch the move
        // event which produces zero movement for some reason.
        float[] x = new float[1];
        float[] y = new float[1];
        x[0] = mLastEvent.getX(0) + mTouchSlop;
        y[0] = mLastEvent.getY(0) + mTouchSlop;
        send(manyPointerEvent(ACTION_MOVE, x, y));
        goToStateClearFrom(STATE_TOUCH_EXPLORING_1FINGER);
        goToStateClearFrom(STATE_TOUCH_EXPLORING_1FINGER);
        assertCapturedEvents(ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT);
        assertCapturedEvents(ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT);
        assertState(STATE_TOUCH_EXPLORING);
    }
    }


    /**
    /**
@@ -173,7 +187,34 @@ public class TouchExplorerTest {
     * change the coordinates.
     * change the coordinates.
     */
     */
    @Test
    @Test
    public void testOneFingerMoveWithExtraMoveEvents() {
    @RequiresFlagsEnabled(Flags.FLAG_REDUCE_TOUCH_EXPLORATION_SENSITIVITY)
    public void testOneFingerMoveWithExtraMoveEvents_generatesOneMoveEvent() {
        goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
        // Inject a set of move events that have the same coordinates as the down event.
        moveEachPointers(mLastEvent, p(0, 0));
        send(mLastEvent);
        // Wait for transition to touch exploring state.
        mHandler.fastForward(2 * USER_INTENT_TIMEOUT);
        // Now move for real.
        moveAtLeastTouchSlop(mLastEvent);
        send(mLastEvent);
        // One more move event with no change.
        moveEachPointers(mLastEvent, p(0, 0));
        send(mLastEvent);
        goToStateClearFrom(STATE_TOUCH_EXPLORING_1FINGER);
        assertCapturedEvents(
                ACTION_HOVER_ENTER,
                ACTION_HOVER_MOVE,
                ACTION_HOVER_EXIT);
    }

    /**
     * Test the case where ACTION_DOWN is followed by a number of ACTION_MOVE events that do not
     * change the coordinates.
     */
    @Test
    @RequiresFlagsDisabled(Flags.FLAG_REDUCE_TOUCH_EXPLORATION_SENSITIVITY)
    public void testOneFingerMoveWithExtraMoveEvents_generatesThreeMoveEvent() {
        goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
        goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
        // Inject a set of move events that have the same coordinates as the down event.
        // Inject a set of move events that have the same coordinates as the down event.
        moveEachPointers(mLastEvent, p(0, 0));
        moveEachPointers(mLastEvent, p(0, 0));
@@ -181,7 +222,7 @@ public class TouchExplorerTest {
        // Wait for transition to touch exploring state.
        // Wait for transition to touch exploring state.
        mHandler.fastForward(2 * USER_INTENT_TIMEOUT);
        mHandler.fastForward(2 * USER_INTENT_TIMEOUT);
        // Now move for real.
        // Now move for real.
        moveEachPointers(mLastEvent, p(10, 10));
        moveAtLeastTouchSlop(mLastEvent);
        send(mLastEvent);
        send(mLastEvent);
        // One more move event with no change.
        // One more move event with no change.
        moveEachPointers(mLastEvent, p(0, 0));
        moveEachPointers(mLastEvent, p(0, 0));
@@ -242,7 +283,7 @@ public class TouchExplorerTest {
        moveEachPointers(mLastEvent, p(0, 0), p(0, 0));
        moveEachPointers(mLastEvent, p(0, 0), p(0, 0));
        send(mLastEvent);
        send(mLastEvent);
        // Now move for real.
        // Now move for real.
        moveEachPointers(mLastEvent, p(10, 10), p(10, 10));
        moveEachPointers(mLastEvent, p(mTouchSlop, mTouchSlop), p(mTouchSlop, mTouchSlop));
        send(mLastEvent);
        send(mLastEvent);
        goToStateClearFrom(STATE_DRAGGING_2FINGERS);
        goToStateClearFrom(STATE_DRAGGING_2FINGERS);
        assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_MOVE, ACTION_MOVE, ACTION_UP);
        assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_MOVE, ACTION_MOVE, ACTION_UP);
@@ -251,7 +292,7 @@ public class TouchExplorerTest {
    @Test
    @Test
    public void testUpEvent_OneFingerMove_clearStateAndInjectHoverEvents() {
    public void testUpEvent_OneFingerMove_clearStateAndInjectHoverEvents() {
        goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
        goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
        moveEachPointers(mLastEvent, p(10, 10));
        moveAtLeastTouchSlop(mLastEvent);
        send(mLastEvent);
        send(mLastEvent);
        // Wait 10 ms to make sure that hover enter and exit are not scheduled for the same moment.
        // Wait 10 ms to make sure that hover enter and exit are not scheduled for the same moment.
        mHandler.fastForward(10);
        mHandler.fastForward(10);
@@ -277,7 +318,7 @@ public class TouchExplorerTest {


        // Wait for the finger moving to the second view.
        // Wait for the finger moving to the second view.
        mHandler.fastForward(oneThirdUserIntentTimeout);
        mHandler.fastForward(oneThirdUserIntentTimeout);
        moveEachPointers(mLastEvent, p(10, 10));
        moveAtLeastTouchSlop(mLastEvent);
        send(mLastEvent);
        send(mLastEvent);


        // Wait for the finger lifting from the second view.
        // Wait for the finger lifting from the second view.
@@ -402,7 +443,6 @@ public class TouchExplorerTest {
        // Manually construct the next move event. Using moveEachPointers() will batch the move
        // Manually construct the next move event. Using moveEachPointers() will batch the move
        // event onto the pointer up event which will mean that the move event still has a pointer
        // event onto the pointer up event which will mean that the move event still has a pointer
        // count of 3.
        // count of 3.
        // Todo: refactor to avoid using batching as there is no special reason to do it that way.
        float[] x = new float[2];
        float[] x = new float[2];
        float[] y = new float[2];
        float[] y = new float[2];
        x[0] = mLastEvent.getX(0) + 100;
        x[0] = mLastEvent.getX(0) + 100;
@@ -734,6 +774,9 @@ public class TouchExplorerTest {
        }
        }
    }
    }


    private void moveAtLeastTouchSlop(MotionEvent event) {
        moveEachPointers(event, p(2 * mTouchSlop, 0));
    }
    /**
    /**
     * A {@link android.os.Handler} that doesn't process messages until {@link #fastForward(int)} is
     * A {@link android.os.Handler} that doesn't process messages until {@link #fastForward(int)} is
     * invoked.
     * invoked.