Avoid changing transform when touching in progress

After swiping from a landscape app to portrait home, the touch
orientation may be changed if there the touch event comes in a
short time (e.g. click app icon immediately):
 DOWN
 MOVE...
 SimpleOrientationTouchTransformer#onDisplayInfoChanged
 MOVE... (start to transform with inconsistent orientation)
 UP

That could disturb the gesture detection:
OverviewInputConsumer#onMotionEvent
 > BaseDragLayer#proxyTouchEvent
  onInterceptTouchEvent, findControllerToHandleTouch
  > PortraitStatesTouchController#onControllerInterceptTouchEvent
   > BaseSwipeDetector#onTouchEvent
which may show the app drawer unexpectedly.

http://recall/-/b2qm27pJZxFIWQccA9qE9Q/ggLXlE5kf7AWMOjUc0FCUU

Bug: 351755391
Flag: EXEMPT bugfix
Test: atest NexusLauncherTests: \
            com.android.quickstep.OrientationTouchTransformerTest# \
            testSimpleOrientationTouchTransformer
Change-Id: Ic0e9d8292606837feb4775663abb60229c90e9c5
diff --git a/quickstep/src/com/android/quickstep/OrientationRectF.java b/quickstep/src/com/android/quickstep/OrientationRectF.java
index aa01b05..2b7ecb2 100644
--- a/quickstep/src/com/android/quickstep/OrientationRectF.java
+++ b/quickstep/src/com/android/quickstep/OrientationRectF.java
@@ -67,13 +67,15 @@
     }
 
     public boolean applyTransform(MotionEvent event, int deltaRotation, boolean forceTransform) {
+        if (deltaRotation == 0) {
+            return contains(event.getX(), event.getY());
+        }
         mTmpMatrix.reset();
         postDisplayRotation(deltaRotation, mHeight, mWidth, mTmpMatrix);
         if (forceTransform) {
             if (DEBUG) {
                 Log.d(TAG, "Transforming rotation due to forceTransform, "
                         + "deltaRotation: " + deltaRotation
-                        + "mRotation: " + mRotation
                         + " this: " + this);
             }
             event.applyTransform(mTmpMatrix);
diff --git a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
index 29a57fc..5264643 100644
--- a/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
+++ b/quickstep/src/com/android/quickstep/SimpleOrientationTouchTransformer.java
@@ -34,12 +34,18 @@
 
     private final Context mContext;
     private OrientationRectF mOrientationRectF;
+    private OrientationRectF mTouchingOrientationRectF;
+    private int mViewRotation;
 
     public SimpleOrientationTouchTransformer(Context context) {
+        this(context, DisplayController.INSTANCE.get(context));
+    }
+
+    @androidx.annotation.VisibleForTesting
+    public SimpleOrientationTouchTransformer(Context context, DisplayController displayController) {
         mContext = context;
-        DisplayController.INSTANCE.get(context).addChangeListener(this);
-        onDisplayInfoChanged(context, DisplayController.INSTANCE.get(context).getInfo(),
-                CHANGE_ALL);
+        displayController.addChangeListener(this);
+        onDisplayInfoChanged(context, displayController.getInfo(), CHANGE_ALL);
     }
 
     @Override
@@ -56,7 +62,29 @@
                 info.rotation);
     }
 
+    /**
+     * Called when the touch is started. This preserves the touching orientation until the touch is
+     * done (i.e. ACTION_CANCEL or ACTION_UP). So the transform won't produce inconsistent position
+     * if display is changed during the touch.
+     */
+    public void updateTouchingOrientation(int viewRotation) {
+        mViewRotation = viewRotation;
+        mTouchingOrientationRectF = new OrientationRectF(mOrientationRectF.left,
+                mOrientationRectF.top, mOrientationRectF.right, mOrientationRectF.bottom,
+                mOrientationRectF.getRotation());
+    }
+
+    /** Called when the touch is finished. */
+    public void clearTouchingOrientation() {
+        mTouchingOrientationRectF = null;
+    }
+
     public void transform(MotionEvent ev, int rotation) {
+        if (mTouchingOrientationRectF != null) {
+            mTouchingOrientationRectF.applyTransformToRotation(ev, mViewRotation,
+                    true /* forceTransform */);
+            return;
+        }
         mOrientationRectF.applyTransformToRotation(ev, rotation, true /* forceTransform */);
     }
 }
