Merge "fix(MultiFingerMultiTap): The two finger triple tap is hard work when Magnification is activated" 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 e3797c9..f55ecb0 100644
--- a/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
+++ b/services/accessibility/java/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandler.java
@@ -916,18 +916,27 @@
                             && event.getPointerCount() == 2;
                     mHandler.removeMessages(MESSAGE_TRANSITION_TO_DELEGATING_STATE);
 
-                    if (isActivated() && event.getPointerCount() == 2) {
-                        storePointerDownLocation(mSecondPointerDownLocation, event);
-                        mHandler.sendEmptyMessageDelayed(MESSAGE_TRANSITION_TO_PANNINGSCALING_STATE,
-                                ViewConfiguration.getTapTimeout());
-                    } else if (mIsTwoFingerCountReached) {
-                        // Placing two-finger triple-taps behind isActivated to avoid
-                        // blocking panning scaling state
+                    if (event.getPointerCount() == 2) {
                         if (isMultiFingerMultiTapTriggered(/* targetTapCount= */ 2, event)) {
                             // 3tap and hold
                             afterLongTapTimeoutTransitionToDraggingState(event);
                         } else {
-                            afterMultiTapTimeoutTransitionToDelegatingState();
+                            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();
@@ -953,6 +962,9 @@
                         // (which is a rare combo to be used aside from magnification)
                         if (isMultiTapTriggered(2 /* taps */) && event.getPointerCount() == 1) {
                             transitionToViewportDraggingStateAndClear(event);
+                        } else if (isMultiFingerMultiTapTriggered(/* targetTapCount= */ 2, event)
+                                && event.getPointerCount() == 2) {
+                            transitionToViewportDraggingStateAndClear(event);
                         } else if (isActivated() && event.getPointerCount() == 2) {
                             if (mIsSinglePanningEnabled
                                     && overscrollState(event, mFirstPointerDownLocation)
@@ -961,11 +973,6 @@
                             }
                             //Primary pointer is swiping, so transit to PanningScalingState
                             transitToPanningScalingStateAndClear();
-                        } else if (isMultiFingerMultiTapTriggered(/* targetTapCount= */ 2, event)
-                                && event.getPointerCount() == 2) {
-                            // Placing two-finger triple-taps behind isActivated to avoid
-                            // blocking panning scaling state
-                            transitionToViewportDraggingStateAndClear(event);
                         } else if (mIsSinglePanningEnabled
                                 && isActivated()
                                 && event.getPointerCount() == 1) {
@@ -979,8 +986,11 @@
                         }
                     } else if (isActivated() && pointerDownValid(mSecondPointerDownLocation)
                             && distanceClosestPointerToPoint(
-                            mSecondPointerDownLocation, /* move */ event) > mSwipeMinDistance) {
-                        //Second pointer is swiping, so transit to PanningScalingState
+                            mSecondPointerDownLocation, /* move */ event) > mSwipeMinDistance
+                            // If mCompleteTapCount is not zero, it means that it is a multi tap
+                            // gesture. So, we should not transit to the PanningScalingState.
+                            && mCompletedTapCount == 0) {
+                        // Second pointer is swiping, so transit to PanningScalingState
                         transitToPanningScalingStateAndClear();
                     }
                 }
@@ -988,6 +998,7 @@
                 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())) {
diff --git a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
index 3b39160..9114027 100644
--- a/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
+++ b/services/tests/servicestests/src/com/android/server/accessibility/magnification/FullScreenMagnificationGestureHandlerTest.java
@@ -588,6 +588,38 @@
     }
 
     @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
+    public void testTwoFingerTap_StateIsActivated_shouldInDelegating() {
+        assumeTrue(mMgh.mIsSinglePanningEnabled);
+        mMgh.setSinglePanningEnabled(false);
+        goFromStateIdleTo(STATE_ACTIVATED);
+        allowEventDelegation();
+
+        send(downEvent());
+        send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_X * 2, DEFAULT_Y));
+        send(upEvent());
+        fastForward(ViewConfiguration.getDoubleTapTimeout());
+
+        assertTrue(mMgh.mCurrentState == mMgh.mDelegatingState);
+    }
+
+    @Test
+    @RequiresFlagsEnabled(Flags.FLAG_ENABLE_MAGNIFICATION_MULTIPLE_FINGER_MULTIPLE_TAP_GESTURE)
+    public void testTwoFingerTap_StateIsIdle_shouldInDelegating() {
+        assumeTrue(mMgh.mIsSinglePanningEnabled);
+        mMgh.setSinglePanningEnabled(false);
+        goFromStateIdleTo(STATE_IDLE);
+        allowEventDelegation();
+
+        send(downEvent());
+        send(pointerEvent(ACTION_POINTER_DOWN, DEFAULT_X * 2, DEFAULT_Y));
+        send(upEvent());
+        fastForward(ViewConfiguration.getDoubleTapTimeout());
+
+        assertTrue(mMgh.mCurrentState == mMgh.mDelegatingState);
+    }
+
+    @Test
     public void testMultiTap_outOfDistanceSlop_shouldInIdle() {
         // All delay motion events should be sent, if multi-tap with out of distance slop.
         // STATE_IDLE will check if tapCount() < 2.
@@ -719,6 +751,20 @@
     }
 
     @Test
+    public void testTwoFingerDown_twoPointerDownAndActivatedState_panningState() {
+        goFromStateIdleTo(STATE_ACTIVATED);
+        PointF pointer1 = DEFAULT_POINT;
+        PointF pointer2 = new PointF(DEFAULT_X * 1.5f, DEFAULT_Y);
+
+        send(downEvent());
+        send(pointerEvent(ACTION_POINTER_DOWN, new PointF[] {pointer1, pointer2}, 1));
+        fastForward(ViewConfiguration.getTapTimeout());
+        assertIn(STATE_PANNING);
+
+        returnToNormalFrom(STATE_PANNING);
+    }
+
+    @Test
     public void testActivatedWithTripleTap_invokeShowWindowPromptAction() {
         goFromStateIdleTo(STATE_ACTIVATED);