diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java index dc7ed2459e..341353212b 100644 --- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java +++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java @@ -237,6 +237,8 @@ public abstract class AbsSwipeUpHandler< getNextStateFlag("STATE_SCALED_CONTROLLER_HOME"); private static final int STATE_SCALED_CONTROLLER_RECENTS = getNextStateFlag("STATE_SCALED_CONTROLLER_RECENTS"); + private static final int STATE_PARALLEL_ANIM_FINISHED = + getNextStateFlag("STATE_PARALLEL_ANIM_FINISHED"); protected static final int STATE_HANDLER_INVALIDATED = getNextStateFlag("STATE_HANDLER_INVALIDATED"); @@ -453,7 +455,8 @@ public abstract class AbsSwipeUpHandler< mStateCallback.runOnceAtState(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED | STATE_SCALED_CONTROLLER_HOME, this::finishCurrentTransitionToHome); - mStateCallback.runOnceAtState(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED, + mStateCallback.runOnceAtState(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED + | STATE_PARALLEL_ANIM_FINISHED, this::reset); mStateCallback.runOnceAtState(STATE_LAUNCHER_PRESENT | STATE_APP_CONTROLLER_RECEIVED @@ -1544,9 +1547,12 @@ public abstract class AbsSwipeUpHandler< @Override public void onAnimationEnd(Animator animation) { mParallelRunningAnim = null; + mStateCallback.setStateOnUiThread(STATE_PARALLEL_ANIM_FINISHED); } }); mParallelRunningAnim.start(); + } else { + mStateCallback.setStateOnUiThread(STATE_PARALLEL_ANIM_FINISHED); } } diff --git a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java index 3483723097..0bf988678b 100644 --- a/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java +++ b/quickstep/tests/multivalentTests/src/com/android/quickstep/AbsSwipeUpHandlerTestCase.java @@ -16,14 +16,22 @@ package com.android.quickstep; +import static com.android.quickstep.AbsSwipeUpHandler.STATE_HANDLER_INVALIDATED; + +import static junit.framework.TestCase.assertFalse; +import static junit.framework.TestCase.assertTrue; + import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.atLeast; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; +import android.animation.ValueAnimator; import android.app.ActivityManager; import android.content.Context; import android.content.Intent; @@ -55,6 +63,7 @@ import com.android.systemui.shared.system.InputConsumerController; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.MockitoJUnit; import org.mockito.junit.MockitoRule; @@ -209,7 +218,7 @@ public abstract class AbsSwipeUpHandlerTestCase< runOnMainSync(() -> { absSwipeUpHandler.startNewTask(unused -> {}); - verify(mRecentsAnimationController).finish(anyBoolean(), any()); + verifyRecentsAnimationFinishedAndCallCallback(); }); } @@ -219,10 +228,57 @@ public abstract class AbsSwipeUpHandlerTestCase< runOnMainSync(() -> { verify(mRecentsAnimationController).detachNavigationBarFromApp(true); - verify(mRecentsAnimationController).finish(anyBoolean(), any(), anyBoolean()); + verifyRecentsAnimationFinishedAndCallCallback(); }); } + @Test + public void testHomeGesture_invalidatesHandlerAfterParallelAnim() { + ValueAnimator parallelAnim = new ValueAnimator(); + parallelAnim.setRepeatCount(ValueAnimator.INFINITE); + when(mActivityInterface.getParallelAnimationToLauncher(any(), anyLong(), any())) + .thenReturn(parallelAnim); + SWIPE_HANDLER handler = createSwipeUpHandlerForGesture(GestureState.GestureEndTarget.HOME); + runOnMainSync(() -> { + parallelAnim.start(); + verifyRecentsAnimationFinishedAndCallCallback(); + assertFalse(handler.mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)); + parallelAnim.end(); + assertTrue(handler.mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)); + }); + } + + @Test + public void testHomeGesture_invalidatesHandlerIfNoParallelAnim() { + when(mActivityInterface.getParallelAnimationToLauncher(any(), anyLong(), any())) + .thenReturn(null); + SWIPE_HANDLER handler = createSwipeUpHandlerForGesture(GestureState.GestureEndTarget.HOME); + runOnMainSync(() -> { + verifyRecentsAnimationFinishedAndCallCallback(); + assertTrue(handler.mStateCallback.hasStates(STATE_HANDLER_INVALIDATED)); + }); + } + + /** + * Verifies that RecentsAnimationController#finish() is called, and captures and runs any + * callback that was passed to it. This ensures that STATE_CURRENT_TASK_FINISHED is correctly + * set for example. + */ + private void verifyRecentsAnimationFinishedAndCallCallback() { + ArgumentCaptor finishCallback = ArgumentCaptor.forClass(Runnable.class); + // Check if the 2 parameter method is called. + verify(mRecentsAnimationController, atLeast(0)).finish( + anyBoolean(), finishCallback.capture()); + if (finishCallback.getAllValues().isEmpty()) { + // Check if the 3 parameter method is called. + verify(mRecentsAnimationController).finish( + anyBoolean(), finishCallback.capture(), anyBoolean()); + } + if (finishCallback.getValue() != null) { + finishCallback.getValue().run(); + } + } + private SWIPE_HANDLER createSwipeUpHandlerForGesture(GestureState.GestureEndTarget endTarget) { boolean isQuickSwitch = endTarget == GestureState.GestureEndTarget.NEW_TASK;