diff --git a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
index cb44a1a..fcf9ab1 100644
--- a/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
+++ b/quickstep/src/com/android/quickstep/util/InputConsumerProxy.java
@@ -108,19 +108,28 @@
             return false;
         }
 
+        final SimpleOrientationTouchTransformer touchTransformer =
+                SimpleOrientationTouchTransformer.INSTANCE.get(mContext);
+        final int viewRotation = mRotationSupplier.get();
+        final boolean needTransform = viewRotation != ev.getSurfaceRotation();
         if (action == ACTION_DOWN) {
             mTouchInProgress = true;
+            if (needTransform) {
+                touchTransformer.updateTouchingOrientation(viewRotation);
+            }
             initInputConsumerIfNeeded(/* isFromTouchDown= */ true);
         } else if (action == ACTION_CANCEL || action == ACTION_UP) {
             // Finish any pending actions
             mTouchInProgress = false;
+            touchTransformer.clearTouchingOrientation();
             if (mDestroyPending) {
                 destroy();
             }
         }
         if (mInputConsumer != null) {
-            SimpleOrientationTouchTransformer.INSTANCE.get(mContext).transform(ev,
-                    mRotationSupplier.get());
+            if (needTransform) {
+                touchTransformer.transform(ev, viewRotation);
+            }
             mInputConsumer.onMotionEvent(ev);
         }
 
diff --git a/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java b/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
index 298dd6c..f5d082d 100644
--- a/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
+++ b/quickstep/tests/src/com/android/quickstep/OrientationTouchTransformerTest.java
@@ -21,6 +21,7 @@
 
 import static com.android.launcher3.util.NavigationMode.NO_BUTTON;
 
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 import static org.mockito.ArgumentMatchers.any;
@@ -288,6 +289,34 @@
         assertTrue(mTouchTransformer.touchInValidSwipeRegions(inRegion2.getX(), inRegion2.getY()));
     }
 
+    @Test
+    public void testSimpleOrientationTouchTransformer() {
+        final DisplayController displayController = mock(DisplayController.class);
+        doReturn(mInfo).when(displayController).getInfo();
+        final SimpleOrientationTouchTransformer transformer =
+                new SimpleOrientationTouchTransformer(getApplicationContext(), displayController);
+        final MotionEvent move1 = generateMotionEvent(MotionEvent.ACTION_MOVE, 100, 10);
+        transformer.transform(move1, Surface.ROTATION_90);
+        // The position is transformed to 90 degree.
+        assertEquals(10, move1.getX(), 0f /* delta */);
+        assertEquals(NORMAL_SCREEN_SIZE.getWidth() - 100, move1.getY(), 0f /* delta */);
+
+        // If the touching state is specified, the position is still transformed to 90 degree even
+        // if the given rotation is changed.
+        final MotionEvent move2 = generateMotionEvent(MotionEvent.ACTION_MOVE, 100, 10);
+        transformer.updateTouchingOrientation(Surface.ROTATION_90);
+        transformer.transform(move2, Surface.ROTATION_0);
+        assertEquals(move1.getX(), move2.getX(), 0f /* delta */);
+        assertEquals(move1.getY(), move2.getY(), 0f /* delta */);
+
+        // If the touching state is cleared, it restores to use the given rotation.
+        final MotionEvent move3 = generateMotionEvent(MotionEvent.ACTION_MOVE, 100, 10);
+        transformer.clearTouchingOrientation();
+        transformer.transform(move3, Surface.ROTATION_0);
+        assertEquals(100, move3.getX(), 0f /* delta */);
+        assertEquals(10, move3.getY(), 0f /* delta */);
+    }
+
     private DisplayController.Info createDisplayInfo(Size screenSize, int rotation) {
         Point displaySize = new Point(screenSize.getWidth(), screenSize.getHeight());
         RotationUtils.rotateSize(displaySize, rotation);