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
diff --git a/services/accessibility/accessibility.aconfig b/services/accessibility/accessibility.aconfig
index 25b6244..f09cb19 100644
--- a/services/accessibility/accessibility.aconfig
+++ b/services/accessibility/accessibility.aconfig
@@ -55,3 +55,10 @@
description: "Scans packages for accessibility service/activity info without holding the A11yMS lock"
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"
+}
diff --git a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
index c418485..fc8d4f8 100644
--- a/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
+++ b/services/accessibility/java/com/android/server/accessibility/gestures/TouchExplorer.java
@@ -882,10 +882,22 @@
final int pointerIndex = event.findPointerIndex(pointerId);
switch (event.getPointerCount()) {
case 1:
- // Touch exploration.
+ // Touch exploration.
sendTouchExplorationGestureStartAndHoverEnterIfNeeded(policyFlags);
- mDispatcher.sendMotionEvent(
- event, ACTION_HOVER_MOVE, rawEvent, pointerIdBits, 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(
+ event, ACTION_HOVER_MOVE, rawEvent, pointerIdBits, policyFlags);
+ }
break;
case 2:
if (mGestureDetector.isMultiFingerGesturesEnabled()
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
index 1cd61e9..efcdbd4 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/gestures/TouchExplorerTest.java
@@ -44,6 +44,10 @@
import android.graphics.PointF;
import android.os.Looper;
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.view.InputDevice;
import android.view.MotionEvent;
@@ -56,6 +60,7 @@
import com.android.server.accessibility.AccessibilityManagerService;
import com.android.server.accessibility.AccessibilityTraceManager;
import com.android.server.accessibility.EventStreamTransformation;
+import com.android.server.accessibility.Flags;
import com.android.server.accessibility.utils.GestureLogParser;
import com.android.server.testutils.OffsettableClock;
@@ -76,6 +81,7 @@
import java.util.ArrayList;
import java.util.List;
+
@RunWith(AndroidJUnit4.class)
public class TouchExplorerTest {
@@ -119,6 +125,9 @@
public final DexmakerShareClassLoaderRule mDexmakerShareClassLoaderRule =
new DexmakerShareClassLoaderRule();
+ @Rule
+ public final CheckFlagsRule mCheckFlagsRule = DeviceFlagsValueProvider.createCheckFlagsRule();
+
/**
* {@link TouchExplorer#sendDownForAllNotInjectedPointers} injecting events with the same object
* is resulting {@link ArgumentCaptor} to capture events with last state. Before implementation
@@ -161,11 +170,16 @@
goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
// Wait for transiting to touch exploring state.
mHandler.fastForward(2 * USER_INTENT_TIMEOUT);
- moveEachPointers(mLastEvent, p(10, 10));
- send(mLastEvent);
+ assertState(STATE_TOUCH_EXPLORING);
+ // 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);
assertCapturedEvents(ACTION_HOVER_ENTER, ACTION_HOVER_MOVE, ACTION_HOVER_EXIT);
- assertState(STATE_TOUCH_EXPLORING);
}
/**
@@ -173,7 +187,8 @@
* change the coordinates.
*/
@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));
@@ -181,7 +196,33 @@
// Wait for transition to touch exploring state.
mHandler.fastForward(2 * USER_INTENT_TIMEOUT);
// Now move for real.
- moveEachPointers(mLastEvent, p(10, 10));
+ 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);
+ // 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));
@@ -242,7 +283,7 @@
moveEachPointers(mLastEvent, p(0, 0), p(0, 0));
send(mLastEvent);
// Now move for real.
- moveEachPointers(mLastEvent, p(10, 10), p(10, 10));
+ moveEachPointers(mLastEvent, p(mTouchSlop, mTouchSlop), p(mTouchSlop, mTouchSlop));
send(mLastEvent);
goToStateClearFrom(STATE_DRAGGING_2FINGERS);
assertCapturedEvents(ACTION_DOWN, ACTION_MOVE, ACTION_MOVE, ACTION_MOVE, ACTION_UP);
@@ -251,7 +292,7 @@
@Test
public void testUpEvent_OneFingerMove_clearStateAndInjectHoverEvents() {
goFromStateClearTo(STATE_TOUCH_EXPLORING_1FINGER);
- moveEachPointers(mLastEvent, p(10, 10));
+ moveAtLeastTouchSlop(mLastEvent);
send(mLastEvent);
// Wait 10 ms to make sure that hover enter and exit are not scheduled for the same moment.
mHandler.fastForward(10);
@@ -277,7 +318,7 @@
// Wait for the finger moving to the second view.
mHandler.fastForward(oneThirdUserIntentTimeout);
- moveEachPointers(mLastEvent, p(10, 10));
+ moveAtLeastTouchSlop(mLastEvent);
send(mLastEvent);
// Wait for the finger lifting from the second view.
@@ -402,7 +443,6 @@
// 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
// 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[] y = new float[2];
x[0] = mLastEvent.getX(0) + 100;
@@ -734,6 +774,9 @@
}
}
+ 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
* invoked.