From 9f3ce10ecebdacc26cf48affb3d0548a809ae95d Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 19 Apr 2023 06:47:41 +0000 Subject: [PATCH] Add a synchronous path when finishing a pre-existing recents animation - If launcher repeatedly starts the recents animation, we try to finish the existing animation before starting the new one, but due to some ordering issues (see b/275561141) the subsequent starts can orphan the previous animation runner, which can result in no animation callbacks for either the previous animation (to cancel) or the new animation (to start). This change only attempts to reduce the likelihood of a second no-op transition by synchronously finishing the existing recents animation on the launcher side prior to starting the next animation. There is one case this doesn't handle, where if the previous onAnimationStart() has not been called back, then we can't directly call the controller to finish, and need to rely on the no-op handling on the shell transition side to handle the gesture. Bug: 275561141 Test: Quickswitch and swipe up repeatedly Change-Id: I820e26dc20fb1851ee0102ed8c114ce998d44999 --- .../quickstep/RecentsAnimationController.java | 25 +++++++++++++------ .../quickstep/TaskAnimationManager.java | 21 +++++++++++++--- 2 files changed, 35 insertions(+), 11 deletions(-) diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationController.java b/quickstep/src/com/android/quickstep/RecentsAnimationController.java index 4adfae5ee8..f8e09e1e88 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationController.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationController.java @@ -150,10 +150,17 @@ public class RecentsAnimationController { @UiThread public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint) { - if (mFinishRequested) { - // If finishing, add to pending finish callbacks, otherwise, if finished, adding to the - // destroyed RunnableList will just trigger the callback to be called immediately - mPendingFinishCallbacks.add(callback); + finishController(toRecents, callback, sendUserLeaveHint, false /* forceFinish */); + } + + @UiThread + public void finishController(boolean toRecents, Runnable callback, boolean sendUserLeaveHint, + boolean forceFinish) { + mPendingFinishCallbacks.add(callback); + if (!forceFinish && mFinishRequested) { + // If finish has already been requested, then add the callback to the pending list. + // If already finished, then adding it to the destroyed RunnableList will just + // trigger the callback to be called immediately return; } ActiveGestureLog.INSTANCE.addLog( @@ -165,15 +172,19 @@ public class RecentsAnimationController { mFinishRequested = true; mFinishTargetIsLauncher = toRecents; mOnFinishedListener.accept(this); - mPendingFinishCallbacks.add(callback); - UI_HELPER_EXECUTOR.execute(() -> { + Runnable finishCb = () -> { mController.finish(toRecents, sendUserLeaveHint); InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_QUICK_SWITCH); InteractionJankMonitorWrapper.end(InteractionJankMonitorWrapper.CUJ_APP_CLOSE_TO_HOME); InteractionJankMonitorWrapper.end( InteractionJankMonitorWrapper.CUJ_APP_SWIPE_TO_RECENTS); MAIN_EXECUTOR.execute(mPendingFinishCallbacks::executeAllAndDestroy); - }); + }; + if (forceFinish) { + finishCb.run(); + } else { + UI_HELPER_EXECUTOR.execute(finishCb); + } } /** diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index c3c11977d3..c8c629233c 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -115,7 +115,7 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn } } // But force-finish it anyways - finishRunningRecentsAnimation(false /* toHome */); + finishRunningRecentsAnimation(false /* toHome */, true /* forceFinish */); if (mCallbacks != null) { // If mCallbacks still != null, that means we are getting this startRecentsAnimation() @@ -291,13 +291,26 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn * Finishes the running recents animation. */ public void finishRunningRecentsAnimation(boolean toHome) { + finishRunningRecentsAnimation(toHome, false /* forceFinish */); + } + + /** + * Finishes the running recents animation. + * @param forceFinish will synchronously finish the controller + */ + private void finishRunningRecentsAnimation(boolean toHome, boolean forceFinish) { if (mController != null) { ActiveGestureLog.INSTANCE.addLog( /* event= */ "finishRunningRecentsAnimation", toHome); mCallbacks.notifyAnimationCanceled(); - Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), toHome - ? mController::finishAnimationToHome - : mController::finishAnimationToApp); + if (forceFinish) { + mController.finishController(toHome, null, false /* sendUserLeaveHint */, + true /* forceFinish */); + } else { + Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), toHome + ? mController::finishAnimationToHome + : mController::finishAnimationToApp); + } cleanUpRecentsAnimation(); } }