summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Android Build Coastguard Worker <android-build-coastguard-worker@google.com> 2025-03-30 15:24:39 -0700
committer Android Build Coastguard Worker <android-build-coastguard-worker@google.com> 2025-03-30 15:24:39 -0700
commit327b059225338e22eb71055d3522f2bb05d3ab54 (patch)
treebb3991d7ab3b9ac0f1305d9ecf60075a371d6fdd
parentc2e92447b5f5af702ccae758f72ce25d5dce858f (diff)
parent7bccee01cb9c4708744fde8240ad1995807b1d75 (diff)
Merge cherrypicks of ['googleplex-android-review.googlesource.com/32746064'] into 25Q2-release.
Change-Id: I15675e16af122b2518412ac9d5f513ea65f0f369
-rw-r--r--quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java19
-rw-r--r--quickstep/src/com/android/quickstep/TaskAnimationManager.java42
-rw-r--r--quickstep/src_protolog/com/android/quickstep/util/ActiveGestureProtoLogProxy.java9
-rw-r--r--quickstep/tests/multivalentTests/src/com/android/quickstep/TaskAnimationManagerTest.java61
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);
}