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

Commit 555910e4 authored by Katie's avatar Katie
Browse files

[A11y] Do not move magnifier viewport for synthesized touchpad gestures

Ensures magnifier viewport is not moved for gestures synthesized
from gestures on the touchpad. For example, viewport is moved for
touchpad one finger movements but not for two-finger scrolls, which
are still passed to underlying content.

Bug: b/354696546
Test: Manual on device
Flag: com.android.server.accessibility.enable_magnification_follows_mouse
Change-Id: I504a512c94ae7e0411d1612f036fb131755cb0ce
parent 192b6f9c
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -39,8 +39,14 @@ public final class MouseEventHandler {
     * @param displayId The display that is being magnified
     */
    public void onEvent(MotionEvent event, int displayId) {
        if (event.getAction() == ACTION_HOVER_MOVE
                || (event.getAction() == ACTION_MOVE && event.getSource() == SOURCE_MOUSE)) {
        // Ignore gesture events synthesized from the touchpad.
        // TODO(b/354696546): Use synthesized pinch gestures to control scale.
        boolean isSynthesizedFromTouchpad =
                event.getClassification() != MotionEvent.CLASSIFICATION_NONE;

        // Consume only move events from the mouse or hovers from any tool.
        if (!isSynthesizedFromTouchpad && (event.getAction() == ACTION_HOVER_MOVE
                || (event.getAction() == ACTION_MOVE && event.getSource() == SOURCE_MOUSE))) {
            final float eventX = event.getX();
            final float eventY = event.getY();

+69 −0
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@ import static android.view.MotionEvent.ACTION_POINTER_DOWN;
import static android.view.MotionEvent.ACTION_POINTER_INDEX_SHIFT;
import static android.view.MotionEvent.ACTION_POINTER_UP;
import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.CLASSIFICATION_TWO_FINGER_SWIPE;
import static android.view.MotionEvent.TOOL_TYPE_FINGER;

import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;

@@ -1413,6 +1415,49 @@ public class FullScreenMagnificationGestureHandlerTest {
        runMoveEventsDoNotMoveMagnifierViewport(InputDevice.SOURCE_STYLUS);
    }

    @Test
    public void testSynthesizedGestureEventsDoNotMoveMagnifierViewport() {
        final EventCaptor eventCaptor = new EventCaptor();
        mMgh.setNext(eventCaptor);

        float centerX =
                (INITIAL_MAGNIFICATION_BOUNDS.left + INITIAL_MAGNIFICATION_BOUNDS.width()) / 2.0f;
        float centerY =
                (INITIAL_MAGNIFICATION_BOUNDS.top + INITIAL_MAGNIFICATION_BOUNDS.height()) / 2.0f;
        float scale = 5.6f; // value is unimportant but unique among tests to increase coverage.
        mFullScreenMagnificationController.setScaleAndCenter(
                DISPLAY_0, centerX, centerY, scale, /* animate= */ false, 1);
        centerX = mFullScreenMagnificationController.getCenterX(DISPLAY_0);
        centerY = mFullScreenMagnificationController.getCenterY(DISPLAY_0);

        // Second finger down on trackpad starts a synthesized two-finger swipe with source
        // mouse.
        MotionEvent downEvent = motionEvent(centerX, centerY, ACTION_DOWN,
                TOOL_TYPE_FINGER, CLASSIFICATION_TWO_FINGER_SWIPE);
        send(downEvent, InputDevice.SOURCE_MOUSE);
        fastForward(20);

        // Two-finger swipe creates a synthesized move event, and shouldn't impact magnifier
        // viewport.
        MotionEvent moveEvent = motionEvent(centerX - 42, centerY - 42, ACTION_MOVE,
                TOOL_TYPE_FINGER, CLASSIFICATION_TWO_FINGER_SWIPE);
        send(moveEvent, InputDevice.SOURCE_MOUSE);
        fastForward(20);

        assertThat(mFullScreenMagnificationController.getCenterX(DISPLAY_0)).isEqualTo(centerX);
        assertThat(mFullScreenMagnificationController.getCenterY(DISPLAY_0)).isEqualTo(centerY);

        // The events were not consumed by magnifier.
        assertThat(eventCaptor.mEvents.size()).isEqualTo(2);
        assertThat(eventCaptor.mEvents.get(0).getSource()).isEqualTo(InputDevice.SOURCE_MOUSE);
        assertThat(eventCaptor.mEvents.get(1).getSource()).isEqualTo(InputDevice.SOURCE_MOUSE);

        final List<Integer> expectedActions = new ArrayList();
        expectedActions.add(Integer.valueOf(ACTION_DOWN));
        expectedActions.add(Integer.valueOf(ACTION_MOVE));
        assertActionsInOrder(eventCaptor.mEvents, expectedActions);
    }

    @Test
    @RequiresFlagsDisabled(Flags.FLAG_ENABLE_MAGNIFICATION_FOLLOWS_MOUSE)
    public void testMouseHoverMoveEventsDoNotMoveMagnifierViewport() {
@@ -2130,6 +2175,30 @@ public class FullScreenMagnificationGestureHandlerTest {
        return MotionEvent.obtain(mLastDownTime, mClock.now(), action, x, y, 0);
    }

    private MotionEvent motionEvent(float x, float y, int action, int toolType,
            int classification) {
        // Create a generic motion event to populate the parameters.
        MotionEvent event = motionEvent(x, y, action);
        int pointerCount = event.getPointerCount();
        MotionEvent.PointerCoords[] coords = new MotionEvent.PointerCoords[pointerCount];
        MotionEvent.PointerProperties[] properties =
                new MotionEvent.PointerProperties[pointerCount];
        for (int i = 0; i < pointerCount; i++) {
            properties[i] = new MotionEvent.PointerProperties();
            event.getPointerProperties(i, properties[i]);
            properties[i].toolType = toolType;
            coords[i] = new MotionEvent.PointerCoords();
            event.getPointerCoords(i, coords[i]);
        }
        // Apply the custom classification.
        return MotionEvent.obtain(event.getDownTime(), event.getEventTime(), action,
                /*pointerCount=*/1, properties, coords,
                event.getMetaState(), event.getButtonState(),
                event.getXPrecision(), event.getYPrecision(), event.getDeviceId(),
                event.getEdgeFlags(), event.getSource(), event.getDisplayId(), event.getFlags(),
                classification);
    }

    private MotionEvent mouseEvent(float x, float y, int action) {
        return fromMouse(motionEvent(x, y, action));
    }