diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index e3427b7087..deeb02757d 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -51,6 +51,7 @@ import static com.android.quickstep.GestureState.STATE_RECENTS_SCROLLING_FINISHE import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.CANCEL_RECENTS_ANIMATION; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.EXPECTING_TASK_APPEARED; +import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.LAUNCHER_DESTROYED; import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent.ON_SETTLED_ON_END_TARGET; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; @@ -182,6 +183,7 @@ public abstract class AbsSwipeUpHandler, if (mActivity != activity) { return; } + handleActivityDestroyed(); mRecentsView = null; mActivity = null; } @@ -462,6 +464,7 @@ public abstract class AbsSwipeUpHandler, if (mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)) { return false; } + mStateCallback.resumeCallbacks(); T createdActivity = mActivityInterface.getCreatedActivity(); if (createdActivity != null) { @@ -531,6 +534,15 @@ public abstract class AbsSwipeUpHandler, return true; } + private void handleActivityDestroyed() { + ActiveGestureLog.INSTANCE.addLog("Launcher activity destroyed", LAUNCHER_DESTROYED); + if (mActivityInterface.shouldCancelGestureOnDestroy()) { + onGestureCancelled(); + } else { + mStateCallback.pauseCallbacks(); + } + } + /** * Return true if the window should be translated horizontally if the recents view scrolls */ diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java index 274b686ea4..22eaa972c3 100644 --- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java +++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java @@ -123,6 +123,14 @@ public abstract class BaseActivityInterface callback); + /** + * Returns {@code true} iff an ongoing navigational gesture should be cancelled on activity + * destroy. Otherwise, the MultiStateCallbacks will be paused until the activity is recreated. + */ + public boolean shouldCancelGestureOnDestroy() { + return true; + } + public abstract ActivityInitListener createActivityInitListener( Predicate onInitListener); diff --git a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java index ae9fb0b385..4cb4665d54 100644 --- a/quickstep/src/com/android/quickstep/FallbackActivityInterface.java +++ b/quickstep/src/com/android/quickstep/FallbackActivityInterface.java @@ -87,6 +87,11 @@ public final class FallbackActivityInterface extends return factory; } + @Override + public boolean shouldCancelGestureOnDestroy() { + return false; + } + @Override public ActivityInitListener createActivityInitListener( Predicate onInitListener) { diff --git a/quickstep/src/com/android/quickstep/MultiStateCallback.java b/quickstep/src/com/android/quickstep/MultiStateCallback.java index a68bea2cc0..6d767ed92e 100644 --- a/quickstep/src/com/android/quickstep/MultiStateCallback.java +++ b/quickstep/src/com/android/quickstep/MultiStateCallback.java @@ -31,6 +31,7 @@ import com.android.quickstep.util.ActiveGestureLog; import java.util.ArrayList; import java.util.LinkedList; +import java.util.List; import java.util.StringJoiner; import java.util.function.Consumer; @@ -52,6 +53,9 @@ public class MultiStateCallback { private int mState = 0; + private boolean mCallbacksPaused = false; + private final List mPendingCallbacks = new ArrayList<>(); + public MultiStateCallback(String[] stateNames) { this(stateNames, stateFlag -> null); } @@ -78,6 +82,24 @@ public class MultiStateCallback { } } + /** Pauses callbacks. */ + public void pauseCallbacks() { + mCallbacksPaused = true; + } + + /** Immediately queues any callbacks that were pending paused. */ + public void resumeCallbacks() { + if (!mCallbacksPaused) { + return; + } + mCallbacksPaused = false; + List queuedCallbacks = new ArrayList<>(mPendingCallbacks); + mPendingCallbacks.clear(); + for (Runnable runnable : queuedCallbacks) { + runnable.run(); + } + } + /** * Adds the provided state flags to the global state and executes any callbacks as a result. */ @@ -99,7 +121,12 @@ public class MultiStateCallback { if ((mState & state) == state) { LinkedList callbacks = mCallbacks.valueAt(i); while (!callbacks.isEmpty()) { - callbacks.pollFirst().run(); + Runnable cb = callbacks.pollFirst(); + if (mCallbacksPaused) { + mPendingCallbacks.add(cb); + } else { + cb.run(); + } } } } @@ -151,7 +178,11 @@ public class MultiStateCallback { if (wasOn != isOn) { ArrayList> listeners = mStateChangeListeners.valueAt(i); for (Consumer listener : listeners) { - listener.accept(isOn); + if (mCallbacksPaused) { + mPendingCallbacks.add(() -> listener.accept(isOn)); + } else { + listener.accept(isOn); + } } } } diff --git a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java index 60065fb16c..0fdd8b5e36 100644 --- a/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java +++ b/quickstep/src/com/android/quickstep/util/ActiveGestureErrorDetector.java @@ -37,7 +37,7 @@ public class ActiveGestureErrorDetector { ON_SETTLED_ON_END_TARGET, START_RECENTS_ANIMATION, FINISH_RECENTS_ANIMATION, CANCEL_RECENTS_ANIMATION, SET_ON_PAGE_TRANSITION_END_CALLBACK, CANCEL_CURRENT_ANIMATION, CLEANUP_SCREENSHOT, SCROLLER_ANIMATION_ABORTED, TASK_APPEARED, EXPECTING_TASK_APPEARED, - FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER, + FLAG_USING_OTHER_ACTIVITY_INPUT_CONSUMER, LAUNCHER_DESTROYED, /** * These GestureEvents are specifically associated to state flags that get set in @@ -162,6 +162,13 @@ public class ActiveGestureErrorDetector { + "before/without setting end target to new task", writer); break; + case LAUNCHER_DESTROYED: + errorDetected |= printErrorIfTrue( + true, + prefix, + /* errorMessage= */ "Launcher destroyed mid-gesture", + writer); + break; case STATE_GESTURE_COMPLETED: errorDetected |= printErrorIfTrue( !encounteredEvents.contains(GestureEvent.MOTION_UP), diff --git a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java index 47bef7b5b2..a4dbf6ade6 100644 --- a/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java +++ b/quickstep/tests/src/com/android/quickstep/FallbackRecentsTest.java @@ -168,7 +168,6 @@ public class FallbackRecentsTest { // b/143488140 //@NavigationModeSwitch - @Ignore @Test public void goToOverviewFromHome() { mDevice.pressHome(); @@ -216,7 +215,6 @@ public class FallbackRecentsTest { // b/143488140 //@NavigationModeSwitch - @Ignore @Test public void testOverview() { startAppFast(getAppPackageName());