Fixing ANR when using quickscrub from homescreen

Change-Id: Id355726f7ec72dc2fd28a3e757355d1143464001
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index d5fa723..080537e 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -21,6 +21,9 @@
 import static android.view.MotionEvent.ACTION_POINTER_DOWN;
 import static android.view.MotionEvent.ACTION_POINTER_UP;
 import static android.view.MotionEvent.ACTION_UP;
+
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_START_DURATION;
 import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SCRUB;
 import static com.android.quickstep.TouchConsumer.INTERACTION_QUICK_SWITCH;
 
@@ -40,14 +43,11 @@
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewConfiguration;
-import android.view.ViewTreeObserver;
 
 import com.android.launcher3.Launcher;
 import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherState;
 import com.android.launcher3.MainThreadExecutor;
 import com.android.launcher3.R;
-import com.android.launcher3.Workspace;
 import com.android.launcher3.model.ModelPreload;
 import com.android.systemui.shared.recents.IOverviewProxy;
 import com.android.systemui.shared.recents.ISystemUiProxy;
@@ -295,20 +295,21 @@
         public void updateTouchTracking(int interactionType) {
             mMainThreadExecutor.execute(() -> {
                 if (TouchConsumer.isInteractionQuick(interactionType)) {
-                    if (mLauncher.getWorkspace().runOnOverlayHidden(
-                            () -> updateTouchTracking(interactionType))) {
+                    Runnable action = () -> {
+                        Runnable onComplete = null;
+                        if (interactionType == INTERACTION_QUICK_SCRUB) {
+                            mQuickScrubController.onQuickScrubStart(true);
+                        } else if (interactionType == INTERACTION_QUICK_SWITCH) {
+                            onComplete = mQuickScrubController::onQuickSwitch;
+                        }
+                        mLauncher.getStateManager().goToState(OVERVIEW, true, 0,
+                                QUICK_SWITCH_START_DURATION, onComplete);
+                    };
+
+                    if (mLauncher.getWorkspace().runOnOverlayHidden(action)) {
                         // Hide the minus one overlay so launcher can get window focus.
                         mLauncher.onQuickstepGestureStarted(true);
-                        return;
                     }
-                    Runnable onComplete = null;
-                    if (interactionType == INTERACTION_QUICK_SCRUB) {
-                        mQuickScrubController.onQuickScrubStart(true);
-                    } else if (interactionType == INTERACTION_QUICK_SWITCH) {
-                        onComplete = mQuickScrubController::onQuickSwitch;
-                    }
-                    mLauncher.getStateManager().goToState(LauncherState.OVERVIEW, true, 0,
-                            QuickScrubController.QUICK_SWITCH_START_DURATION, onComplete);
                 }
             });
         }
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index a4ca68a..0b11707 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -1163,12 +1163,9 @@
             if (mOverlayShown) {
                 mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.SWIPE,
                         Action.Direction.RIGHT, ContainerType.WORKSPACE, -1);
-                if (mOnOverlayHiddenCallback != null) {
-                    mOnOverlayHiddenCallback.run();
-                    mOnOverlayHiddenCallback = null;
-                }
             }
             mOverlayShown = false;
+            tryRunOverlayCallback();
         }
         float offset = 0f;
         float slip = 0f;
@@ -1193,6 +1190,24 @@
     }
 
     /**
+     * @return false if the callback is still pending
+     */
+    private boolean tryRunOverlayCallback() {
+        if (mOnOverlayHiddenCallback == null) {
+            // Return true as no callback is pending. This is used by OnWindowFocusChangeListener
+            // to remove itself if multiple focus handles were added.
+            return true;
+        }
+        if (mOverlayShown || !hasWindowFocus()) {
+            return false;
+        }
+
+        mOnOverlayHiddenCallback.run();
+        mOnOverlayHiddenCallback = null;
+        return true;
+    }
+
+    /**
      * Runs the given callback when the minus one overlay is hidden. Specifically, it is run
      * when launcher's window has focus and the overlay is no longer being shown. If a callback
      * is already present, the new callback will chain off it so both are run.
@@ -1200,39 +1215,6 @@
      * @return Whether the callback was deferred.
      */
     public boolean runOnOverlayHidden(Runnable callback) {
-        View rootView = getRootView();
-        if (rootView.hasWindowFocus()) {
-            if (mOverlayShown) {
-                chainOverlayHiddenCallback(callback);
-                return true;
-            } else {
-                callback.run();
-                return false;
-            }
-        }
-        ViewTreeObserver observer = rootView.getViewTreeObserver();
-        if (observer != null && observer.isAlive()) {
-            observer.addOnWindowFocusChangeListener(
-                    new ViewTreeObserver.OnWindowFocusChangeListener() {
-                        @Override
-                        public void onWindowFocusChanged(boolean hasFocus) {
-                            if (hasFocus) {
-                                // Defer further if the minus one overlay is still showing.
-                                if (mOverlayShown) {
-                                    chainOverlayHiddenCallback(callback);
-                                } else {
-                                    callback.run();
-                                }
-                                observer.removeOnWindowFocusChangeListener(this);
-                            }
-                        }
-                    });
-            return true;
-        }
-        return false;
-    }
-
-    private void chainOverlayHiddenCallback(Runnable callback) {
         if (mOnOverlayHiddenCallback == null) {
             mOnOverlayHiddenCallback = callback;
         } else {
@@ -1243,6 +1225,21 @@
                 callback.run();
             };
         }
+        if (!tryRunOverlayCallback()) {
+            ViewTreeObserver observer = getViewTreeObserver();
+            if (observer != null && observer.isAlive()) {
+                observer.addOnWindowFocusChangeListener(
+                        new ViewTreeObserver.OnWindowFocusChangeListener() {
+                            @Override
+                            public void onWindowFocusChanged(boolean hasFocus) {
+                                if (tryRunOverlayCallback() && observer.isAlive()) {
+                                    observer.removeOnWindowFocusChangeListener(this);
+                                }
+                            }});
+            }
+            return true;
+        }
+        return false;
     }
 
     @Override