Waiting for a small timeout for launcher draw, before performing the swipe gesture.

This allow for a better synchronized motion, in case launcher draw was fast enough

Change-Id: Ie59aa1e8a2ffa94f3640b4ea08a0c23eeabafb54
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index df012df..d6fe866 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -36,6 +36,7 @@
 import android.graphics.PointF;
 import android.graphics.Rect;
 import android.os.Bundle;
+import android.os.Looper;
 import android.util.Log;
 import android.view.Display;
 import android.view.MotionEvent;
@@ -56,12 +57,17 @@
 import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
 import com.android.systemui.shared.system.WindowManagerWrapper;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
+
 /**
  * Touch consumer for handling events originating from an activity other than Launcher
  */
 public class OtherActivityTouchConsumer extends ContextWrapper implements TouchConsumer {
     private static final String TAG = "ActivityTouchConsumer";
 
+    private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150;
+
     private final RunningTaskInfo mRunningTask;
     private final RecentsModel mRecentsModel;
     private final Intent mHomeIntent;
@@ -111,7 +117,6 @@
                     startTouchTrackingForWindowAnimation();
                 }
 
-                mVelocityTracker.addMovement(ev);
                 Display display = getSystemService(WindowManager.class).getDefaultDisplay();
                 mDisplayRotation = display.getRotation();
                 WindowManagerWrapper.getInstance().getStableInsets(mStableInsets);
@@ -127,7 +132,6 @@
                             ev.getY(newPointerIdx) - (mLastPos.y - mDownPos.y));
                     mLastPos.set(ev.getX(newPointerIdx), ev.getY(newPointerIdx));
                     mActivePointerId = ev.getPointerId(newPointerIdx);
-                    mVelocityTracker.clear();
                 }
                 break;
             }
@@ -136,7 +140,6 @@
                 if (pointerIndex == INVALID_POINTER_ID) {
                     break;
                 }
-                mVelocityTracker.addMovement(ev);
                 mLastPos.set(ev.getX(pointerIndex), ev.getY(pointerIndex));
 
                 float displacement = ev.getY(pointerIndex) - mDownPos.y;
@@ -250,44 +253,60 @@
         // Create the shared handler
         final WindowTransformSwipeHandler handler =
                 new WindowTransformSwipeHandler(mRunningTask, this);
-        BackgroundExecutor.get().submit(() -> {
-            ActivityManagerWrapper.getInstance().startRecentsActivity(mHomeIntent,
-                    new AssistDataReceiver() {
-                        @Override
-                        public void onHandleAssistData(Bundle bundle) {
-                            // Pass to AIAI
-                        }
-                    },
-                    new RecentsAnimationListener() {
-                        public void onAnimationStart(
-                                RecentsAnimationControllerCompat controller,
-                                RemoteAnimationTargetCompat[] apps) {
-                            if (mInteractionHandler == handler) {
-                                handler.setRecentsAnimation(controller, apps);
-
-                            } else {
-                                controller.finish(false /* toHome */);
-                            }
-                        }
-
-                        public void onAnimationCanceled() {
-                            if (mInteractionHandler == handler) {
-                                handler.setRecentsAnimation(null, null);
-                            }
-                        }
-                    }, null, null);
-        });
 
         // Preload the plan
         mRecentsModel.loadTasks(mRunningTask.id, null);
         mInteractionHandler = handler;
         handler.setGestureEndCallback(this::onFinish);
+
+        CountDownLatch drawWaitLock = new CountDownLatch(1);
         handler.setLauncherOnDrawCallback(() -> {
+            drawWaitLock.countDown();
             if (handler == mInteractionHandler) {
                 switchToMainConsumer();
             }
         });
-        mMainThreadExecutor.execute(handler::initWhenReady);
+        handler.initWhenReady(mMainThreadExecutor);
+
+        Runnable startActivity = () -> ActivityManagerWrapper.getInstance()
+                .startRecentsActivity(mHomeIntent,
+                new AssistDataReceiver() {
+                    @Override
+                    public void onHandleAssistData(Bundle bundle) {
+                        // Pass to AIAI
+                    }
+                },
+                new RecentsAnimationListener() {
+                    public void onAnimationStart(
+                            RecentsAnimationControllerCompat controller,
+                            RemoteAnimationTargetCompat[] apps) {
+                        if (mInteractionHandler == handler) {
+                            handler.setRecentsAnimation(controller, apps);
+
+                        } else {
+                            controller.finish(false /* toHome */);
+                        }
+                    }
+
+                    public void onAnimationCanceled() {
+                        if (mInteractionHandler == handler) {
+                            handler.setRecentsAnimation(null, null);
+                        }
+                    }
+                }, null, null);
+
+        if (Looper.myLooper() != Looper.getMainLooper()) {
+            startActivity.run();
+            try {
+                drawWaitLock.await(LAUNCHER_DRAW_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+            } catch (Exception e) {
+                // We have waited long enough for launcher to draw
+            }
+        } else {
+            // We should almost always get touch-town on background thread. This is an edge case
+            // when the background Choreographer has not yet initialized.
+            BackgroundExecutor.get().submit(startActivity);
+        }
     }
 
     /**
@@ -360,4 +379,14 @@
     public void onTouchTrackingComplete() { }
 
     public void switchToMainConsumer() { }
+
+    @Override
+    public void preProcessMotionEvent(MotionEvent ev) {
+        if (mVelocityTracker != null) {
+           mVelocityTracker.addMovement(ev);
+           if (ev.getActionMasked() == ACTION_POINTER_UP) {
+               mVelocityTracker.clear();
+           }
+        }
+    }
 }
diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java
index d4d3a3f..77480af 100644
--- a/quickstep/src/com/android/quickstep/TouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/TouchConsumer.java
@@ -55,4 +55,10 @@
     default void onQuickScrubEnd() { }
 
     default void onQuickScrubProgress(float progress) { }
+
+    /**
+     * Called on the binder thread to allow the consumer to process the motion event before it is
+     * posted on a handler thread.
+     */
+    default void preProcessMotionEvent(MotionEvent ev) { }
 }
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index ab496ad..e80f97d 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -178,6 +178,7 @@
             mEventQueue.setInterimChoreographer(mCurrentConsumer.shouldUseBackgroundConsumer()
                     ? mBackgroundThreadChoreographer : null);
         }
