diff options
author | 2025-03-30 15:24:39 -0700 | |
---|---|---|
committer | 2025-03-30 15:24:39 -0700 | |
commit | 327b059225338e22eb71055d3522f2bb05d3ab54 (patch) | |
tree | bb3991d7ab3b9ac0f1305d9ecf60075a371d6fdd | |
parent | c2e92447b5f5af702ccae758f72ce25d5dce858f (diff) | |
parent | 7bccee01cb9c4708744fde8240ad1995807b1d75 (diff) |
Merge cherrypicks of ['googleplex-android-review.googlesource.com/32746064'] into 25Q2-release.
Change-Id: I15675e16af122b2518412ac9d5f513ea65f0f369
4 files changed, 116 insertions, 15 deletions
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index 48630b11d3..f803709a46 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -221,15 +221,6 @@ public abstract class AbsSwipeUpHandler< // The previous task view type before the user quick switches between tasks private TaskViewType mPreviousTaskViewType; - private final Runnable mLauncherOnDestroyCallback = () -> { - ActiveGestureProtoLogProxy.logLauncherDestroyed(); - mRecentsView.removeOnScrollChangedListener(mOnRecentsScrollListener); - mRecentsView = null; - mContainer = null; - mStateCallback.clearState(STATE_LAUNCHER_PRESENT); - mRecentsAnimationStartCallbacks.clear(); - }; - private static int FLAG_COUNT = 0; private static int getNextStateFlag(String name) { if (DEBUG_STATES) { @@ -356,6 +347,16 @@ public abstract class AbsSwipeUpHandler< private final SwipePipToHomeAnimator[] mSwipePipToHomeAnimators = new SwipePipToHomeAnimator[2]; + private final Runnable mLauncherOnDestroyCallback = () -> { + ActiveGestureProtoLogProxy.logLauncherDestroyed(); + mRecentsView.removeOnScrollChangedListener(mOnRecentsScrollListener); + mRecentsView = null; + mContainer = null; + mStateCallback.clearState(STATE_LAUNCHER_PRESENT); + mRecentsAnimationStartCallbacks.clear(); + mTaskAnimationManager.onLauncherDestroyed(); + }; + // Interpolate RecentsView scale from start of quick switch scroll until this scroll threshold private final float mQuickSwitchScaleScrollThreshold; diff --git a/quickstep/src/com/android/quickstep/TaskAnimationManager.java b/quickstep/src/com/android/quickstep/TaskAnimationManager.java index cf0a3d570f..e552cd978b 100644 --- a/quickstep/src/com/android/quickstep/TaskAnimationManager.java +++ b/quickstep/src/com/android/quickstep/TaskAnimationManager.java @@ -425,22 +425,29 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn public void finishRunningRecentsAnimation(boolean toHome) { finishRunningRecentsAnimation(toHome, false /* forceFinish */, null /* forceFinishCb */); } + public void finishRunningRecentsAnimation( + boolean toHome, boolean forceFinish, Runnable forceFinishCb) { + finishRunningRecentsAnimation(toHome, forceFinish, forceFinishCb, mController); + } /** * Finishes the running recents animation. * @param forceFinish will synchronously finish the controller */ - public void finishRunningRecentsAnimation(boolean toHome, boolean forceFinish, - Runnable forceFinishCb) { - if (mController != null) { + public void finishRunningRecentsAnimation( + boolean toHome, + boolean forceFinish, + @Nullable Runnable forceFinishCb, + @Nullable RecentsAnimationController controller) { + if (controller != null) { ActiveGestureProtoLogProxy.logFinishRunningRecentsAnimation(toHome); if (forceFinish) { - mController.finishController(toHome, forceFinishCb, false /* sendUserLeaveHint */, + controller.finishController(toHome, forceFinishCb, false /* sendUserLeaveHint */, true /* forceFinish */); } else { Utilities.postAsyncCallback(MAIN_EXECUTOR.getHandler(), toHome - ? mController::finishAnimationToHome - : mController::finishAnimationToApp); + ? controller::finishAnimationToHome + : controller::finishAnimationToApp); } } } @@ -465,6 +472,29 @@ public class TaskAnimationManager implements RecentsAnimationCallbacks.RecentsAn return mController != null; } + void onLauncherDestroyed() { + if (!mRecentsAnimationStartPending) { + return; + } + if (mCallbacks == null) { + return; + } + ActiveGestureProtoLogProxy.logQueuingForceFinishRecentsAnimation(); + mCallbacks.addListener(new RecentsAnimationCallbacks.RecentsAnimationListener() { + @Override + public void onRecentsAnimationStart( + RecentsAnimationController controller, + RecentsAnimationTargets targets, + @Nullable TransitionInfo transitionInfo) { + finishRunningRecentsAnimation( + /* toHome= */ false, + /* forceFinish= */ true, + /* forceFinishCb= */ null, + controller); + } + }); + } + /** * Cleans up the recents animation entirely. */ diff --git a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java index 2532fcf8cf..1c8656c54b 100644 --- a/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java +++ b/quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java @@ -570,4 +570,13 @@ public class ActiveGestureProtoLogProxy { "OtherActivityInputConsumer.startTouchTrackingForWindowAnimation: " + "interactionHandler=%s", interactionHandler); } + + public static void logQueuingForceFinishRecentsAnimation() { + ActiveGestureLog.INSTANCE.addLog("Launcher destroyed while mRecentsAnimationStartPending ==" + + " true, queuing a callback to clean the pending animation up on start", + /* gestureEvent= */ ON_START_RECENTS_ANIMATION); + if (!enableActiveGestureProtoLog() || !isProtoLogInitialized()) return; + ProtoLog.d(ACTIVE_GESTURE_LOG, "Launcher destroyed while mRecentsAnimationStartPending ==" + + " true, queuing a callback to clean the pending animation up on start"); + } } diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java index fd88a5cb27..75b59d734a 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java @@ -19,19 +19,30 @@ package com.android.quickstep; import static org.junit.Assert.assertEquals; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; +import android.app.ActivityManager; import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; +import android.content.res.Configuration; +import android.graphics.Rect; +import android.os.Bundle; import android.view.Display; +import android.view.RemoteAnimationTarget; +import android.view.SurfaceControl; +import android.window.TransitionInfo; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.systemui.shared.system.RecentsAnimationControllerCompat; + import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; @@ -80,6 +91,56 @@ public class TaskAnimationManagerTest { optionsCaptor.getValue().getPendingIntentBackgroundActivityStartMode()); } + @Test + public void testLauncherDestroyed_whileRecentsAnimationStartPending_finishesAnimation() { + final GestureState gestureState = mock(GestureState.class); + final ArgumentCaptor<RecentsAnimationCallbacks> listenerCaptor = + ArgumentCaptor.forClass(RecentsAnimationCallbacks.class); + final RecentsAnimationControllerCompat controllerCompat = + mock(RecentsAnimationControllerCompat.class); + final RemoteAnimationTarget remoteAnimationTarget = new RemoteAnimationTarget( + /* taskId= */ 0, + /* mode= */ RemoteAnimationTarget.MODE_CLOSING, + /* leash= */ new SurfaceControl(), + /* isTranslucent= */ false, + /* clipRect= */ null, + /* contentInsets= */ null, + /* prefixOrderIndex= */ 0, + /* position= */ null, + /* localBounds= */ null, + /* screenSpaceBounds= */ null, + new Configuration().windowConfiguration, + /* isNotInRecents= */ false, + /* startLeash= */ null, + /* startBounds= */ null, + /* taskInfo= */ new ActivityManager.RunningTaskInfo(), + /* allowEnterPip= */ false); + + doReturn(mock(LauncherActivityInterface.class)).when(gestureState).getContainerInterface(); + when(mSystemUiProxy + .startRecentsActivity(any(), any(), listenerCaptor.capture(), anyBoolean())) + .thenReturn(true); + when(gestureState.getRunningTaskIds(anyBoolean())).thenReturn(new int[0]); + + runOnMainSync(() -> { + mTaskAnimationManager.startRecentsAnimation( + gestureState, + new Intent(), + mock(RecentsAnimationCallbacks.RecentsAnimationListener.class)); + mTaskAnimationManager.onLauncherDestroyed(); + listenerCaptor.getValue().onAnimationStart( + controllerCompat, + new RemoteAnimationTarget[] { remoteAnimationTarget }, + new RemoteAnimationTarget[] { remoteAnimationTarget }, + new Rect(), + new Rect(), + new Bundle(), + new TransitionInfo(0, 0)); + }); + runOnMainSync(() -> verify(controllerCompat) + .finish(/* toHome= */ eq(false), anyBoolean(), any())); + } + protected static void runOnMainSync(Runnable runnable) { InstrumentationRegistry.getInstrumentation().runOnMainSync(runnable); } |