From 19002551bc4e1dcb7dcc5f614dfc6ea3d8c9a505 Mon Sep 17 00:00:00 2001 From: Evan Rosky Date: Mon, 11 Apr 2022 18:23:57 -0700 Subject: [PATCH] Finish recents animation always Previously, some launcher-side state would be finished, but the actual animation would never be finished until the next touch-down. This is a problem for shell-transitions because it relies on animations finishing. This change handles the scenario where the gesture finishes before the animation even starts by slotting in a placeholder listener that just immediately finishes. If the animation has started but there was no motion, then it directly finishes the recents animation. Bug: 228898164 Test: open an app, tap on the bottom-bar. With logging it should be evident that the transition finishes. Change-Id: I27e00ceb4b21a2c37dc556bfecb4a90ef7155a85 --- .../OtherActivityInputConsumer.java | 37 ++++++++++++++++++- 1 file changed, 35 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java index dd459f5258..0bdc54ce54 100644 --- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java +++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java @@ -27,6 +27,7 @@ import static com.android.launcher3.PagedView.ACTION_MOVE_ALLOW_EASY_FLING; import static com.android.launcher3.PagedView.DEBUG_FAILED_QUICKSWITCH; import static com.android.launcher3.Utilities.EDGE_NAV_BAR; import static com.android.launcher3.Utilities.squaredHypot; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.TraceHelper.FLAG_CHECK_FOR_RACE_CONDITIONS; import static com.android.launcher3.util.VelocityUtils.PX_PER_MS; import static com.android.quickstep.util.ActiveGestureLog.INTENT_EXTRA_LOG_TRACE_ID; @@ -47,6 +48,7 @@ import android.view.ViewConfiguration; import androidx.annotation.UiThread; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.testing.TestLogging; import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.tracing.InputConsumerProto; @@ -58,7 +60,9 @@ import com.android.quickstep.BaseActivityInterface; import com.android.quickstep.GestureState; import com.android.quickstep.InputConsumer; import com.android.quickstep.RecentsAnimationCallbacks; +import com.android.quickstep.RecentsAnimationController; import com.android.quickstep.RecentsAnimationDeviceState; +import com.android.quickstep.RecentsAnimationTargets; import com.android.quickstep.RotationTouchHelper; import com.android.quickstep.TaskAnimationManager; import com.android.quickstep.util.ActiveGestureLog; @@ -104,6 +108,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC private VelocityTracker mVelocityTracker; private AbsSwipeUpHandler mInteractionHandler; + private final FinishImmediatelyHandler mCleanupHandler = new FinishImmediatelyHandler(); private final boolean mIsDeferredDownTarget; private final PointF mDownPos = new PointF(); @@ -373,6 +378,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC if (mTaskAnimationManager.isRecentsAnimationRunning()) { mActiveCallbacks = mTaskAnimationManager.continueRecentsAnimation(mGestureState); + mActiveCallbacks.removeListener(mCleanupHandler); mActiveCallbacks.addListener(mInteractionHandler); mTaskAnimationManager.notifyRecentsAnimationState(mInteractionHandler); notifyGestureStarted(true /*isLikelyToStartNewTask*/); @@ -410,7 +416,19 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } } else { // Since we start touch tracking on DOWN, we may reach this state without actually - // starting the gesture. In that case, just cleanup immediately. + // starting the gesture. In that case, we need to clean-up an unfinished or un-started + // animation. + if (mActiveCallbacks != null && mInteractionHandler != null) { + if (mTaskAnimationManager.isRecentsAnimationRunning()) { + // The animation started, but with no movement, in this case, there will be no + // animateToProgress so we have to manually finish here. + mTaskAnimationManager.finishRunningRecentsAnimation(false /* toHome */); + } else { + // The animation hasn't started yet, so insert a replacement handler into the + // callbacks which immediately finishes the animation after it starts. + mActiveCallbacks.addListener(mCleanupHandler); + } + } onConsumerAboutToBeSwitched(); onInteractionGestureFinished(); @@ -453,7 +471,7 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC } private void removeListener() { - if (mActiveCallbacks != null) { + if (mActiveCallbacks != null && mInteractionHandler != null) { mActiveCallbacks.removeListener(mInteractionHandler); } } @@ -479,4 +497,19 @@ public class OtherActivityInputConsumer extends ContextWrapper implements InputC mInteractionHandler.writeToProto(inputConsumerProto); } } + + /** + * A listener which just finishes the animation immediately after starting. Replaces + * AbsSwipeUpHandler if the gesture itself finishes before the animation even starts. + */ + private static class FinishImmediatelyHandler + implements RecentsAnimationCallbacks.RecentsAnimationListener { + + public void onRecentsAnimationStart(RecentsAnimationController controller, + RecentsAnimationTargets targets) { + Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), () -> { + controller.finish(false /* toRecents */, null); + }); + } + } }