+        mCurrentConsumer.preProcessMotionEvent(ev);
         mEventQueue.queue(ev);
     }
 
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index 3364c36..5f5d15b 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -119,6 +119,7 @@
     private boolean mWasLauncherAlreadyVisible;
 
     private float mCurrentDisplacement;
+    private boolean mGestureStarted;
 
     private @InteractionType int mInteractionType = INTERACTION_NORMAL;
     private boolean mStartedQuickScrubFromHome;
@@ -216,6 +217,7 @@
             long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx);
             mLauncherTransitionController = launcher.getStateManager()
                     .createAnimationToNewWorkspace(OVERVIEW, accuracy);
+            mLauncherTransitionController.dispatchOnStart();
             mLauncherTransitionController.setPlayFraction(mCurrentShift.value);
 
             state = STATE_ACTIVITY_MULTIPLIER_COMPLETE | STATE_LAUNCHER_DRAWN
@@ -273,10 +275,15 @@
     private void launcherFrameDrawn() {
         View rootView = mLauncher.getRootView();
         if (rootView.getAlpha() < 1) {
-            final MultiStateCallback callback = mStateCallback;
-            rootView.animate().alpha(1)
-                    .setDuration(getFadeInDuration())
-                    .withEndAction(() -> callback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE));
+            if (mGestureStarted) {
+                final MultiStateCallback callback = mStateCallback;
+                rootView.animate().alpha(1)
+                        .setDuration(getFadeInDuration())
+                        .withEndAction(() -> callback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE));
+            } else {
+                rootView.setAlpha(1);
+                mStateCallback.setState(STATE_ACTIVITY_MULTIPLIER_COMPLETE);
+            }
         }
         mLauncherLayoutListener.setHandler(this);
         onLauncherLayoutChanged();
@@ -416,7 +423,9 @@
         setStateOnUiThread(STATE_APP_CONTROLLER_RECEIVED);
     }
 
-    public void onGestureStarted() { }
+    public void onGestureStarted() {
+        mGestureStarted = true;
+    }
 
     @WorkerThread
     public void onGestureEnded(float endVelocity) {
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index 639fb6c..fcf36ca 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1256,7 +1256,7 @@
                 && AbstractFloatingView.getTopOpenView(this) == null;
         boolean isActionMain = Intent.ACTION_MAIN.equals(intent.getAction());
         boolean internalStateHandled = InternalStateHandler
-                .handleNewIntent(this, intent, alreadyOnHome);
+                .handleNewIntent(this, intent, isStarted());
 
         if (isActionMain) {
             if (!internalStateHandled) {
diff --git a/src/com/android/launcher3/states/InternalStateHandler.java b/src/com/android/launcher3/states/InternalStateHandler.java
index 4c3ef4b..7298383 100644
--- a/src/com/android/launcher3/states/InternalStateHandler.java
+++ b/src/com/android/launcher3/states/InternalStateHandler.java
@@ -23,6 +23,7 @@
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
 import com.android.launcher3.LauncherModel.Callbacks;
+import com.android.launcher3.MainThreadExecutor;
 import com.android.launcher3.util.Preconditions;
 
 import java.lang.ref.WeakReference;
@@ -52,9 +53,12 @@
         return intent;
     }
 
-    public final void initWhenReady() {
-        Preconditions.assertUIThread();
+    public final void initWhenReady(MainThreadExecutor executor) {
         sPendingHandler = new WeakReference<>(this);
+        executor.execute(this::initIfReadOnUIThread);
+    }
+
+    private void initIfReadOnUIThread() {
         LauncherAppState app = LauncherAppState.getInstanceNoCreate();
         if (app == null) {
             return;
@@ -76,15 +80,15 @@
     }
 
     public static boolean handleCreate(Launcher launcher, Intent intent) {
-        return handleIntent(launcher, intent, false);
+        return handleIntent(launcher, intent, false, false);
     }
 
     public static boolean handleNewIntent(Launcher launcher, Intent intent, boolean alreadyOnHome) {
-        return handleIntent(launcher, intent, alreadyOnHome);
+        return handleIntent(launcher, intent, alreadyOnHome, true);
     }
 
     private static boolean handleIntent(
-            Launcher launcher, Intent intent, boolean alreadyOnHome) {
+            Launcher launcher, Intent intent, boolean alreadyOnHome, boolean explicitIntent) {
         boolean result = false;
         if (intent != null && intent.getExtras() != null) {
             IBinder stateBinder = intent.getExtras().getBinder(EXTRA_STATE_HANDLER);
@@ -96,7 +100,7 @@
                 result = true;
             }
         }
-        if (!result) {
+        if (!result && !explicitIntent) {
             InternalStateHandler pendingHandler = sPendingHandler.get();
             if (pendingHandler != null) {
                 if (!pendingHandler.init(launcher, alreadyOnHome)) {