Loading services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +3 −2 Original line number Original line Diff line number Diff line Loading @@ -533,9 +533,10 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0; & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0; MagnificationGestureHandler magnificationGestureHandler; MagnificationGestureHandler magnificationGestureHandler; if (mAms.getMagnificationMode(displayId) if (mAms.getMagnificationMode(displayId) == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW && triggerable) { == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) { magnificationGestureHandler = new WindowMagnificationGestureHandler(displayContext, magnificationGestureHandler = new WindowMagnificationGestureHandler(displayContext, mAms.getWindowMagnificationMgr(), mAms::onMagnificationScaleChanged, displayId); mAms.getWindowMagnificationMgr(), mAms::onMagnificationScaleChanged, detectControlGestures, triggerable, displayId); } else { } else { magnificationGestureHandler = new FullScreenMagnificationGestureHandler(displayContext, magnificationGestureHandler = new FullScreenMagnificationGestureHandler(displayContext, mAms.getMagnificationController(), mAms::onMagnificationScaleChanged, mAms.getMagnificationController(), mAms::onMagnificationScaleChanged, Loading services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -37,6 +37,8 @@ class MagnificationGestureMatcher { public static final int GESTURE_SWIPE = GESTURE_BASE + 2; public static final int GESTURE_SWIPE = GESTURE_BASE + 2; public static final int GESTURE_SINGLE_TAP = GESTURE_BASE + 3; public static final int GESTURE_SINGLE_TAP = GESTURE_BASE + 3; public static final int GESTURE_SINGLE_TAP_AND_HOLD = GESTURE_BASE + 4; public static final int GESTURE_SINGLE_TAP_AND_HOLD = GESTURE_BASE + 4; public static final int GESTURE_TRIPLE_TAP = GESTURE_BASE + 5; public static final int GESTURE_TRIPLE_TAP_AND_HOLD = GESTURE_BASE + 6; @IntDef(prefix = {"GESTURE_MAGNIFICATION_"}, value = { @IntDef(prefix = {"GESTURE_MAGNIFICATION_"}, value = { GESTURE_TWO_FINGER_DOWN, GESTURE_TWO_FINGER_DOWN, Loading @@ -61,6 +63,10 @@ class MagnificationGestureMatcher { return "GESTURE_SINGLE_TAP"; return "GESTURE_SINGLE_TAP"; case GESTURE_SINGLE_TAP_AND_HOLD: case GESTURE_SINGLE_TAP_AND_HOLD: return "GESTURE_SINGLE_TAP_AND_HOLD"; return "GESTURE_SINGLE_TAP_AND_HOLD"; case GESTURE_TRIPLE_TAP: return "GESTURE_TRIPLE_TAP"; case GESTURE_TRIPLE_TAP_AND_HOLD: return "GESTURE_TRIPLE_TAP_AND_HOLD"; } } return "none"; return "none"; } } Loading services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java +56 −17 Original line number Original line Diff line number Diff line Loading @@ -44,9 +44,11 @@ import java.util.Queue; * This class handles window magnification in response to touch events and shortcut. * This class handles window magnification in response to touch events and shortcut. * * * The behavior is as follows: * The behavior is as follows: * * <ol> * <ol> * <li> Window magnification can be "toggled" by tapping shortcut. It is triggered via * <li> 1. Toggle Window magnification by triple-tap gesture shortcut. It is triggered via * {@link #onTripleTap(MotionEvent)}. * <li> 2. Toggle Window magnification by tapping shortcut. It is triggered via * {@link #notifyShortcutTriggered()}. * {@link #notifyShortcutTriggered()}. * <li> When the window magnifier is visible, pinching with any number of additional fingers * <li> When the window magnifier is visible, pinching with any number of additional fingers * would adjust the magnification scale .<strong>Note</strong> that this operation is valid only * would adjust the magnification scale .<strong>Note</strong> that this operation is valid only Loading @@ -72,7 +74,6 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl private static final float MAX_SCALE = WindowMagnificationManager.MAX_SCALE; private static final float MAX_SCALE = WindowMagnificationManager.MAX_SCALE; private final WindowMagnificationManager mWindowMagnificationMgr; private final WindowMagnificationManager mWindowMagnificationMgr; @VisibleForTesting @VisibleForTesting final DelegatingState mDelegatingState; final DelegatingState mDelegatingState; @VisibleForTesting @VisibleForTesting Loading @@ -85,6 +86,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl @VisibleForTesting @VisibleForTesting State mPreviousState; State mPreviousState; final boolean mDetectShortcutTrigger; private MotionEventDispatcherDelegate mMotionEventDispatcherDelegate; private MotionEventDispatcherDelegate mMotionEventDispatcherDelegate; private final int mDisplayId; private final int mDisplayId; Loading @@ -97,7 +100,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl */ */ public WindowMagnificationGestureHandler(Context context, public WindowMagnificationGestureHandler(Context context, WindowMagnificationManager windowMagnificationMgr, WindowMagnificationManager windowMagnificationMgr, MagnificationGestureHandler.ScaleChangedListener listener, int displayId) { MagnificationGestureHandler.ScaleChangedListener listener, boolean detectTripleTap, boolean detectShortcutTrigger, int displayId) { super(listener); super(listener); if (DEBUG_ALL) { if (DEBUG_ALL) { Slog.i(LOG_TAG, Slog.i(LOG_TAG, Loading @@ -105,12 +109,13 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl } } mWindowMagnificationMgr = windowMagnificationMgr; mWindowMagnificationMgr = windowMagnificationMgr; mDetectShortcutTrigger = detectShortcutTrigger; mDisplayId = displayId; mDisplayId = displayId; mMotionEventDispatcherDelegate = new MotionEventDispatcherDelegate(context, mMotionEventDispatcherDelegate = new MotionEventDispatcherDelegate(context, (event, rawEvent, policyFlags) -> super.onMotionEvent( (event, rawEvent, policyFlags) -> super.onMotionEvent( event, rawEvent, policyFlags)); event, rawEvent, policyFlags)); mDelegatingState = new DelegatingState(mMotionEventDispatcherDelegate); mDelegatingState = new DelegatingState(mMotionEventDispatcherDelegate); mDetectingState = new DetectingState(context); mDetectingState = new DetectingState(context, detectTripleTap); mObservePanningScalingState = new PanningScalingGestureState( mObservePanningScalingState = new PanningScalingGestureState( new PanningScalingHandler(context, MAX_SCALE, MIN_SCALE, true, new PanningScalingHandler(context, MAX_SCALE, MIN_SCALE, true, new PanningScalingHandler.MagnificationDelegate() { new PanningScalingHandler.MagnificationDelegate() { Loading Loading @@ -176,11 +181,10 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl if (DEBUG_ALL) { if (DEBUG_ALL) { Slog.i(LOG_TAG, "notifyShortcutTriggered():"); Slog.i(LOG_TAG, "notifyShortcutTriggered():"); } } if (mWindowMagnificationMgr.isWindowMagnifierEnabled(mDisplayId)) { if (!mDetectShortcutTrigger) { disableWindowMagnifier(); return; } else { enableWindowMagnifier(Float.NaN, Float.NaN); } } toggleMagnification(Float.NaN, Float.NaN); } } @Override @Override Loading @@ -206,6 +210,21 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl mWindowMagnificationMgr.disableWindowMagnifier(mDisplayId, false); mWindowMagnificationMgr.disableWindowMagnifier(mDisplayId, false); } } private void toggleMagnification(float centerX, float centerY) { if (mWindowMagnificationMgr.isWindowMagnifierEnabled(mDisplayId)) { disableWindowMagnifier(); } else { enableWindowMagnifier(centerX, centerY); } } private void onTripleTap(MotionEvent up) { if (DEBUG_DETECTING) { Slog.i(LOG_TAG, "onTripleTap()"); } toggleMagnification(up.getX(), up.getY()); } void resetToDetectState() { void resetToDetectState() { transitionTo(mDetectingState); transitionTo(mDetectingState); } } Loading Loading @@ -363,11 +382,28 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl private final MagnificationGesturesObserver mGesturesObserver; private final MagnificationGesturesObserver mGesturesObserver; DetectingState(Context context) { /** mGesturesObserver = new MagnificationGesturesObserver(this, new SimpleSwipe(context), * {@code true} if this detector should detect and respond to triple-tap new MultiTap(context, 1, MagnificationGestureMatcher.GESTURE_SINGLE_TAP, null), * gestures for engaging and disengaging magnification, new MultiTapAndHold(context, 1, * {@code false} if it should ignore such gestures MagnificationGestureMatcher.GESTURE_SINGLE_TAP_AND_HOLD, null), */ private final boolean mDetectTripleTap; DetectingState(Context context, boolean detectTripleTap) { mDetectTripleTap = detectTripleTap; final MultiTap multiTap = new MultiTap(context, mDetectTripleTap ? 3 : 1, mDetectTripleTap ? MagnificationGestureMatcher.GESTURE_TRIPLE_TAP : MagnificationGestureMatcher.GESTURE_SINGLE_TAP, null); final MultiTapAndHold multiTapAndHold = new MultiTapAndHold(context, mDetectTripleTap ? 3 : 1, mDetectTripleTap ? MagnificationGestureMatcher.GESTURE_TRIPLE_TAP_AND_HOLD : MagnificationGestureMatcher.GESTURE_SINGLE_TAP_AND_HOLD, null); mGesturesObserver = new MagnificationGesturesObserver(this, new SimpleSwipe(context), multiTap, multiTapAndHold, new TwoFingersDown(context)); new TwoFingersDown(context)); } } Loading Loading @@ -395,7 +431,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl @Override @Override public boolean shouldStopDetection(MotionEvent motionEvent) { public boolean shouldStopDetection(MotionEvent motionEvent) { return !mWindowMagnificationMgr.isWindowMagnifierEnabled(mDisplayId); return !mWindowMagnificationMgr.isWindowMagnifierEnabled(mDisplayId) && !mDetectTripleTap; } } @Override @Override Loading @@ -412,6 +449,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl if (gestureId == MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN if (gestureId == MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN && mWindowMagnificationMgr.pointersInWindow(mDisplayId, motionEvent) > 0) { && mWindowMagnificationMgr.pointersInWindow(mDisplayId, motionEvent) > 0) { transitionTo(mObservePanningScalingState); transitionTo(mObservePanningScalingState); } else if (gestureId == MagnificationGestureMatcher.GESTURE_TRIPLE_TAP) { onTripleTap(motionEvent); } else { } else { mMotionEventDispatcherDelegate.sendDelayedMotionEvents(delayedEventQueue, mMotionEventDispatcherDelegate.sendDelayedMotionEvents(delayedEventQueue, lastDownEventTime); lastDownEventTime); Loading services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java +50 −17 Original line number Original line Diff line number Diff line Loading @@ -56,10 +56,11 @@ public class WindowMagnificationGestureHandlerTest { public static final int STATE_IDLE = 1; public static final int STATE_IDLE = 1; public static final int STATE_SHOW_MAGNIFIER = 2; public static final int STATE_SHOW_MAGNIFIER = 2; public static final int STATE_TWO_FINGERS_DOWN = 3; public static final int STATE_TWO_FINGERS_DOWN = 3; public static final int STATE_SHOW_MAGNIFIER_TRIPLE_TAP = 4; //TODO: Test it after can injecting Handler to GestureMatcher is available. //TODO: Test it after can injecting Handler to GestureMatcher is available. public static final int FIRST_STATE = STATE_IDLE; public static final int FIRST_STATE = STATE_IDLE; public static final int LAST_STATE = STATE_TWO_FINGERS_DOWN; public static final int LAST_STATE = STATE_SHOW_MAGNIFIER_TRIPLE_TAP; // Co-prime x and y, to potentially catch x-y-swapped errors // Co-prime x and y, to potentially catch x-y-swapped errors public static final float DEFAULT_X = 301; public static final float DEFAULT_X = 301; Loading @@ -79,7 +80,8 @@ public class WindowMagnificationGestureHandlerTest { mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0); mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0); mMockConnection = new MockWindowMagnificationConnection(); mMockConnection = new MockWindowMagnificationConnection(); mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler( mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler( mContext, mWindowMagnificationManager, mock(ScaleChangedListener.class), DISPLAY_0); mContext, mWindowMagnificationManager, mock(ScaleChangedListener.class), /** detectTripleTap= */true, /** detectShortcutTrigger= */true, DISPLAY_0); mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); mMockConnection.getConnectionCallback().onWindowMagnifierBoundsChanged(DISPLAY_0, mMockConnection.getConnectionCallback().onWindowMagnifierBoundsChanged(DISPLAY_0, DEFAULT_WINDOW_FRAME); DEFAULT_WINDOW_FRAME); Loading Loading @@ -108,7 +110,9 @@ public class WindowMagnificationGestureHandlerTest { * <br> IDLE -> SHOW_MAGNIFIER [label="a11y\nbtn"] * <br> IDLE -> SHOW_MAGNIFIER [label="a11y\nbtn"] * <br> SHOW_MAGNIFIER -> TWO_FINGER_DOWN [label="2hold"] * <br> SHOW_MAGNIFIER -> TWO_FINGER_DOWN [label="2hold"] * <br> TWO_FINGER_DOWN -> SHOW_MAGNIFIER [label="release"] * <br> TWO_FINGER_DOWN -> SHOW_MAGNIFIER [label="release"] * <br> SHOW_MAGNIFIER -> IDLE [label="a11y\nbtn"]* * <br> SHOW_MAGNIFIER -> IDLE [label="a11y\nbtn"] * <br> IDLE -> SHOW_MAGNIFIER_TRIPLE_TAP [label="3tap"] * <br> SHOW_MAGNIFIER_TRIPLE_TAP -> IDLE [label="3tap"] * </p> * </p> * This navigates between states using "canonical" paths, specified in * This navigates between states using "canonical" paths, specified in * {@link #goFromStateIdleTo} (for traversing away from {@link #STATE_IDLE}) and * {@link #goFromStateIdleTo} (for traversing away from {@link #STATE_IDLE}) and Loading Loading @@ -167,20 +171,24 @@ public class WindowMagnificationGestureHandlerTest { check(!isWindowMagnifierEnabled(DISPLAY_0), state); check(!isWindowMagnifierEnabled(DISPLAY_0), state); check(mWindowMagnificationGestureHandler.mCurrentState check(mWindowMagnificationGestureHandler.mCurrentState == mWindowMagnificationGestureHandler.mDetectingState, state); == mWindowMagnificationGestureHandler.mDetectingState, state); } break; } case STATE_SHOW_MAGNIFIER: { break; case STATE_SHOW_MAGNIFIER: case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: { check(isWindowMagnifierEnabled(DISPLAY_0), state); check(isWindowMagnifierEnabled(DISPLAY_0), state); check(mWindowMagnificationGestureHandler.mCurrentState check(mWindowMagnificationGestureHandler.mCurrentState == mWindowMagnificationGestureHandler.mDetectingState, state); == mWindowMagnificationGestureHandler.mDetectingState, state); } break; } break; case STATE_TWO_FINGERS_DOWN: { case STATE_TWO_FINGERS_DOWN: { check(isWindowMagnifierEnabled(DISPLAY_0), state); check(isWindowMagnifierEnabled(DISPLAY_0), state); check(mWindowMagnificationGestureHandler.mCurrentState check(mWindowMagnificationGestureHandler.mCurrentState == mWindowMagnificationGestureHandler.mObservePanningScalingState, == mWindowMagnificationGestureHandler.mObservePanningScalingState, state); state); } break; } break; default: throw new IllegalArgumentException("Illegal state: " + state); default: throw new IllegalArgumentException("Illegal state: " + state); } } } } Loading @@ -192,17 +200,27 @@ public class WindowMagnificationGestureHandlerTest { switch (state) { switch (state) { case STATE_IDLE: { case STATE_IDLE: { // no op // no op } break; } break; case STATE_SHOW_MAGNIFIER: { case STATE_SHOW_MAGNIFIER: { triggerShortcut(); triggerShortcut(); } break; } break; case STATE_TWO_FINGERS_DOWN: { case STATE_TWO_FINGERS_DOWN: { goFromStateIdleTo(STATE_SHOW_MAGNIFIER); goFromStateIdleTo(STATE_SHOW_MAGNIFIER); send(downEvent()); send(downEvent()); //Second finger is outside the window. //Second finger is outside the window. send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_WINDOW_FRAME.right + 10, send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_WINDOW_FRAME.right + 10, DEFAULT_WINDOW_FRAME.bottom + 10)); DEFAULT_WINDOW_FRAME.bottom + 10)); } break; } break; case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: { // Perform triple tap gesture tap(); tap(); tap(); } break; default: default: throw new IllegalArgumentException("Illegal state: " + state); throw new IllegalArgumentException("Illegal state: " + state); } } Loading @@ -218,15 +236,25 @@ public class WindowMagnificationGestureHandlerTest { switch (state) { switch (state) { case STATE_IDLE: { case STATE_IDLE: { // no op // no op } break; } break; case STATE_SHOW_MAGNIFIER: { case STATE_SHOW_MAGNIFIER: { mWindowMagnificationManager.disableWindowMagnifier(DISPLAY_0, false); mWindowMagnificationManager.disableWindowMagnifier(DISPLAY_0, false); } break; } break; case STATE_TWO_FINGERS_DOWN: { case STATE_TWO_FINGERS_DOWN: { send(upEvent()); send(upEvent()); returnToNormalFrom(STATE_SHOW_MAGNIFIER); returnToNormalFrom(STATE_SHOW_MAGNIFIER); } break; } default: throw new IllegalArgumentException("Illegal state: " + state); break; case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: { tap(); tap(); tap(); } break; default: throw new IllegalArgumentException("Illegal state: " + state); } } } } Loading Loading @@ -270,6 +298,11 @@ public class WindowMagnificationGestureHandlerTest { return TouchEventGenerator.upEvent(DISPLAY_0, x, y); return TouchEventGenerator.upEvent(DISPLAY_0, x, y); } } private void tap() { send(downEvent()); send(upEvent()); } private MotionEvent pointerEvent(int action, float x, float y) { private MotionEvent pointerEvent(int action, float x, float y) { final MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords(); final MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords(); defPointerCoords.x = DEFAULT_X; defPointerCoords.x = DEFAULT_X; Loading Loading
services/accessibility/java/com/android/server/accessibility/AccessibilityInputFilter.java +3 −2 Original line number Original line Diff line number Diff line Loading @@ -533,9 +533,10 @@ class AccessibilityInputFilter extends InputFilter implements EventStreamTransfo & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0; & FLAG_FEATURE_TRIGGERED_SCREEN_MAGNIFIER) != 0; MagnificationGestureHandler magnificationGestureHandler; MagnificationGestureHandler magnificationGestureHandler; if (mAms.getMagnificationMode(displayId) if (mAms.getMagnificationMode(displayId) == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW && triggerable) { == Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW) { magnificationGestureHandler = new WindowMagnificationGestureHandler(displayContext, magnificationGestureHandler = new WindowMagnificationGestureHandler(displayContext, mAms.getWindowMagnificationMgr(), mAms::onMagnificationScaleChanged, displayId); mAms.getWindowMagnificationMgr(), mAms::onMagnificationScaleChanged, detectControlGestures, triggerable, displayId); } else { } else { magnificationGestureHandler = new FullScreenMagnificationGestureHandler(displayContext, magnificationGestureHandler = new FullScreenMagnificationGestureHandler(displayContext, mAms.getMagnificationController(), mAms::onMagnificationScaleChanged, mAms.getMagnificationController(), mAms::onMagnificationScaleChanged, Loading
services/accessibility/java/com/android/server/accessibility/magnification/MagnificationGestureMatcher.java +6 −0 Original line number Original line Diff line number Diff line Loading @@ -37,6 +37,8 @@ class MagnificationGestureMatcher { public static final int GESTURE_SWIPE = GESTURE_BASE + 2; public static final int GESTURE_SWIPE = GESTURE_BASE + 2; public static final int GESTURE_SINGLE_TAP = GESTURE_BASE + 3; public static final int GESTURE_SINGLE_TAP = GESTURE_BASE + 3; public static final int GESTURE_SINGLE_TAP_AND_HOLD = GESTURE_BASE + 4; public static final int GESTURE_SINGLE_TAP_AND_HOLD = GESTURE_BASE + 4; public static final int GESTURE_TRIPLE_TAP = GESTURE_BASE + 5; public static final int GESTURE_TRIPLE_TAP_AND_HOLD = GESTURE_BASE + 6; @IntDef(prefix = {"GESTURE_MAGNIFICATION_"}, value = { @IntDef(prefix = {"GESTURE_MAGNIFICATION_"}, value = { GESTURE_TWO_FINGER_DOWN, GESTURE_TWO_FINGER_DOWN, Loading @@ -61,6 +63,10 @@ class MagnificationGestureMatcher { return "GESTURE_SINGLE_TAP"; return "GESTURE_SINGLE_TAP"; case GESTURE_SINGLE_TAP_AND_HOLD: case GESTURE_SINGLE_TAP_AND_HOLD: return "GESTURE_SINGLE_TAP_AND_HOLD"; return "GESTURE_SINGLE_TAP_AND_HOLD"; case GESTURE_TRIPLE_TAP: return "GESTURE_TRIPLE_TAP"; case GESTURE_TRIPLE_TAP_AND_HOLD: return "GESTURE_TRIPLE_TAP_AND_HOLD"; } } return "none"; return "none"; } } Loading
services/accessibility/java/com/android/server/accessibility/magnification/WindowMagnificationGestureHandler.java +56 −17 Original line number Original line Diff line number Diff line Loading @@ -44,9 +44,11 @@ import java.util.Queue; * This class handles window magnification in response to touch events and shortcut. * This class handles window magnification in response to touch events and shortcut. * * * The behavior is as follows: * The behavior is as follows: * * <ol> * <ol> * <li> Window magnification can be "toggled" by tapping shortcut. It is triggered via * <li> 1. Toggle Window magnification by triple-tap gesture shortcut. It is triggered via * {@link #onTripleTap(MotionEvent)}. * <li> 2. Toggle Window magnification by tapping shortcut. It is triggered via * {@link #notifyShortcutTriggered()}. * {@link #notifyShortcutTriggered()}. * <li> When the window magnifier is visible, pinching with any number of additional fingers * <li> When the window magnifier is visible, pinching with any number of additional fingers * would adjust the magnification scale .<strong>Note</strong> that this operation is valid only * would adjust the magnification scale .<strong>Note</strong> that this operation is valid only Loading @@ -72,7 +74,6 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl private static final float MAX_SCALE = WindowMagnificationManager.MAX_SCALE; private static final float MAX_SCALE = WindowMagnificationManager.MAX_SCALE; private final WindowMagnificationManager mWindowMagnificationMgr; private final WindowMagnificationManager mWindowMagnificationMgr; @VisibleForTesting @VisibleForTesting final DelegatingState mDelegatingState; final DelegatingState mDelegatingState; @VisibleForTesting @VisibleForTesting Loading @@ -85,6 +86,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl @VisibleForTesting @VisibleForTesting State mPreviousState; State mPreviousState; final boolean mDetectShortcutTrigger; private MotionEventDispatcherDelegate mMotionEventDispatcherDelegate; private MotionEventDispatcherDelegate mMotionEventDispatcherDelegate; private final int mDisplayId; private final int mDisplayId; Loading @@ -97,7 +100,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl */ */ public WindowMagnificationGestureHandler(Context context, public WindowMagnificationGestureHandler(Context context, WindowMagnificationManager windowMagnificationMgr, WindowMagnificationManager windowMagnificationMgr, MagnificationGestureHandler.ScaleChangedListener listener, int displayId) { MagnificationGestureHandler.ScaleChangedListener listener, boolean detectTripleTap, boolean detectShortcutTrigger, int displayId) { super(listener); super(listener); if (DEBUG_ALL) { if (DEBUG_ALL) { Slog.i(LOG_TAG, Slog.i(LOG_TAG, Loading @@ -105,12 +109,13 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl } } mWindowMagnificationMgr = windowMagnificationMgr; mWindowMagnificationMgr = windowMagnificationMgr; mDetectShortcutTrigger = detectShortcutTrigger; mDisplayId = displayId; mDisplayId = displayId; mMotionEventDispatcherDelegate = new MotionEventDispatcherDelegate(context, mMotionEventDispatcherDelegate = new MotionEventDispatcherDelegate(context, (event, rawEvent, policyFlags) -> super.onMotionEvent( (event, rawEvent, policyFlags) -> super.onMotionEvent( event, rawEvent, policyFlags)); event, rawEvent, policyFlags)); mDelegatingState = new DelegatingState(mMotionEventDispatcherDelegate); mDelegatingState = new DelegatingState(mMotionEventDispatcherDelegate); mDetectingState = new DetectingState(context); mDetectingState = new DetectingState(context, detectTripleTap); mObservePanningScalingState = new PanningScalingGestureState( mObservePanningScalingState = new PanningScalingGestureState( new PanningScalingHandler(context, MAX_SCALE, MIN_SCALE, true, new PanningScalingHandler(context, MAX_SCALE, MIN_SCALE, true, new PanningScalingHandler.MagnificationDelegate() { new PanningScalingHandler.MagnificationDelegate() { Loading Loading @@ -176,11 +181,10 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl if (DEBUG_ALL) { if (DEBUG_ALL) { Slog.i(LOG_TAG, "notifyShortcutTriggered():"); Slog.i(LOG_TAG, "notifyShortcutTriggered():"); } } if (mWindowMagnificationMgr.isWindowMagnifierEnabled(mDisplayId)) { if (!mDetectShortcutTrigger) { disableWindowMagnifier(); return; } else { enableWindowMagnifier(Float.NaN, Float.NaN); } } toggleMagnification(Float.NaN, Float.NaN); } } @Override @Override Loading @@ -206,6 +210,21 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl mWindowMagnificationMgr.disableWindowMagnifier(mDisplayId, false); mWindowMagnificationMgr.disableWindowMagnifier(mDisplayId, false); } } private void toggleMagnification(float centerX, float centerY) { if (mWindowMagnificationMgr.isWindowMagnifierEnabled(mDisplayId)) { disableWindowMagnifier(); } else { enableWindowMagnifier(centerX, centerY); } } private void onTripleTap(MotionEvent up) { if (DEBUG_DETECTING) { Slog.i(LOG_TAG, "onTripleTap()"); } toggleMagnification(up.getX(), up.getY()); } void resetToDetectState() { void resetToDetectState() { transitionTo(mDetectingState); transitionTo(mDetectingState); } } Loading Loading @@ -363,11 +382,28 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl private final MagnificationGesturesObserver mGesturesObserver; private final MagnificationGesturesObserver mGesturesObserver; DetectingState(Context context) { /** mGesturesObserver = new MagnificationGesturesObserver(this, new SimpleSwipe(context), * {@code true} if this detector should detect and respond to triple-tap new MultiTap(context, 1, MagnificationGestureMatcher.GESTURE_SINGLE_TAP, null), * gestures for engaging and disengaging magnification, new MultiTapAndHold(context, 1, * {@code false} if it should ignore such gestures MagnificationGestureMatcher.GESTURE_SINGLE_TAP_AND_HOLD, null), */ private final boolean mDetectTripleTap; DetectingState(Context context, boolean detectTripleTap) { mDetectTripleTap = detectTripleTap; final MultiTap multiTap = new MultiTap(context, mDetectTripleTap ? 3 : 1, mDetectTripleTap ? MagnificationGestureMatcher.GESTURE_TRIPLE_TAP : MagnificationGestureMatcher.GESTURE_SINGLE_TAP, null); final MultiTapAndHold multiTapAndHold = new MultiTapAndHold(context, mDetectTripleTap ? 3 : 1, mDetectTripleTap ? MagnificationGestureMatcher.GESTURE_TRIPLE_TAP_AND_HOLD : MagnificationGestureMatcher.GESTURE_SINGLE_TAP_AND_HOLD, null); mGesturesObserver = new MagnificationGesturesObserver(this, new SimpleSwipe(context), multiTap, multiTapAndHold, new TwoFingersDown(context)); new TwoFingersDown(context)); } } Loading Loading @@ -395,7 +431,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl @Override @Override public boolean shouldStopDetection(MotionEvent motionEvent) { public boolean shouldStopDetection(MotionEvent motionEvent) { return !mWindowMagnificationMgr.isWindowMagnifierEnabled(mDisplayId); return !mWindowMagnificationMgr.isWindowMagnifierEnabled(mDisplayId) && !mDetectTripleTap; } } @Override @Override Loading @@ -412,6 +449,8 @@ public class WindowMagnificationGestureHandler extends MagnificationGestureHandl if (gestureId == MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN if (gestureId == MagnificationGestureMatcher.GESTURE_TWO_FINGER_DOWN && mWindowMagnificationMgr.pointersInWindow(mDisplayId, motionEvent) > 0) { && mWindowMagnificationMgr.pointersInWindow(mDisplayId, motionEvent) > 0) { transitionTo(mObservePanningScalingState); transitionTo(mObservePanningScalingState); } else if (gestureId == MagnificationGestureMatcher.GESTURE_TRIPLE_TAP) { onTripleTap(motionEvent); } else { } else { mMotionEventDispatcherDelegate.sendDelayedMotionEvents(delayedEventQueue, mMotionEventDispatcherDelegate.sendDelayedMotionEvents(delayedEventQueue, lastDownEventTime); lastDownEventTime); Loading
services/tests/servicestests/src/com/android/server/accessibility/magnification/WindowMagnificationGestureHandlerTest.java +50 −17 Original line number Original line Diff line number Diff line Loading @@ -56,10 +56,11 @@ public class WindowMagnificationGestureHandlerTest { public static final int STATE_IDLE = 1; public static final int STATE_IDLE = 1; public static final int STATE_SHOW_MAGNIFIER = 2; public static final int STATE_SHOW_MAGNIFIER = 2; public static final int STATE_TWO_FINGERS_DOWN = 3; public static final int STATE_TWO_FINGERS_DOWN = 3; public static final int STATE_SHOW_MAGNIFIER_TRIPLE_TAP = 4; //TODO: Test it after can injecting Handler to GestureMatcher is available. //TODO: Test it after can injecting Handler to GestureMatcher is available. public static final int FIRST_STATE = STATE_IDLE; public static final int FIRST_STATE = STATE_IDLE; public static final int LAST_STATE = STATE_TWO_FINGERS_DOWN; public static final int LAST_STATE = STATE_SHOW_MAGNIFIER_TRIPLE_TAP; // Co-prime x and y, to potentially catch x-y-swapped errors // Co-prime x and y, to potentially catch x-y-swapped errors public static final float DEFAULT_X = 301; public static final float DEFAULT_X = 301; Loading @@ -79,7 +80,8 @@ public class WindowMagnificationGestureHandlerTest { mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0); mWindowMagnificationManager = new WindowMagnificationManager(mContext, 0); mMockConnection = new MockWindowMagnificationConnection(); mMockConnection = new MockWindowMagnificationConnection(); mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler( mWindowMagnificationGestureHandler = new WindowMagnificationGestureHandler( mContext, mWindowMagnificationManager, mock(ScaleChangedListener.class), DISPLAY_0); mContext, mWindowMagnificationManager, mock(ScaleChangedListener.class), /** detectTripleTap= */true, /** detectShortcutTrigger= */true, DISPLAY_0); mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); mWindowMagnificationManager.setConnection(mMockConnection.getConnection()); mMockConnection.getConnectionCallback().onWindowMagnifierBoundsChanged(DISPLAY_0, mMockConnection.getConnectionCallback().onWindowMagnifierBoundsChanged(DISPLAY_0, DEFAULT_WINDOW_FRAME); DEFAULT_WINDOW_FRAME); Loading Loading @@ -108,7 +110,9 @@ public class WindowMagnificationGestureHandlerTest { * <br> IDLE -> SHOW_MAGNIFIER [label="a11y\nbtn"] * <br> IDLE -> SHOW_MAGNIFIER [label="a11y\nbtn"] * <br> SHOW_MAGNIFIER -> TWO_FINGER_DOWN [label="2hold"] * <br> SHOW_MAGNIFIER -> TWO_FINGER_DOWN [label="2hold"] * <br> TWO_FINGER_DOWN -> SHOW_MAGNIFIER [label="release"] * <br> TWO_FINGER_DOWN -> SHOW_MAGNIFIER [label="release"] * <br> SHOW_MAGNIFIER -> IDLE [label="a11y\nbtn"]* * <br> SHOW_MAGNIFIER -> IDLE [label="a11y\nbtn"] * <br> IDLE -> SHOW_MAGNIFIER_TRIPLE_TAP [label="3tap"] * <br> SHOW_MAGNIFIER_TRIPLE_TAP -> IDLE [label="3tap"] * </p> * </p> * This navigates between states using "canonical" paths, specified in * This navigates between states using "canonical" paths, specified in * {@link #goFromStateIdleTo} (for traversing away from {@link #STATE_IDLE}) and * {@link #goFromStateIdleTo} (for traversing away from {@link #STATE_IDLE}) and Loading Loading @@ -167,20 +171,24 @@ public class WindowMagnificationGestureHandlerTest { check(!isWindowMagnifierEnabled(DISPLAY_0), state); check(!isWindowMagnifierEnabled(DISPLAY_0), state); check(mWindowMagnificationGestureHandler.mCurrentState check(mWindowMagnificationGestureHandler.mCurrentState == mWindowMagnificationGestureHandler.mDetectingState, state); == mWindowMagnificationGestureHandler.mDetectingState, state); } break; } case STATE_SHOW_MAGNIFIER: { break; case STATE_SHOW_MAGNIFIER: case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: { check(isWindowMagnifierEnabled(DISPLAY_0), state); check(isWindowMagnifierEnabled(DISPLAY_0), state); check(mWindowMagnificationGestureHandler.mCurrentState check(mWindowMagnificationGestureHandler.mCurrentState == mWindowMagnificationGestureHandler.mDetectingState, state); == mWindowMagnificationGestureHandler.mDetectingState, state); } break; } break; case STATE_TWO_FINGERS_DOWN: { case STATE_TWO_FINGERS_DOWN: { check(isWindowMagnifierEnabled(DISPLAY_0), state); check(isWindowMagnifierEnabled(DISPLAY_0), state); check(mWindowMagnificationGestureHandler.mCurrentState check(mWindowMagnificationGestureHandler.mCurrentState == mWindowMagnificationGestureHandler.mObservePanningScalingState, == mWindowMagnificationGestureHandler.mObservePanningScalingState, state); state); } break; } break; default: throw new IllegalArgumentException("Illegal state: " + state); default: throw new IllegalArgumentException("Illegal state: " + state); } } } } Loading @@ -192,17 +200,27 @@ public class WindowMagnificationGestureHandlerTest { switch (state) { switch (state) { case STATE_IDLE: { case STATE_IDLE: { // no op // no op } break; } break; case STATE_SHOW_MAGNIFIER: { case STATE_SHOW_MAGNIFIER: { triggerShortcut(); triggerShortcut(); } break; } break; case STATE_TWO_FINGERS_DOWN: { case STATE_TWO_FINGERS_DOWN: { goFromStateIdleTo(STATE_SHOW_MAGNIFIER); goFromStateIdleTo(STATE_SHOW_MAGNIFIER); send(downEvent()); send(downEvent()); //Second finger is outside the window. //Second finger is outside the window. send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_WINDOW_FRAME.right + 10, send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_WINDOW_FRAME.right + 10, DEFAULT_WINDOW_FRAME.bottom + 10)); DEFAULT_WINDOW_FRAME.bottom + 10)); } break; } break; case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: { // Perform triple tap gesture tap(); tap(); tap(); } break; default: default: throw new IllegalArgumentException("Illegal state: " + state); throw new IllegalArgumentException("Illegal state: " + state); } } Loading @@ -218,15 +236,25 @@ public class WindowMagnificationGestureHandlerTest { switch (state) { switch (state) { case STATE_IDLE: { case STATE_IDLE: { // no op // no op } break; } break; case STATE_SHOW_MAGNIFIER: { case STATE_SHOW_MAGNIFIER: { mWindowMagnificationManager.disableWindowMagnifier(DISPLAY_0, false); mWindowMagnificationManager.disableWindowMagnifier(DISPLAY_0, false); } break; } break; case STATE_TWO_FINGERS_DOWN: { case STATE_TWO_FINGERS_DOWN: { send(upEvent()); send(upEvent()); returnToNormalFrom(STATE_SHOW_MAGNIFIER); returnToNormalFrom(STATE_SHOW_MAGNIFIER); } break; } default: throw new IllegalArgumentException("Illegal state: " + state); break; case STATE_SHOW_MAGNIFIER_TRIPLE_TAP: { tap(); tap(); tap(); } break; default: throw new IllegalArgumentException("Illegal state: " + state); } } } } Loading Loading @@ -270,6 +298,11 @@ public class WindowMagnificationGestureHandlerTest { return TouchEventGenerator.upEvent(DISPLAY_0, x, y); return TouchEventGenerator.upEvent(DISPLAY_0, x, y); } } private void tap() { send(downEvent()); send(upEvent()); } private MotionEvent pointerEvent(int action, float x, float y) { private MotionEvent pointerEvent(int action, float x, float y) { final MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords(); final MotionEvent.PointerCoords defPointerCoords = new MotionEvent.PointerCoords(); defPointerCoords.x = DEFAULT_X; defPointerCoords.x = DEFAULT_X; Loading