Passing proper velocity information when simulating touch events on recents view

Change-Id: I488b8d61c47e49dbdc65b16e2470b171912efc3f
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index b152bb9..5755205 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -67,6 +67,8 @@
 import java.util.concurrent.CountDownLatch;
 import java.util.concurrent.TimeUnit;
 
+import androidx.annotation.Nullable;
+
 /**
  * Touch consumer for handling events originating from an activity other than Launcher
  */
@@ -196,7 +198,7 @@
 
                 if (mPassedInitialSlop && mInteractionHandler != null) {
                     // Move
-                    dispatchMotion(ev, displacement - mStartDisplacement);
+                    dispatchMotion(ev, displacement - mStartDisplacement, null);
 
                     if (FeatureFlags.SWIPE_HOME.get()) {
                         mMotionPauseDetector.addPosition(displacement);
@@ -217,11 +219,11 @@
         }
     }
 
-    private void dispatchMotion(MotionEvent ev, float displacement) {
+    private void dispatchMotion(MotionEvent ev, float displacement, @Nullable Float velocityX) {
         mInteractionHandler.updateDisplacement(displacement);
         boolean isLandscape = isNavBarOnLeft() || isNavBarOnRight();
         if (!isLandscape) {
-            mInteractionHandler.dispatchMotionEventToRecentsView(ev);
+            mInteractionHandler.dispatchMotionEventToRecentsView(ev, velocityX);
         }
     }
 
@@ -316,15 +318,16 @@
      */
     private void finishTouchTracking(MotionEvent ev) {
         if (mPassedInitialSlop && mInteractionHandler != null) {
-            dispatchMotion(ev, getDisplacement(ev) - mStartDisplacement);
 
             mVelocityTracker.computeCurrentVelocity(1000,
                     ViewConfiguration.get(this).getScaledMaximumFlingVelocity());
-
             float velocityX = mVelocityTracker.getXVelocity(mActivePointerId);
             float velocity = isNavBarOnRight() ? velocityX
                     : isNavBarOnLeft() ? -velocityX
                             : mVelocityTracker.getYVelocity(mActivePointerId);
+
+            dispatchMotion(ev, getDisplacement(ev) - mStartDisplacement, velocityX);
+
             mInteractionHandler.onGestureEnded(velocity, velocityX);
         } else {
             // Since we start touch tracking on DOWN, we may reach this state without actually
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index d118e99..86a8081 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -70,6 +70,7 @@
 
 import androidx.annotation.AnyThread;
 import androidx.annotation.NonNull;
+import androidx.annotation.Nullable;
 import androidx.annotation.UiThread;
 import androidx.annotation.WorkerThread;
 
@@ -624,23 +625,37 @@
     }
 
     @WorkerThread
-    public void dispatchMotionEventToRecentsView(MotionEvent event) {
+    @SuppressWarnings("WrongThread")
+    public void dispatchMotionEventToRecentsView(MotionEvent event, @Nullable Float velocityX) {
         if (mRecentsView == null) {
             return;
         }
-        // Pass the motion events to RecentsView to allow scrolling during swipe up.
-        if (mDispatchedDownEvent) {
-            mRecentsView.dispatchTouchEvent(event);
+        if (Looper.myLooper() == mMainThreadHandler.getLooper()) {
+            dispatchMotionEventToRecentsViewUi(event, velocityX);
         } else {
+            MotionEvent ev = MotionEvent.obtain(event);
+            postAsyncCallback(mMainThreadHandler, () -> {
+                dispatchMotionEventToRecentsViewUi(ev, velocityX);
+                ev.recycle();
+            });
+        }
+    }
+
+    @UiThread
+    private void dispatchMotionEventToRecentsViewUi(MotionEvent event, @Nullable Float velocityX) {
+        // Pass the motion events to RecentsView to allow scrolling during swipe up.
+        if (!mDispatchedDownEvent) {
             // The first event we dispatch should be ACTION_DOWN.
             mDispatchedDownEvent = true;
             MotionEvent downEvent = MotionEvent.obtain(event);
             downEvent.setAction(MotionEvent.ACTION_DOWN);
             int flags = downEvent.getEdgeFlags();
             downEvent.setEdgeFlags(flags | TouchInteractionService.EDGE_NAV_BAR);
-            mRecentsView.dispatchTouchEvent(downEvent);
+            mRecentsView.simulateTouchEvent(downEvent, velocityX);
             downEvent.recycle();
         }
+
+        mRecentsView.simulateTouchEvent(event, velocityX);
     }
 
     @WorkerThread
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 840d2bd..923da7b 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -159,6 +159,8 @@
 
     private final ViewPool<TaskView> mTaskViewPool;
 
+    @Nullable Float mSimulatedVelocityX = null;
+
     /**
      * TODO: Call reloadIdNeeded in onTaskStackChanged.
      */
@@ -1610,4 +1612,18 @@
             }
         }
     }
+
+    public void simulateTouchEvent(MotionEvent event, @Nullable Float velocityX) {
+        mSimulatedVelocityX = velocityX;
+        dispatchTouchEvent(event);
+        mSimulatedVelocityX = null;
+    }
+
+    @Override
+    protected int computeXVelocity() {
+        if (mSimulatedVelocityX != null) {
+            return mSimulatedVelocityX.intValue();
+        }
+        return super.computeXVelocity();
+    }
 }
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index a6b3a19..8f9e7c8 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -1134,9 +1134,7 @@
                 final int activePointerId = mActivePointerId;
                 final int pointerIndex = ev.findPointerIndex(activePointerId);
                 final float x = ev.getX(pointerIndex);
-                final VelocityTracker velocityTracker = mVelocityTracker;
-                velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
-                int velocityX = (int) velocityTracker.getXVelocity(activePointerId);
+                int velocityX = computeXVelocity();
                 final int deltaX = (int) (x - mDownMotionX);
                 final int pageWidth = getPageAt(mCurrentPage).getMeasuredWidth();
                 boolean isSignificantMove = Math.abs(deltaX) > pageWidth *
@@ -1240,6 +1238,12 @@
         return true;
     }
 
+    protected int computeXVelocity() {
+        final VelocityTracker velocityTracker = mVelocityTracker;
+        velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
+        return (int) velocityTracker.getXVelocity(mActivePointerId);
+    }
+
     protected boolean shouldFlingForVelocity(int velocityX) {
         return Math.abs(velocityX) > mFlingThresholdVelocity;
     }