Merge "fix(MultiFingerMultiTap): Delete lots of duplicated code" into main
diff --git a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
index 5c6f99a..aa57e0b 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -305,12 +305,8 @@
}
mDelegatingState = new DelegatingState();
- mDetectingState = Flags.enableMagnificationMultipleFingerMultipleTapGesture()
- ? new DetectingStateWithMultiFinger(context)
- : new DetectingState(context);
- mViewportDraggingState = Flags.enableMagnificationMultipleFingerMultipleTapGesture()
- ? new ViewportDraggingStateWithMultiFinger()
- : new ViewportDraggingState();
+ mDetectingState = new DetectingState(context);
+ mViewportDraggingState = new ViewportDraggingState();
mPanningScalingState = new PanningScalingState(context);
mSinglePanningState = new SinglePanningState(context);
mFullScreenMagnificationVibrationHelper = fullScreenMagnificationVibrationHelper;
@@ -701,62 +697,6 @@
}
}
- final class ViewportDraggingStateWithMultiFinger extends ViewportDraggingState {
- // LINT.IfChange(viewport_dragging_state_with_multi_finger)
- @Override
- public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags)
- throws GestureException {
- final int action = event.getActionMasked();
- switch (action) {
- case ACTION_POINTER_DOWN: {
- clearAndTransitToPanningScalingState();
- }
- break;
- case ACTION_MOVE: {
- if (event.getPointerCount() > 2) {
- throw new GestureException("Should have one pointer down.");
- }
- final float eventX = event.getX();
- final float eventY = event.getY();
- if (mFullScreenMagnificationController.magnificationRegionContains(
- mDisplayId, eventX, eventY)) {
- mFullScreenMagnificationController.setCenter(mDisplayId, eventX, eventY,
- /* animate */ mLastMoveOutsideMagnifiedRegion,
- AccessibilityManagerService.MAGNIFICATION_GESTURE_HANDLER_ID);
- mLastMoveOutsideMagnifiedRegion = false;
- } else {
- mLastMoveOutsideMagnifiedRegion = true;
- }
- }
- break;
-
- case ACTION_UP:
- case ACTION_CANCEL: {
- // If mScaleToRecoverAfterDraggingEnd >= 1.0, the dragging state is triggered
- // by zoom in temporary, and the magnifier needs to recover to original scale
- // after exiting dragging state.
- // Otherwise, the magnifier should be disabled.
- if (mScaleToRecoverAfterDraggingEnd >= 1.0f) {
- zoomToScale(mScaleToRecoverAfterDraggingEnd, event.getX(),
- event.getY());
- } else {
- zoomOff();
- }
- clear();
- mScaleToRecoverAfterDraggingEnd = Float.NaN;
- transitionTo(mDetectingState);
- }
- break;
-
- case ACTION_DOWN: {
- throw new GestureException(
- "Unexpected event type: " + MotionEvent.actionToString(action));
- }
- }
- }
- // LINT.ThenChange(:viewport_dragging_state)
- }
-
/**
* This class handles motion events when the event dispatcher has
* determined that the user is performing a single-finger drag of the
@@ -777,7 +717,6 @@
protected boolean mLastMoveOutsideMagnifiedRegion;
- // LINT.IfChange(viewport_dragging_state)
@Override
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags)
throws GestureException {
@@ -788,7 +727,11 @@
}
break;
case ACTION_MOVE: {
- if (event.getPointerCount() != 1) {
+ if (Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
+ if (event.getPointerCount() > 2) {
+ throw new GestureException("Should have at most two pointers down.");
+ }
+ } else if (event.getPointerCount() != 1) {
throw new GestureException("Should have one pointer down.");
}
final float eventX = event.getX();
@@ -823,14 +766,20 @@
}
break;
- case ACTION_DOWN:
case ACTION_POINTER_UP: {
+ if (!Flags.enableMagnificationMultipleFingerMultipleTapGesture()) {
+ throw new GestureException(
+ "Unexpected event type: " + MotionEvent.actionToString(action));
+ }
+ }
+ break;
+
+ case ACTION_DOWN: {
throw new GestureException(
"Unexpected event type: " + MotionEvent.actionToString(action));
}
}
}
- // LINT.ThenChange(:viewport_dragging_state_with_multi_finger)
private boolean isAlwaysOnMagnificationEnabled() {
return mFullScreenMagnificationController.isAlwaysOnMagnificationEnabled();
@@ -916,270 +865,31 @@
}
}
- final class DetectingStateWithMultiFinger extends DetectingState {
- private static final int TWO_FINGER_GESTURE_MAX_TAPS = 2;
- // A flag set to true when two fingers have touched down.
- // Used to indicate what next finger action should be.
- private boolean mIsTwoFingerCountReached = false;
- // A tap counts when two fingers are down and up once.
- private int mCompletedTapCount = 0;
- DetectingStateWithMultiFinger(Context context) {
- super(context);
- }
-
- // LINT.IfChange(detecting_state_with_multi_finger)
- @Override
- public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
- cacheDelayedMotionEvent(event, rawEvent, policyFlags);
- switch (event.getActionMasked()) {
- case MotionEvent.ACTION_DOWN: {
- mLastDetectingDownEventTime = event.getDownTime();
- mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
-
- mFirstPointerDownLocation.set(event.getX(), event.getY());
-
- if (!mFullScreenMagnificationController.magnificationRegionContains(
- mDisplayId, event.getX(), event.getY())) {
-
- transitionToDelegatingStateAndClear();
-
- } else if (isMultiTapTriggered(2 /* taps */)) {
-
- // 3tap and hold
- afterLongTapTimeoutTransitionToDraggingState(event);
-
- } else if (isTapOutOfDistanceSlop()) {
-
- transitionToDelegatingStateAndClear();
-
- } else if (mDetectSingleFingerTripleTap
- || mDetectTwoFingerTripleTap
- // If activated, delay an ACTION_DOWN for mMultiTapMaxDelay
- // to ensure reachability of
- // STATE_PANNING_SCALING(triggerable with ACTION_POINTER_DOWN)
- || isActivated()) {
-
- afterMultiTapTimeoutTransitionToDelegatingState();
-
- } else {
-
- // Delegate pending events without delay
- transitionToDelegatingStateAndClear();
- }
- }
- break;
- case ACTION_POINTER_DOWN: {
- mIsTwoFingerCountReached = mDetectTwoFingerTripleTap
- && event.getPointerCount() == 2;
- mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
-
- if (event.getPointerCount() == 2) {
- if (isMultiFingerMultiTapTriggered(
- TWO_FINGER_GESTURE_MAX_TAPS - 1, event)) {
- // 3tap and hold
- afterLongTapTimeoutTransitionToDraggingState(event);
- } else {
- if (mDetectTwoFingerTripleTap) {
- // If mDetectTwoFingerTripleTap, delay transition to the delegating
- // state for mMultiTapMaxDelay to ensure reachability of
- // multi finger multi tap
- afterMultiTapTimeoutTransitionToDelegatingState();
- }
-
- if (isActivated()) {
- // If activated, delay transition to the panning scaling
- // state for tap timeout to ensure reachability of
- // multi finger multi tap
- storePointerDownLocation(mSecondPointerDownLocation, event);
- mHandler.sendEmptyMessageDelayed(
- MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE,
- ViewConfiguration.getTapTimeout());
- }
- }
- } else {
- transitionToDelegatingStateAndClear();
- }
- }
- break;
- case ACTION_POINTER_UP: {
- // If it is a two-finger gesture, do not transition to the delegating state
- // to ensure the reachability of
- // the two-finger triple tap (triggerable with ACTION_MOVE and ACTION_UP)
- if (!mIsTwoFingerCountReached) {
- transitionToDelegatingStateAndClear();
- }
- }
- break;
- case ACTION_MOVE: {
- if (isFingerDown()
- && distance(mLastDown, /* move */ event) > mSwipeMinDistance) {
- // Swipe detected - transition immediately
-
- // For convenience, viewport dragging takes precedence
- // over insta-delegating on 3tap&swipe
- // (which is a rare combo to be used aside from magnification)
- if (isMultiTapTriggered(2 /* taps */) && event.getPointerCount() == 1) {
- transitionToViewportDraggingStateAndClear(event);
- } else if (isMultiFingerMultiTapTriggered(
- TWO_FINGER_GESTURE_MAX_TAPS - 1, event)
- && event.getPointerCount() == 2) {
- transitionToViewportDraggingStateAndClear(event);
- } else if (isActivated() && event.getPointerCount() == 2) {
- if (mOverscrollHandler != null
- && overscrollState(event, mFirstPointerDownLocation)
- == OVERSCROLL_VERTICAL_EDGE) {
- transitionToDelegatingStateAndClear();
- } else {
- //Primary pointer is swiping, so transit to PanningScalingState
- transitToPanningScalingStateAndClear();
- }
- } else if (mOneFingerPanningSettingsProvider.isOneFingerPanningEnabled()
- && isActivated()
- && event.getPointerCount() == 1) {
- if (mOverscrollHandler != null
- && overscrollState(event, mFirstPointerDownLocation)
- == OVERSCROLL_VERTICAL_EDGE) {
- transitionToDelegatingStateAndClear();
- } else if (overscrollState(event, mFirstPointerDownLocation)
- != OVERSCROLL_NONE) {
- transitionToDelegatingStateAndClear();
- } else {
- transitToSinglePanningStateAndClear();
- }
- } else if (!mIsTwoFingerCountReached) {
- // If it is a two-finger gesture, do not transition to the
- // delegating state to ensure the reachability of
- // the two-finger triple tap (triggerable with ACTION_UP)
- transitionToDelegatingStateAndClear();
- }
- } else if (isActivated() && pointerDownValid(mSecondPointerDownLocation)
- && distanceClosestPointerToPoint(
- mSecondPointerDownLocation, /* move */ event) > mSwipeMinDistance) {
- // Second pointer is swiping, so transit to PanningScalingState
- // Delay an ACTION_MOVE for tap timeout to ensure it is not trigger from
- // multi finger multi tap
- storePointerDownLocation(mSecondPointerDownLocation, event);
- mHandler.sendEmptyMessageDelayed(
- MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE,
- ViewConfiguration.getTapTimeout());
- }
- }
- break;
- case ACTION_UP: {
-
- mHandler.removeMessages(MESSAGE_ON_TRIPLE_TAP_AND_HOLD);
- mHandler.removeMessages(MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE);
-
- if (!mFullScreenMagnificationController.magnificationRegionContains(
- mDisplayId, event.getX(), event.getY())) {
- transitionToDelegatingStateAndClear();
-
- } else if (isMultiFingerMultiTapTriggered(TWO_FINGER_GESTURE_MAX_TAPS, event)) {
- // Placing multiple fingers before a single finger, because achieving a
- // multi finger multi tap also means achieving a single finger triple tap
- onTripleTap(event);
-
- } else if (isMultiTapTriggered(3 /* taps */)) {
- onTripleTap(/* up */ event);
-
- } else if (
- // Possible to be false on: 3tap&drag -> scale -> PTR_UP -> UP
- isFingerDown()
- //TODO long tap should never happen here
- && ((timeBetween(mLastDown, mLastUp) >= mLongTapMinDelay)
- || (distance(mLastDown, mLastUp) >= mSwipeMinDistance))
- // If it is a two-finger but not reach 3 tap, do not transition to the
- // delegating state to ensure the reachability of the triple tap
- && mCompletedTapCount == 0) {
- transitionToDelegatingStateAndClear();
-
- }
- }
- break;
- }
- }
- // LINT.ThenChange(:detecting_state)
-
- @Override
- public void clear() {
- mCompletedTapCount = 0;
- setShortcutTriggered(false);
- removePendingDelayedMessages();
- clearDelayedMotionEvents();
- mFirstPointerDownLocation.set(Float.NaN, Float.NaN);
- mSecondPointerDownLocation.set(Float.NaN, Float.NaN);
- }
-
- private boolean isMultiFingerMultiTapTriggered(int targetTapCount, MotionEvent event) {
- if (event.getActionMasked() == ACTION_UP && mIsTwoFingerCountReached) {
- mCompletedTapCount++;
- mIsTwoFingerCountReached = false;
- }
-
- if (mDetectTwoFingerTripleTap && mCompletedTapCount > TWO_FINGER_GESTURE_MAX_TAPS - 1) {
- final boolean enabled = !isActivated();
- mMagnificationLogger.logMagnificationTwoFingerTripleTap(enabled);
- }
- return mDetectTwoFingerTripleTap && mCompletedTapCount == targetTapCount;
- }
-
- void transitionToDelegatingStateAndClear() {
- mCompletedTapCount = 0;
- transitionTo(mDelegatingState);
- sendDelayedMotionEvents();
- removePendingDelayedMessages();
- mFirstPointerDownLocation.set(Float.NaN, Float.NaN);
- mSecondPointerDownLocation.set(Float.NaN, Float.NaN);
- }
-
- void transitionToViewportDraggingStateAndClear(MotionEvent down) {
-
- if (DEBUG_DETECTING) Slog.i(mLogTag, "onTripleTapAndHold()");
- final boolean shortcutTriggered = mShortcutTriggered;
-
- // Only log the 3tap and hold event
- if (!shortcutTriggered) {
- final boolean enabled = !isActivated();
- if (mCompletedTapCount == TWO_FINGER_GESTURE_MAX_TAPS - 1) {
- // Two finger triple tap and hold
- mMagnificationLogger.logMagnificationTwoFingerTripleTap(enabled);
- } else {
- // Triple tap and hold also belongs to triple tap event
- mMagnificationLogger.logMagnificationTripleTap(enabled);
- }
- }
- clear();
-
- mViewportDraggingState.prepareForZoomInTemporary(shortcutTriggered);
- zoomInTemporary(down.getX(), down.getY(), shortcutTriggered);
- transitionTo(mViewportDraggingState);
- }
- }
-
/**
* This class handles motion events when the event dispatch has not yet
* determined what the user is doing. It watches for various tap events.
*/
class DetectingState implements State, Handler.Callback {
- protected static final int MESSAGE_ON_TRIPLE_TAP_AND_HOLD = 1;
- protected static final int MESSAGE_TRANSITION_TO_DELEGATING_STATE = 2;
- protected static final int MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE = 3;
+ private static final int MESSAGE_ON_TRIPLE_TAP_AND_HOLD = 1;
+ private static final int MESSAGE_TRANSITION_TO_DELEGATING_STATE = 2;
+ private static final int MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE = 3;
final int mLongTapMinDelay;
final int mSwipeMinDistance;
final int mMultiTapMaxDelay;
final int mMultiTapMaxDistance;
+ @Nullable final TwoFingerDoubleTapHandler mTwoFingerDoubleTapHandler;
- protected MotionEventInfo mDelayedEventQueue;
- protected MotionEvent mLastDown;
- protected MotionEvent mPreLastDown;
- protected MotionEvent mLastUp;
- protected MotionEvent mPreLastUp;
+ private MotionEventInfo mDelayedEventQueue;
+ private MotionEvent mLastDown;
+ private MotionEvent mPreLastDown;
+ private MotionEvent mLastUp;
+ private MotionEvent mPreLastUp;
- protected PointF mFirstPointerDownLocation = new PointF(Float.NaN, Float.NaN);
- protected PointF mSecondPointerDownLocation = new PointF(Float.NaN, Float.NaN);
- protected long mLastDetectingDownEventTime;
+ private PointF mFirstPointerDownLocation = new PointF(Float.NaN, Float.NaN);
+ private PointF mSecondPointerDownLocation = new PointF(Float.NaN, Float.NaN);
+ private long mLastDetectingDownEventTime;
@VisibleForTesting boolean mShortcutTriggered;
@@ -1191,6 +901,9 @@
MagnificationGestureMatcher.getMagnificationMultiTapTimeout(context);
mSwipeMinDistance = ViewConfiguration.get(context).getScaledTouchSlop();
mMultiTapMaxDistance = ViewConfiguration.get(context).getScaledDoubleTapSlop();
+ mTwoFingerDoubleTapHandler =
+ Flags.enableMagnificationMultipleFingerMultipleTapGesture()
+ ? new TwoFingerDoubleTapHandler() : null;
}
@Override
@@ -1218,7 +931,6 @@
return true;
}
- // LINT.IfChange(detecting_state)
@Override
public void onMotionEvent(MotionEvent event, MotionEvent rawEvent, int policyFlags) {
cacheDelayedMotionEvent(event, rawEvent, policyFlags);
@@ -1244,6 +956,7 @@
transitionToDelegatingStateAndClear();
} else if (mDetectSingleFingerTripleTap
+ || (mTwoFingerDoubleTapHandler != null && mDetectTwoFingerTripleTap)
// If activated, delay an ACTION_DOWN for mMultiTapMaxDelay
// to ensure reachability of
// STATE_PANNING_SCALING(triggerable with ACTION_POINTER_DOWN)
@@ -1259,6 +972,12 @@
}
break;
case ACTION_POINTER_DOWN: {
+ if (mTwoFingerDoubleTapHandler != null) {
+ mTwoFingerDoubleTapHandler.onPointerDown(event);
+ break;
+ }
+
+ // LINT.IfChange(action_pointer_down)
if (isActivated() && event.getPointerCount() == 2) {
storePointerDownLocation(mSecondPointerDownLocation, event);
mHandler.sendEmptyMessageDelayed(MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE,
@@ -1266,13 +985,26 @@
} else {
transitionToDelegatingStateAndClear();
}
+ // LINT.ThenChange(:action_pointer_down_with_multi_finger)
}
break;
case ACTION_POINTER_UP: {
+ if (mTwoFingerDoubleTapHandler != null) {
+ mTwoFingerDoubleTapHandler.onPointerUp();
+ break;
+ }
+ // LINT.IfChange(action_pointer_up)
transitionToDelegatingStateAndClear();
+ // LINT.ThenChange(:action_pointer_up_with_multi_finger)
}
break;
case ACTION_MOVE: {
+ if (mTwoFingerDoubleTapHandler != null) {
+ mTwoFingerDoubleTapHandler.onMove(event);
+ break;
+ }
+
+ // LINT.IfChange(action_move)
if (isFingerDown()
&& distance(mLastDown, /* move */ event) > mSwipeMinDistance) {
// Swipe detected - transition immediately
@@ -1313,12 +1045,20 @@
//Second pointer is swiping, so transit to PanningScalingState
transitToPanningScalingStateAndClear();
}
+ // LINT.ThenChange(:action_move_with_multi_finger)
}
break;
case ACTION_UP: {
mHandler.removeMessages(MESSAGE_ON_TRIPLE_TAP_AND_HOLD);
+ if (mTwoFingerDoubleTapHandler != null) {
+ mHandler.removeMessages(MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE);
+ mTwoFingerDoubleTapHandler.onUp(event);
+ break;
+ }
+
+ // LINT.IfChange(action_up)
if (!mFullScreenMagnificationController.magnificationRegionContains(
mDisplayId, event.getX(), event.getY())) {
transitionToDelegatingStateAndClear();
@@ -1335,11 +1075,11 @@
transitionToDelegatingStateAndClear();
}
+ // LINT.ThenChange(:action_up_with_multi_finger)
}
break;
}
}
- // LINT.ThenChange(:detecting_state_with_multi_finger)
protected void storePointerDownLocation(PointF pointerDownLocation, MotionEvent event) {
final int index = event.getActionIndex();
@@ -1425,6 +1165,9 @@
@Override
public void clear() {
+ if (mTwoFingerDoubleTapHandler != null) {
+ mTwoFingerDoubleTapHandler.mCompletedTapCount = 0;
+ }
setShortcutTriggered(false);
removePendingDelayedMessages();
clearDelayedMotionEvents();
@@ -1501,9 +1244,13 @@
}
void transitionToDelegatingStateAndClear() {
+ if (mTwoFingerDoubleTapHandler != null) {
+ mTwoFingerDoubleTapHandler.mCompletedTapCount = 0;
+ }
transitionTo(mDelegatingState);
sendDelayedMotionEvents();
removePendingDelayedMessages();
+ mFirstPointerDownLocation.set(Float.NaN, Float.NaN);
mSecondPointerDownLocation.set(Float.NaN, Float.NaN);
}
@@ -1543,9 +1290,15 @@
// Only log the 3tap and hold event
if (!shortcutTriggered) {
- // Triple tap and hold also belongs to triple tap event
final boolean enabled = !isActivated();
- mMagnificationLogger.logMagnificationTripleTap(enabled);
+ if (mTwoFingerDoubleTapHandler != null
+ && mTwoFingerDoubleTapHandler.shouldLogTwoFingerDoubleTap()) {
+ // Two finger double tap and hold
+ mMagnificationLogger.logMagnificationTwoFingerTripleTap(enabled);
+ } else {
+ // Triple tap and hold also belongs to triple tap event
+ mMagnificationLogger.logMagnificationTripleTap(enabled);
+ }
}
clear();
@@ -1604,6 +1357,173 @@
}
return false;
}
+
+ final class TwoFingerDoubleTapHandler {
+ private static final int TWO_FINGER_GESTURE_MAX_TAPS = 2;
+ // A tap counts when two fingers are down and up once.
+ private int mCompletedTapCount;
+ // A flag set to true when two fingers have touched down.
+ // Used to indicate what next finger action should be.
+ private boolean mIsTwoFingerCountReached;
+
+ TwoFingerDoubleTapHandler() {
+ mCompletedTapCount = 0;
+ mIsTwoFingerCountReached = false;
+ }
+
+ private void onPointerDown(MotionEvent event) {
+ mIsTwoFingerCountReached = mDetectTwoFingerTripleTap
+ && event.getPointerCount() == 2;
+ mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
+
+ // LINT.IfChange(action_pointer_down_with_multi_finger)
+ if (event.getPointerCount() == 2) {
+ if (isMultiFingerMultiTapTriggered(
+ TWO_FINGER_GESTURE_MAX_TAPS - 1, event)) {
+ // 3tap and hold
+ afterLongTapTimeoutTransitionToDraggingState(event);
+ } else {
+ if (mDetectTwoFingerTripleTap) {
+ // If mDetectTwoFingerTripleTap, delay transition to the delegating
+ // state for mMultiTapMaxDelay to ensure reachability of
+ // multi finger multi tap
+ afterMultiTapTimeoutTransitionToDelegatingState();
+ }
+
+ if (isActivated()) {
+ // If activated, delay transition to the panning scaling
+ // state for tap timeout to ensure reachability of
+ // multi finger multi tap
+ storePointerDownLocation(mSecondPointerDownLocation, event);
+ mHandler.sendEmptyMessageDelayed(
+ MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE,
+ ViewConfiguration.getTapTimeout());
+ }
+ }
+ } else {
+ transitionToDelegatingStateAndClear();
+ }
+ // LINT.ThenChange(:action_pointer_down)
+ }
+
+ private void onMove(MotionEvent event) {
+ // LINT.IfChange(action_move_with_multi_finger)
+ if (isFingerDown()
+ && distance(mLastDown, /* move */ event) > mSwipeMinDistance) {
+ // Swipe detected - transition immediately
+
+ // For convenience, viewport dragging takes precedence
+ // over insta-delegating on 3tap&swipe
+ // (which is a rare combo to be used aside from magnification)
+ if (isMultiTapTriggered(2 /* taps */) && event.getPointerCount() == 1) {
+ transitionToViewportDraggingStateAndClear(event);
+ } else if (isMultiFingerMultiTapTriggered(
+ TWO_FINGER_GESTURE_MAX_TAPS - 1, event)
+ && event.getPointerCount() == 2) {
+ transitionToViewportDraggingStateAndClear(event);
+ } else if (isActivated() && event.getPointerCount() == 2) {
+ if (mOverscrollHandler != null
+ && overscrollState(event, mFirstPointerDownLocation)
+ == OVERSCROLL_VERTICAL_EDGE) {
+ transitionToDelegatingStateAndClear();
+ } else {
+ //Primary pointer is swiping, so transit to PanningScalingState
+ transitToPanningScalingStateAndClear();
+ }
+ } else if (mOneFingerPanningSettingsProvider.isOneFingerPanningEnabled()
+ && isActivated()
+ && event.getPointerCount() == 1) {
+ if (mOverscrollHandler != null
+ && overscrollState(event, mFirstPointerDownLocation)
+ == OVERSCROLL_VERTICAL_EDGE) {
+ transitionToDelegatingStateAndClear();
+ } else if (overscrollState(event, mFirstPointerDownLocation)
+ != OVERSCROLL_NONE) {
+ transitionToDelegatingStateAndClear();
+ } else {
+ transitToSinglePanningStateAndClear();
+ }
+ } else if (!mIsTwoFingerCountReached) {
+ // If it is a two-finger gesture, do not transition to the
+ // delegating state to ensure the reachability of
+ // the two-finger triple tap (triggerable with ACTION_UP)
+ transitionToDelegatingStateAndClear();
+ }
+ } else if (isActivated() && pointerDownValid(mSecondPointerDownLocation)
+ && distanceClosestPointerToPoint(
+ mSecondPointerDownLocation, /* move */ event) > mSwipeMinDistance) {
+ // Second pointer is swiping, so transit to PanningScalingState
+ // Delay an ACTION_MOVE for tap timeout to ensure it is not trigger from
+ // multi finger multi tap
+ storePointerDownLocation(mSecondPointerDownLocation, event);
+ mHandler.sendEmptyMessageDelayed(
+ MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE,
+ ViewConfiguration.getTapTimeout());
+ }
+ // LINT.ThenChange(:action_move)
+ }
+
+ private void onPointerUp() {
+ // If it is a two-finger gesture, do not transition to the delegating state
+ // to ensure the reachability of
+ // the two-finger triple tap (triggerable with ACTION_MOVE and ACTION_UP)
+ // LINT.IfChange(action_pointer_up_with_multi_finger)
+ if (!mIsTwoFingerCountReached) {
+ transitionToDelegatingStateAndClear();
+ }
+ // LINT.ThenChange(:action_pointer_up)
+ }
+
+ private void onUp(MotionEvent event) {
+ // LINT.IfChange(action_up_with_multi_finger)
+ if (!mFullScreenMagnificationController.magnificationRegionContains(
+ mDisplayId, event.getX(), event.getY())) {
+ transitionToDelegatingStateAndClear();
+
+ } else if (isMultiFingerMultiTapTriggered(
+ TWO_FINGER_GESTURE_MAX_TAPS, event)) {
+ // Placing multiple fingers before a single finger, because achieving a
+ // multi finger multi tap also means achieving a single finger
+ // triple tap
+ onTripleTap(event);
+
+ } else if (isMultiTapTriggered(3 /* taps */)) {
+ onTripleTap(/* up */ event);
+
+ } else if (
+ // Possible to be false on: 3tap&drag -> scale -> PTR_UP -> UP
+ isFingerDown()
+ //TODO long tap should never happen here
+ && ((timeBetween(mLastDown, mLastUp) >= mLongTapMinDelay)
+ || (distance(mLastDown, mLastUp) >= mSwipeMinDistance))
+ // If it is a two-finger but not reach 3 tap, do not
+ // transition to the delegating state to ensure the
+ // reachability of the triple tap
+ && mCompletedTapCount == 0) {
+ transitionToDelegatingStateAndClear();
+ }
+ // LINT.ThenChange(:action_up)
+ }
+
+ private boolean isMultiFingerMultiTapTriggered(int targetTapCount, MotionEvent event) {
+ if (event.getActionMasked() == ACTION_UP && mIsTwoFingerCountReached) {
+ mCompletedTapCount++;
+ mIsTwoFingerCountReached = false;
+ }
+
+ if (mDetectTwoFingerTripleTap
+ && mCompletedTapCount > TWO_FINGER_GESTURE_MAX_TAPS - 1) {
+ final boolean enabled = !isActivated();
+ mMagnificationLogger.logMagnificationTwoFingerTripleTap(enabled);
+ }
+ return mDetectTwoFingerTripleTap && mCompletedTapCount == targetTapCount;
+ }
+
+ private boolean shouldLogTwoFingerDoubleTap() {
+ return mCompletedTapCount
+ == TwoFingerDoubleTapHandler.TWO_FINGER_GESTURE_MAX_TAPS - 1;
+ }
+ }
}
private void zoomInTemporary(float centerX, float centerY, boolean shortcutTriggered) {