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

Commit 7307cfaf authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Allow moving WindowMagnification with a mouse even at the edge of a screen" into main

parents 4d0222e0 567c01e1
Loading
Loading
Loading
Loading
+10 −0
Original line number Diff line number Diff line
@@ -67,3 +67,13 @@ flag {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    name: "window_magnification_move_with_mouse_on_edge"
    namespace: "accessibility"
    description: "Allows window magnification to be moved by mouse further on the edge of the screen."
    bug: "420776720"
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}
+72 −2
Original line number Diff line number Diff line
@@ -26,13 +26,17 @@ import static org.mockito.Mockito.verify;

import android.os.Handler;
import android.os.SystemClock;
import android.platform.test.annotations.EnableFlags;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

import androidx.test.core.view.PointerCoordsBuilder;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import androidx.test.filters.SmallTest;

import com.android.systemui.Flags;
import com.android.systemui.SysuiTestCase;

import org.junit.After;
@@ -50,9 +54,9 @@ public class MagnificationGestureDetectorTest extends SysuiTestCase {

    private static final float ACTION_DOWN_X = 100;
    private static final float ACTION_DOWN_Y = 200;
    private int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
    private final int mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
    private MagnificationGestureDetector mGestureDetector;
    private MotionEventHelper mMotionEventHelper = new MotionEventHelper();
    private final MotionEventHelper mMotionEventHelper = new MotionEventHelper();
    private View mSpyView;
    @Mock
    private MagnificationGestureDetector.OnGestureListener mListener;
@@ -133,6 +137,37 @@ public class MagnificationGestureDetectorTest extends SysuiTestCase {
        verify(mListener, never()).onSingleTap(mSpyView);
    }

    @Test
    public void performSingleTapWithBatchedSmallTouchEvents_invokeCallback() {
        mGestureDetector = new MagnificationGestureDetector(mContext, mHandler, mListener);

        final long downTime = SystemClock.uptimeMillis();
        final MotionEvent.PointerCoords coords = PointerCoordsBuilder.newBuilder()
                .setCoords(ACTION_DOWN_X, ACTION_DOWN_Y).build();

        final MotionEvent downEvent = mMotionEventHelper.obtainBatchedMotionEvent(downTime,
                MotionEvent.ACTION_DOWN, InputDevice.SOURCE_TOUCHSCREEN,
                MotionEvent.TOOL_TYPE_FINGER, coords);

        // Move event without changing location.
        final MotionEvent.PointerCoords dragCoords1 = PointerCoordsBuilder.newBuilder()
                .setCoords(ACTION_DOWN_X + mTouchSlop / 2.f, ACTION_DOWN_Y).build();
        final MotionEvent.PointerCoords dragCoords2 = new MotionEvent.PointerCoords(dragCoords1);
        final MotionEvent moveEvent = mMotionEventHelper.obtainBatchedMotionEvent(downTime,
                MotionEvent.ACTION_MOVE, InputDevice.SOURCE_TOUCHSCREEN,
                MotionEvent.TOOL_TYPE_FINGER, dragCoords1, dragCoords2);

        final MotionEvent upEvent = mMotionEventHelper.obtainBatchedMotionEvent(downTime,
                MotionEvent.ACTION_UP, InputDevice.SOURCE_TOUCHSCREEN, MotionEvent.TOOL_TYPE_FINGER,
                coords);

        mGestureDetector.onTouch(mSpyView, downEvent);
        mGestureDetector.onTouch(mSpyView, moveEvent);
        mGestureDetector.onTouch(mSpyView, upEvent);

        verify(mListener).onSingleTap(mSpyView);
    }

    @Test
    public void performLongPress_invokeCallbacksInOrder() {
        final long downTime = SystemClock.uptimeMillis();
@@ -173,4 +208,39 @@ public class MagnificationGestureDetectorTest extends SysuiTestCase {
        inOrder.verify(mListener).onFinish(ACTION_DOWN_X, ACTION_DOWN_Y);
        verify(mListener, never()).onSingleTap(mSpyView);
    }

    @Test
    @EnableFlags(Flags.FLAG_WINDOW_MAGNIFICATION_MOVE_WITH_MOUSE_ON_EDGE)
    public void performDragWithMouse_invokeCallbacksUsingRelative() {
        mGestureDetector = new MagnificationGestureDetector(mContext, mHandler, mListener);

        final long downTime = SystemClock.uptimeMillis();
        final MotionEvent.PointerCoords coords = PointerCoordsBuilder.newBuilder()
                .setCoords(ACTION_DOWN_X, ACTION_DOWN_Y).build();

        final MotionEvent downEvent = mMotionEventHelper.obtainBatchedMotionEvent(downTime,
                MotionEvent.ACTION_DOWN, InputDevice.SOURCE_MOUSE, MotionEvent.TOOL_TYPE_MOUSE,
                coords);

        // Drag event without changing location but with relative delta on X axis.
        final MotionEvent.PointerCoords dragCoords1 = new MotionEvent.PointerCoords(coords);
        dragCoords1.setAxisValue(MotionEvent.AXIS_RELATIVE_X, mTouchSlop + 10);
        final MotionEvent.PointerCoords dragCoords2 = new MotionEvent.PointerCoords(coords);
        dragCoords2.setAxisValue(MotionEvent.AXIS_RELATIVE_X, 20);
        final MotionEvent moveEvent = mMotionEventHelper.obtainBatchedMotionEvent(downTime,
                MotionEvent.ACTION_MOVE, InputDevice.SOURCE_MOUSE, MotionEvent.TOOL_TYPE_MOUSE,
                dragCoords1, dragCoords2);

        final MotionEvent upEvent = mMotionEventHelper.obtainBatchedMotionEvent(downTime,
                MotionEvent.ACTION_UP, InputDevice.SOURCE_MOUSE, MotionEvent.TOOL_TYPE_MOUSE,
                coords);

        mGestureDetector.onTouch(mSpyView, downEvent);
        mGestureDetector.onTouch(mSpyView, moveEvent);
        mGestureDetector.onTouch(mSpyView, upEvent);

        verify(mListener).onStart(ACTION_DOWN_X, ACTION_DOWN_Y);
        verify(mListener).onDrag(mSpyView, mTouchSlop + 30, 0);
        verify(mListener).onFinish(ACTION_DOWN_X, ACTION_DOWN_Y);
    }
}
+23 −2
Original line number Diff line number Diff line
@@ -22,10 +22,13 @@ import android.content.Context;
import android.graphics.PointF;
import android.os.Handler;
import android.view.Display;
import android.view.InputDevice;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;

import com.android.systemui.Flags;

/**
 * Detects single tap and drag gestures using the supplied {@link MotionEvent}s. The {@link
 * OnGestureListener} callback will notify users when a particular motion event has occurred. This
@@ -194,8 +197,22 @@ class MagnificationGestureDetector {
                    break;
                case MotionEvent.ACTION_MOVE:
                case MotionEvent.ACTION_UP:
                    float dx = event.getRawX() - mLastLocation.x;
                    float dy = event.getRawY() - mLastLocation.y;
                    float dx = 0;
                    float dy = 0;
                    if (Flags.windowMagnificationMoveWithMouseOnEdge() && isMouseEvent(event)) {
                        // With mouse input, we use relative delta values so that user can drag
                        // even at the edge of the screen, where the pointer location doesn't change
                        // but input event still contain the delta value.
                        for (int i = 0; i < event.getHistorySize(); i++) {
                            dx += event.getHistoricalAxisValue(MotionEvent.AXIS_RELATIVE_X, i);
                            dy += event.getHistoricalAxisValue(MotionEvent.AXIS_RELATIVE_Y, i);
                        }
                        dx += event.getAxisValue(MotionEvent.AXIS_RELATIVE_X);
                        dy += event.getAxisValue(MotionEvent.AXIS_RELATIVE_Y);
                    } else {
                        dx = event.getRawX() - mLastLocation.x;
                        dy = event.getRawY() - mLastLocation.y;
                    }
                    mAccumulatedDelta.offset(dx, dy);
                    mLastLocation.set(event.getRawX(), event.getRawY());
                    break;
@@ -227,5 +244,9 @@ class MagnificationGestureDetector {
            pointF.x = Float.NaN;
            pointF.y = Float.NaN;
        }

        private static boolean isMouseEvent(MotionEvent event) {
            return (event.getSource() & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE;
        }
    }
}
+31 −0
Original line number Diff line number Diff line
@@ -18,6 +18,9 @@ package com.android.systemui.accessibility;

import android.view.MotionEvent;

import androidx.test.core.view.MotionEventBuilder;
import androidx.test.core.view.PointerPropertiesBuilder;

import com.android.internal.annotations.GuardedBy;

import java.util.ArrayList;
@@ -44,4 +47,32 @@ public class MotionEventHelper {
        }
        return event;
    }

    /**
     * Creates a {@link MotionEvent} with a batch of pointers. Call this with one or more pointer
     * coordinates, which will be added to the batch of the event.
     */
    public MotionEvent obtainBatchedMotionEvent(long downTime, int action, int source,
            int toolType, MotionEvent.PointerCoords... coords) {
        if (coords.length == 0) {
            throw new IllegalArgumentException("coords cannot be empty");
        }
        MotionEvent event = MotionEventBuilder.newBuilder()
                .setDownTime(downTime)
                .setEventTime(downTime)
                .setAction(action)
                .setSource(source)
                .setPointer(
                        PointerPropertiesBuilder.newBuilder().setToolType(toolType).build(),
                        coords[0])
                .build();
        for (int i = 1; i < coords.length; i++) {
            event.addBatch(downTime, new MotionEvent.PointerCoords[]{coords[i]}, /* metaState= */
                    0);
        }
        synchronized (this) {
            mMotionEvents.add(event);
        }
        return event;
    }
}