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

Commit e27a8ea8 authored by Katie Dektar's avatar Katie Dektar Committed by Android (Google) Code Review
Browse files

Merge "[A11y] Adds ability for magnifier to follow mouse and stylus" into main

parents c4c834fe 02bd8c6c
Loading
Loading
Loading
Loading
+17 −9
Original line number Diff line number Diff line
@@ -45,9 +45,11 @@ import android.view.accessibility.AccessibilityEvent;

import com.android.server.LocalServices;
import com.android.server.accessibility.gestures.TouchExplorer;
import com.android.server.accessibility.magnification.FullScreenMagnificationController;
import com.android.server.accessibility.magnification.FullScreenMagnificationGestureHandler;
import com.android.server.accessibility.magnification.FullScreenMagnificationVibrationHelper;
import com.android.server.accessibility.magnification.MagnificationGestureHandler;
import com.android.server.accessibility.magnification.MouseEventHandler;
import com.android.server.accessibility.magnification.WindowMagnificationGestureHandler;
import com.android.server.accessibility.magnification.WindowMagnificationPromptController;
import com.android.server.policy.WindowManagerPolicy;
@@ -864,15 +866,21 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
                    TYPE_MAGNIFICATION_OVERLAY, null /* options */);
            FullScreenMagnificationVibrationHelper fullScreenMagnificationVibrationHelper =
                    new FullScreenMagnificationVibrationHelper(uiContext);
            magnificationGestureHandler = new FullScreenMagnificationGestureHandler(uiContext,
                    mAms.getMagnificationController().getFullScreenMagnificationController(),
            FullScreenMagnificationController controller =
                    mAms.getMagnificationController().getFullScreenMagnificationController();
            magnificationGestureHandler =
                    new FullScreenMagnificationGestureHandler(
                            uiContext,
                            controller,
                            mAms.getTraceManager(),
                            mAms.getMagnificationController(),
                            detectControlGestures,
                            detectTwoFingerTripleTap,
                            triggerable,
                    new WindowMagnificationPromptController(displayContext, mUserId), displayId,
                    fullScreenMagnificationVibrationHelper);
                            new WindowMagnificationPromptController(displayContext, mUserId),
                            displayId,
                            fullScreenMagnificationVibrationHelper,
                            new MouseEventHandler(controller));
        }
        return magnificationGestureHandler;
    }
+38 −14
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.accessibility.magnification;

import static android.view.InputDevice.SOURCE_MOUSE;
import static android.view.InputDevice.SOURCE_STYLUS;
import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_DOWN;
@@ -183,7 +185,10 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
    private final int mMinimumVelocity;
    private final int mMaximumVelocity;

    public FullScreenMagnificationGestureHandler(@UiContext Context context,
    private MouseEventHandler mMouseEventHandler;

    public FullScreenMagnificationGestureHandler(
            @UiContext Context context,
            FullScreenMagnificationController fullScreenMagnificationController,
            AccessibilityTraceManager trace,
            Callback callback,
@@ -192,7 +197,8 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
            boolean detectShortcutTrigger,
            @NonNull WindowMagnificationPromptController promptController,
            int displayId,
            FullScreenMagnificationVibrationHelper fullScreenMagnificationVibrationHelper) {
            FullScreenMagnificationVibrationHelper fullScreenMagnificationVibrationHelper,
            MouseEventHandler mouseEventHandler) {
        this(
                context,
                fullScreenMagnificationController,
@@ -207,9 +213,8 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
                /* magnificationLogger= */ null,
                ViewConfiguration.get(context),
                new OneFingerPanningSettingsProvider(
                        context,
                        Flags.enableMagnificationOneFingerPanningGesture()
                ));
                        context, Flags.enableMagnificationOneFingerPanningGesture()),
                mouseEventHandler);
    }

    /** Constructor for tests. */
