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

Commit 6259298c authored by ryanlwlin's avatar ryanlwlin
Browse files

Gesture detection for window magnification (1/n)

To change the gesturehandler easily for different magnification mode,
we rename MagnificationGestureHandler to FullScreenMagnificationGestureHandler
and add a common class MagnificationGestureHandler. We will create
different MagnificationGestureHandler based on magnification mode.

Bug: 146400227
Test:FullScreenMagnificationGestureHandlerTest
Test: AccessibilityInputFilterTest.java
Change-Id: Ib7a45300a1f1323e1005b89694bb66932b22ab1b
parent 2cc1d117
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -31,6 +31,7 @@ import android.view.accessibility.AccessibilityEvent;

import com.android.server.LocalServices;
import com.android.server.accessibility.gestures.TouchExplorer;
import com.android.server.accessibility.magnification.MagnificationGestureHandler;
import com.android.server.policy.WindowManagerPolicy;

import java.util.ArrayList;
@@ -402,7 +403,7 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo
                final boolean triggerable = (mEnabledFeatures
                        & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0;
                MagnificationGestureHandler magnificationGestureHandler =
                        new MagnificationGestureHandler(displayContext,
                        new FullScreenMagnificationGestureHandler(displayContext,
                                mAms.getMagnificationController(),
                                detectControlGestures, triggerable, displayId);
                addFirstEventHandler(displayId, magnificationGestureHandler);
+49 −46
Original line number Diff line number Diff line
@@ -53,14 +53,16 @@ import android.view.ScaleGestureDetector;
import android.view.ScaleGestureDetector.OnScaleGestureListener;
import android.view.ViewConfiguration;

import com.android.internal.R;
import com.android.internal.annotations.VisibleForTesting;
import com.android.server.accessibility.gestures.GestureUtils;
import com.android.server.accessibility.magnification.MagnificationGestureHandler;

import java.util.ArrayDeque;
import java.util.Queue;

/**
 * This class handles magnification in response to touch events.
 * This class handles full screen magnification in response to touch events.
 *
 * The behavior is as follows:
 *
@@ -108,14 +110,14 @@ import java.util.Queue;
 * 7. The magnification scale will be persisted in settings and in the cloud.
 */
@SuppressWarnings("WeakerAccess")
class MagnificationGestureHandler extends BaseEventStreamTransformation {
    private static final String LOG_TAG = "MagnificationGestureHandler";
class FullScreenMagnificationGestureHandler extends MagnificationGestureHandler {
    private static final String LOG_TAG = "FullScreenMagnificationGestureHandler";

    private static final boolean DEBUG_ALL = false;
    private static final boolean DEBUG_STATE_TRANSITIONS = false || DEBUG_ALL;
    private static final boolean DEBUG_DETECTING = false || DEBUG_ALL;
    private static final boolean DEBUG_PANNING_SCALING = false || DEBUG_ALL;
    private static final boolean DEBUG_EVENT_STREAM = false || DEBUG_ALL;
    private static final boolean DEBUG_STATE_TRANSITIONS = false | DEBUG_ALL;
    private static final boolean DEBUG_DETECTING = false | DEBUG_ALL;
    private static final boolean DEBUG_PANNING_SCALING = false | DEBUG_ALL;
    private static final boolean DEBUG_EVENT_STREAM = false | DEBUG_ALL;

    // The MIN_SCALE is different from MagnificationController.MIN_SCALE due
    // to AccessibilityService.MagnificationController#setScale() has
@@ -167,14 +169,14 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
     *                           {@code false} if it should ignore such triggers.
     * @param displayId The logical display id.
     */
    public MagnificationGestureHandler(Context context,
    FullScreenMagnificationGestureHandler(Context context,
            MagnificationController magnificationController,
            boolean detectTripleTap,
            boolean detectShortcutTrigger,
            int displayId) {
        if (DEBUG_ALL) {
            Log.i(LOG_TAG,
                    "MagnificationGestureHandler(detectTripleTap = " + detectTripleTap
                    "FullScreenMagnificationGestureHandler(detectTripleTap = " + detectTripleTap
                            + ", detectShortcutTrigger = " + detectShortcutTrigger + ")");
        }

@@ -263,7 +265,8 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
        clearAndTransitionToStateDetecting();
    }

    void notifyShortcutTriggered() {
    @Override
    public void notifyShortcutTriggered() {
        if (mDetectShortcutTrigger) {
            boolean wasMagnifying = mMagnificationController.resetIfNeeded(mDisplayId,
                    /* animate */ true);
@@ -383,10 +386,10 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
        float mInitialScaleFactor = -1;
        boolean mScaling;

        public PanningScalingState(Context context) {
        PanningScalingState(Context context) {
            final TypedValue scaleValue = new TypedValue();
            context.getResources().getValue(
                    com.android.internal.R.dimen.config_screen_magnification_scaling_threshold,
                    R.dimen.config_screen_magnification_scaling_threshold,
                    scaleValue, false);
            mScalingThreshold = scaleValue.getFloat();
            mScaleGestureDetector = new ScaleGestureDetector(context, this, Handler.getMain());
@@ -407,7 +410,6 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
            } else if (action == ACTION_UP || action == ACTION_CANCEL) {

                persistScaleAndTransitionTo(mDetectingState);

            }
        }

@@ -489,10 +491,9 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {

        @Override
        public String toString() {
            return "PanningScalingState{" +
                    "mInitialScaleFactor=" + mInitialScaleFactor +
                    ", mScaling=" + mScaling +
                    '}';
            return "PanningScalingState{" + "mInitialScaleFactor=" + mInitialScaleFactor
                    + ", mScaling=" + mScaling
                    + '}';
        }
    }

@@ -561,10 +562,10 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {

        @Override
        public String toString() {
            return "ViewportDraggingState{" +
                    "mZoomedInBeforeDrag=" + mZoomedInBeforeDrag +
                    ", mLastMoveOutsideMagnifiedRegion=" + mLastMoveOutsideMagnifiedRegion +
                    '}';
            return "ViewportDraggingState{"
                    + "mZoomedInBeforeDrag=" + mZoomedInBeforeDrag
                    + ", mLastMoveOutsideMagnifiedRegion=" + mLastMoveOutsideMagnifiedRegion
                    + '}';
        }
    }

@@ -577,13 +578,14 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
        @Override
        public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {

        	// Ensure that the state at the end of delegation is consistent with the last delegated
            // Ensures that the state at the end of delegation is consistent with the last delegated
            // UP/DOWN event in queue: still delegating if pointer is down, detecting otherwise
            switch (event.getActionMasked()) {
                case ACTION_UP:
                case ACTION_CANCEL: {
                    transitionTo(mDetectingState);
                } break;
                }
                    break;

                case ACTION_DOWN: {
                    transitionTo(mDelegatingState);
@@ -630,11 +632,11 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {

        @VisibleForTesting Handler mHandler = new Handler(Looper.getMainLooper(), this);

        public DetectingState(Context context) {
        DetectingState(Context context) {
            mLongTapMinDelay = ViewConfiguration.getLongPressTimeout();
            mMultiTapMaxDelay = ViewConfiguration.getDoubleTapTimeout()
                    + context.getResources().getInteger(
                    com.android.internal.R.integer.config_screen_magnification_multi_tap_adjustment);
                    R.integer.config_screen_magnification_multi_tap_adjustment);
            mSwipeMinDistance = ViewConfiguration.get(context).getScaledTouchSlop();
            mMultiTapMaxDistance = ViewConfiguration.get(context).getScaledDoubleTapSlop();
        }
@@ -913,11 +915,11 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {

        @Override
        public String toString() {
            return "DetectingState{" +
                    "tapCount()=" + tapCount() +
                    ", mShortcutTriggered=" + mShortcutTriggered +
                    ", mDelayedEventQueue=" + MotionEventInfo.toString(mDelayedEventQueue) +
                    '}';
            return "DetectingState{"
                    + "tapCount()=" + tapCount()
                    + ", mShortcutTriggered=" + mShortcutTriggered
                    + ", mDelayedEventQueue=" + MotionEventInfo.toString(mDelayedEventQueue)
                    + '}';
        }

        void toggleShortcutTriggered() {
@@ -986,18 +988,18 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {

    @Override
    public String toString() {
        return "MagnificationGesture{" +
                "mDetectingState=" + mDetectingState +
                ", mDelegatingState=" + mDelegatingState +
                ", mMagnifiedInteractionState=" + mPanningScalingState +
                ", mViewportDraggingState=" + mViewportDraggingState +
                ", mDetectTripleTap=" + mDetectTripleTap +
                ", mDetectShortcutTrigger=" + mDetectShortcutTrigger +
                ", mCurrentState=" + State.nameOf(mCurrentState) +
                ", mPreviousState=" + State.nameOf(mPreviousState) +
                ", mMagnificationController=" + mMagnificationController +
                ", mDisplayId=" + mDisplayId +
                '}';
        return "MagnificationGesture{"
                + "mDetectingState=" + mDetectingState
                + ", mDelegatingState=" + mDelegatingState
                + ", mMagnifiedInteractionState=" + mPanningScalingState
                + ", mViewportDraggingState=" + mViewportDraggingState
                + ", mDetectTripleTap=" + mDetectTripleTap
                + ", mDetectShortcutTrigger=" + mDetectShortcutTrigger
                + ", mCurrentState=" + State.nameOf(mCurrentState)
                + ", mPreviousState=" + State.nameOf(mPreviousState)
                + ", mMagnificationController=" + mMagnificationController
                + ", mDisplayId=" + mDisplayId
                + '}';
    }

    private static final class MotionEventInfo {
@@ -1085,9 +1087,10 @@ class MagnificationGestureHandler extends BaseEventStreamTransformation {
     */
    private static class ScreenStateReceiver extends BroadcastReceiver {
        private final Context mContext;
        private final MagnificationGestureHandler mGestureHandler;
        private final FullScreenMagnificationGestureHandler mGestureHandler;

        public ScreenStateReceiver(Context context, MagnificationGestureHandler gestureHandler) {
        ScreenStateReceiver(Context context,
                FullScreenMagnificationGestureHandler gestureHandler) {
            mContext = context;
            mGestureHandler = gestureHandler;
        }
+30 −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 com.android.server.accessibility.BaseEventStreamTransformation;

/**
 * A base class that detects gestures and defines common methods for magnification.
 */
public abstract class MagnificationGestureHandler extends BaseEventStreamTransformation {

    /**
     * Called when the shortcut target is magnification.
     */
    public abstract void notifyShortcutTriggered();
}
+1 −1
Original line number Diff line number Diff line
@@ -80,7 +80,7 @@ public class AccessibilityInputFilterTest {
    // The expected order of EventStreamTransformations.
    private final Class[] mExpectedEventHandlerTypes =
            {KeyboardInterceptor.class, MotionEventInjector.class,
                    MagnificationGestureHandler.class, TouchExplorer.class,
                    FullScreenMagnificationGestureHandler.class, TouchExplorer.class,
                    AutoclickController.class, AccessibilityInputFilter.class};

    private MagnificationController mMockMagnificationController;
+11 −9
Original line number Diff line number Diff line
@@ -59,7 +59,7 @@ import org.junit.runner.RunWith;
import java.util.function.IntConsumer;

/**
 * Tests the state transitions of {@link MagnificationGestureHandler}
 * Tests the state transitions of {@link FullScreenMagnificationGestureHandler}
 *
 * Here's a dot graph describing the transitions being tested:
 * {@code
@@ -87,7 +87,7 @@ import java.util.function.IntConsumer;
 * }
 */
@RunWith(AndroidJUnit4.class)
public class MagnificationGestureHandlerTest {
public class FullScreenMagnificationGestureHandlerTest {

    public static final int STATE_IDLE = 1;
    public static final int STATE_ZOOMED = 2;
@@ -113,7 +113,7 @@ public class MagnificationGestureHandlerTest {
    MagnificationController mMagnificationController;

    private OffsettableClock mClock;
    private MagnificationGestureHandler mMgh;
    private FullScreenMagnificationGestureHandler mMgh;
    private TestHandler mHandler;

    private long mLastDownTime = Integer.MIN_VALUE;
@@ -154,16 +154,17 @@ public class MagnificationGestureHandlerTest {
    }

    @NonNull
    private MagnificationGestureHandler newInstance(boolean detectTripleTap,
    private FullScreenMagnificationGestureHandler newInstance(boolean detectTripleTap,
            boolean detectShortcutTrigger) {
        MagnificationGestureHandler h = new MagnificationGestureHandler(
        FullScreenMagnificationGestureHandler h = new FullScreenMagnificationGestureHandler(
                mContext, mMagnificationController,
                detectTripleTap, detectShortcutTrigger, DISPLAY_0);
        mHandler = new TestHandler(h.mDetectingState, mClock) {
            @Override
            protected String messageToString(Message m) {
                return DebugUtils.valueToString(
                        MagnificationGestureHandler.DetectingState.class, "MESSAGE_", m.what);
                        FullScreenMagnificationGestureHandler.DetectingState.class, "MESSAGE_",
                        m.what);
            }
        };
        h.mDetectingState.mHandler = mHandler;
@@ -541,7 +542,8 @@ public class MagnificationGestureHandlerTest {
    }

    private static String stateToString(int state) {
        return DebugUtils.valueToString(MagnificationGestureHandlerTest.class, "STATE_", state);
        return DebugUtils.valueToString(FullScreenMagnificationGestureHandlerTest.class, "STATE_",
                state);
    }

    private void tap() {