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