Merge "Fix broken animation on two consecutive swipes." into tm-dev

This commit is contained in:
Shan Huang
2022-05-16 15:16:02 +00:00
committed by Android (Google) Code Review
2 changed files with 83 additions and 3 deletions

View File

@@ -67,8 +67,12 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
SETTING_VALUE_ON) != SETTING_VALUE_OFF;
private static final int PROGRESS_THRESHOLD = SystemProperties
.getInt(PREDICTIVE_BACK_PROGRESS_THRESHOLD_PROP, -1);
private final AtomicBoolean mEnableAnimations = new AtomicBoolean(false);
/**
* Max duration to wait for a transition to finish before accepting another gesture start
* request.
*/
private static final long MAX_TRANSITION_DURATION = 2000;
/**
* Location of the initial touch event of the back gesture.
@@ -84,6 +88,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
/** True when a back gesture is ongoing */
private boolean mBackGestureStarted = false;
/** Tracks if an uninterruptible transition is in progress */
private boolean mTransitionInProgress = false;
/** @see #setTriggerBack(boolean) */
private boolean mTriggerBack;
@@ -96,6 +102,10 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
private IOnBackInvokedCallback mBackToLauncherCallback;
private float mTriggerThreshold;
private float mProgressThreshold;
private final Runnable mResetTransitionRunnable = () -> {
finishAnimation();
mTransitionInProgress = false;
};
public BackAnimationController(
@NonNull @ShellMainThread ShellExecutor shellExecutor,
@@ -229,7 +239,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mBackToLauncherCallback = null;
}
private void onBackToLauncherAnimationFinished() {
@VisibleForTesting
void onBackToLauncherAnimationFinished() {
if (mBackNavigationInfo != null) {
IOnBackInvokedCallback callback = mBackNavigationInfo.getOnBackInvokedCallback();
if (mTriggerBack) {
@@ -246,6 +257,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
* {@link BackAnimationController}
*/
public void onMotionEvent(MotionEvent event, int action, @BackEvent.SwipeEdge int swipeEdge) {
if (mTransitionInProgress) {
return;
}
if (action == MotionEvent.ACTION_MOVE) {
if (!mBackGestureStarted) {
// Let the animation initialized here to make sure the onPointerDownOutsideFocus
@@ -370,6 +384,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
IOnBackInvokedCallback targetCallback = shouldDispatchToLauncher
? mBackToLauncherCallback
: mBackNavigationInfo.getOnBackInvokedCallback();
if (shouldDispatchToLauncher) {
startTransition();
}
if (mTriggerBack) {
dispatchOnBackInvoked(targetCallback);
} else {
@@ -436,6 +453,9 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
* Sets to true when the back gesture has passed the triggering threshold, false otherwise.
*/
public void setTriggerBack(boolean triggerBack) {
if (mTransitionInProgress) {
return;
}
mTriggerBack = triggerBack;
}
@@ -467,6 +487,23 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont
mTransaction.remove(screenshotSurface);
}
mTransaction.apply();
stopTransition();
backNavigationInfo.onBackNavigationFinished(triggerBack);
}
private void startTransition() {
if (mTransitionInProgress) {
return;
}
mTransitionInProgress = true;
mShellExecutor.executeDelayed(mResetTransitionRunnable, MAX_TRANSITION_DURATION);
}
private void stopTransition() {
if (!mTransitionInProgress) {
return;
}
mShellExecutor.removeCallbacks(mResetTransitionRunnable);
mTransitionInProgress = false;
}
}

View File

@@ -26,8 +26,10 @@ import static org.mockito.Mockito.atLeastOnce;
import static org.mockito.Mockito.doReturn;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import android.app.IActivityTaskManager;
import android.app.WindowConfiguration;
@@ -180,7 +182,8 @@ public class BackAnimationControllerTest {
// b/207481538, we check that the surface is not moved for now, we can re-enable this once
// we implement the animation
verify(mTransaction, never()).setScale(eq(screenshotSurface), anyInt(), anyInt());
verify(mTransaction, never()).setPosition(animationTarget.leash, 100, 100);
verify(mTransaction, never()).setPosition(
animationTarget.leash, 100, 100);
verify(mTransaction, atLeastOnce()).apply();
}
@@ -251,6 +254,46 @@ public class BackAnimationControllerTest {
verify(mIOnBackInvokedCallback, never()).onBackInvoked();
}
public void ignoresGesture_transitionInProgress() throws RemoteException {
mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
RemoteAnimationTarget animationTarget = createAnimationTarget();
createNavigationInfo(animationTarget, null, null,
BackNavigationInfo.TYPE_RETURN_TO_HOME, null);
triggerBackGesture();
// Check that back invocation is dispatched.
verify(mIOnBackInvokedCallback).onBackInvoked();
reset(mIOnBackInvokedCallback);
// Verify that we prevent animation from restarting if another gestures happens before
// the previous transition is finished.
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
verifyNoMoreInteractions(mIOnBackInvokedCallback);
// Verify that we start accepting gestures again once transition finishes.
mController.onBackToLauncherAnimationFinished();
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
doMotionEvent(MotionEvent.ACTION_MOVE, 100);
verify(mIOnBackInvokedCallback).onBackStarted();
}
@Test
public void acceptsGesture_transitionTimeout() throws RemoteException {
mController.setBackToLauncherCallback(mIOnBackInvokedCallback);
RemoteAnimationTarget animationTarget = createAnimationTarget();
createNavigationInfo(animationTarget, null, null,
BackNavigationInfo.TYPE_RETURN_TO_HOME, null);
triggerBackGesture();
reset(mIOnBackInvokedCallback);
// Simulate transition timeout.
mShellExecutor.flushAll();
doMotionEvent(MotionEvent.ACTION_DOWN, 0);
doMotionEvent(MotionEvent.ACTION_MOVE, 100);
verify(mIOnBackInvokedCallback).onBackStarted();
}
private void doMotionEvent(int actionDown, int coordinate) {
mController.onMotionEvent(
MotionEvent.obtain(0, mEventTime, actionDown, coordinate, coordinate, 0),