@@ -227,8 +232,8 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
            FullScreenMagnificationVibrationHelper fullScreenMagnificationVibrationHelper,
            MagnificationLogger magnificationLogger,
            ViewConfiguration viewConfiguration,
            OneFingerPanningSettingsProvider oneFingerPanningSettingsProvider
    ) {
            OneFingerPanningSettingsProvider oneFingerPanningSettingsProvider,
            MouseEventHandler mouseEventHandler) {
        super(displayId, detectSingleFingerTripleTap, detectTwoFingerTripleTap,
                detectShortcutTrigger, trace, callback);
        if (DEBUG_ALL) {
@@ -318,6 +323,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
        mOverscrollEdgeSlop = context.getResources().getDimensionPixelSize(
                R.dimen.accessibility_fullscreen_magnification_gesture_edge_slop);
        mIsWatch = context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_WATCH);
        mMouseEventHandler = mouseEventHandler;

        if (mDetectShortcutTrigger) {
            mScreenStateReceiver = new ScreenStateReceiver(context, this);
@@ -331,15 +337,28 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH

    @Override
    void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
        if (event.getSource() == SOURCE_TOUCHSCREEN) {
            if (event.getActionMasked() == ACTION_DOWN) {
                cancelFling();
            }
            handleTouchEventWith(mCurrentState, event, rawEvent, policyFlags);
        } else if (Flags.enableMagnificationFollowsMouse()
                && (event.getSource() == SOURCE_MOUSE || event.getSource() == SOURCE_STYLUS)) {
            if (mFullScreenMagnificationController.isActivated(mDisplayId)) {
                // TODO(b/354696546): Allow mouse/stylus to activate whichever display they are
                // over, rather than only interacting with the current display.

        handleEventWith(mCurrentState, event, rawEvent, policyFlags);
                // Send through the mouse/stylus event handler.
                mMouseEventHandler.onEvent(event, mDisplayId);
            }
            // Dispatch to normal event handling flow.
            dispatchTransformedEvent(event, rawEvent, policyFlags);
        }
    }

    private void handleTouchEventWith(
            State stateHandler, MotionEvent event, MotionEvent rawEvent, int policyFlags) {

    private void handleEventWith(State stateHandler,
            MotionEvent event, MotionEvent rawEvent, int policyFlags) {
        // To keep InputEventConsistencyVerifiers within GestureDetectors happy
        mPanningScalingState.mScrollGestureDetector.onTouchEvent(event);
        mPanningScalingState.mScaleGestureDetector.onTouchEvent(event);
@@ -1421,6 +1440,11 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH

        protected void cacheDelayedMotionEvent(MotionEvent event, MotionEvent rawEvent,
                int policyFlags) {
            if (Flags.enableMagnificationFollowsMouse()
                    && !event.isFromSource(SOURCE_TOUCHSCREEN)) {
                // Only touch events need to be cached and sent later.
                return;
            }
            if (event.getActionMasked() == ACTION_DOWN) {
                mPreLastDown = mLastDown;
                mLastDown = MotionEvent.obtain(event);
@@ -1458,7 +1482,7 @@ public class FullScreenMagnificationGestureHandler extends MagnificationGestureH
                mDelayedEventQueue = info.mNext;

                info.event.setDownTime(info.event.getDownTime() + offset);
                handleEventWith(mDelegatingState, info.event, info.rawEvent, info.policyFlags);
                handleTouchEventWith(mDelegatingState, info.event, info.rawEvent, info.policyFlags);

                info.recycle();
            } while (mDelayedEventQueue != null);
+29 −4
Original line number Diff line number Diff line
@@ -16,6 +16,8 @@

package com.android.server.accessibility.magnification;

import static android.view.InputDevice.SOURCE_MOUSE;
import static android.view.InputDevice.SOURCE_STYLUS;
import static android.view.InputDevice.SOURCE_TOUCHSCREEN;
import static android.view.MotionEvent.ACTION_CANCEL;
import static android.view.MotionEvent.ACTION_UP;
@@ -139,13 +141,36 @@ public abstract class MagnificationGestureHandler extends BaseEventStreamTransfo
        }
    }

    /**
     * Some touchscreen, mouse and stylus events may modify magnifier state. Checks for whether the
     * event should not be dispatched to the magnifier.
     *
     * @param event The event to check.
     * @return `true` if the event should be sent through the normal event flow or `false` if it
     *     should be observed by magnifier.
     */
    private boolean shouldDispatchTransformedEvent(MotionEvent event) {
        if ((!mDetectSingleFingerTripleTap && !mDetectTwoFingerTripleTap && !mDetectShortcutTrigger)
                || !event.isFromSource(SOURCE_TOUCHSCREEN)) {
            return true;
        if (event.getSource() == SOURCE_TOUCHSCREEN) {
            if (mDetectSingleFingerTripleTap
                    || mDetectTwoFingerTripleTap
                    || mDetectShortcutTrigger) {
                // Observe touchscreen events while magnification activation is detected.
                return false;
            }
        }
        if (Flags.enableMagnificationFollowsMouse()) {
            if (event.isFromSource(SOURCE_MOUSE) || event.isFromSource(SOURCE_STYLUS)) {
                // Note that mouse events include other mouse-like pointing devices
                // such as touchpads and pointing sticks.
                // Observe any mouse or stylus movement.
                // We observe all movement to ensure that events continue to come in order,
                // even though only some movement types actually move the viewport.
                return false;
            }
        }
        // Magnification dispatches (ignores) all other events
        return true;
    }

    final void dispatchTransformedEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
        if (DEBUG_EVENT_STREAM) {
+61 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.server.accessibility.magnification;

import static android.view.InputDevice.SOURCE_MOUSE;
import static android.view.MotionEvent.ACTION_HOVER_MOVE;
import static android.view.MotionEvent.ACTION_MOVE;

import android.view.MotionEvent;

import com.android.server.accessibility.AccessibilityManagerService;

/** MouseEventHandler handles mouse and stylus events that should move the viewport. */
public final class MouseEventHandler {
    private final FullScreenMagnificationController mFullScreenMagnificationController;

    public MouseEventHandler(FullScreenMagnificationController fullScreenMagnificationController) {
        mFullScreenMagnificationController = fullScreenMagnificationController;
    }

    /**
     * Handles a mouse or stylus event, moving the magnifier if needed.
     *
     * @param event The mouse or stylus MotionEvent to consume
     * @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)) {
            final float eventX = event.getX();
            final float eventY = event.getY();

            // Only move the viewport when over a magnified region.
            // TODO(b/354696546): Ensure this doesn't stop the viewport from reaching the
            // corners and edges at high levels of magnification.
            if (mFullScreenMagnificationController.magnificationRegionContains(
                    displayId, eventX, eventY)) {
                mFullScreenMagnificationController.setCenter(
                        displayId,
                        eventX,
                        eventY,
                        /* animate= */ false,
                        AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
            }
        }
    }
}
+4 −0
Original line number Diff line number Diff line
@@ -148,6 +148,10 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl

    @Override
    void onMotionEventInternal(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
        if (event.getSource() != SOURCE_TOUCHSCREEN) {
            // Window Magnification viewport doesn't move with mouse events (yet).
            return;
        }
        // To keep InputEventConsistencyVerifiers within GestureDetectors happy.
        mObservePanningScalingState.mPanningScalingHandler.onTouchEvent(event);
        mCurrentState.onMotionEvent(event, rawEvent, policyFlags);
Loading