Loading libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +8 −4 Original line number Diff line number Diff line Loading @@ -146,7 +146,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private final Handler mBgHandler; private final WindowManager mWindowManager; private final Transitions mTransitions; private final BackTransitionHandler mBackTransitionHandler; @VisibleForTesting final BackTransitionHandler mBackTransitionHandler; @VisibleForTesting final Rect mTouchableArea = new Rect(); Loading Loading @@ -174,7 +175,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont @Nullable private IOnBackInvokedCallback mActiveCallback; @Nullable private RemoteAnimationTarget[] mApps; @VisibleForTesting RemoteAnimationTarget[] mApps; @VisibleForTesting final RemoteCallback mNavigationObserver = new RemoteCallback( Loading Loading @@ -1448,7 +1450,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont * Check whether this transition is prepare for predictive back animation, which could * happen when core make an activity become visible. */ private boolean handlePrepareTransition( @VisibleForTesting boolean handlePrepareTransition( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction st, @NonNull SurfaceControl.Transaction ft, Loading Loading @@ -1491,7 +1494,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont * Check whether this transition is triggered from back gesture commitment. * Reparent the transition targets to animation leashes, so the animation won't be broken. */ private boolean handleCloseTransition(@NonNull TransitionInfo info, @VisibleForTesting boolean handleCloseTransition(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction st, @NonNull SurfaceControl.Transaction ft, @NonNull Transitions.TransitionFinishCallback finishCallback) { Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +215 −0 Original line number Diff line number Diff line Loading @@ -16,8 +16,19 @@ package com.android.wm.shell.back; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_CLOSE_PREPARE_BACK_NAVIGATION; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION; import static android.window.BackNavigationInfo.KEY_NAVIGATION_FINISHED; import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; Loading @@ -25,6 +36,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; 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.spy; Loading @@ -32,6 +44,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import android.app.ActivityManager; import android.app.IActivityTaskManager; import android.app.WindowConfiguration; import android.content.pm.ApplicationInfo; Loading @@ -40,6 +53,7 @@ import android.graphics.Rect; import android.hardware.input.InputManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; import android.provider.Settings; Loading @@ -51,11 +65,16 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.WindowManager; import android.window.BackEvent; import android.window.BackMotionEvent; import android.window.BackNavigationInfo; import android.window.IBackAnimationFinishedCallback; import android.window.IOnBackInvokedCallback; import android.window.IWindowContainerToken; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; import android.window.WindowContainerToken; import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; Loading Loading @@ -128,6 +147,8 @@ public class BackAnimationControllerTest extends ShellTestCase { private ShellBackAnimationRegistry mShellBackAnimationRegistry; private Rect mTouchableRegion; private BackAnimationController.BackTransitionHandler mBackTransitionHandler; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); Loading Loading @@ -165,6 +186,8 @@ public class BackAnimationControllerTest extends ShellTestCase { mShellExecutor.flushAll(); mTouchableRegion = new Rect(0, 0, 100, 100); mController.mTouchableArea.set(mTouchableRegion); mBackTransitionHandler = mController.mBackTransitionHandler; spyOn(mBackTransitionHandler); } private void createNavigationInfo(int backType, Loading Loading @@ -606,6 +629,198 @@ public class BackAnimationControllerTest extends ShellTestCase { mCrossTaskBackAnimation.getRunner()); } @Test public void testCloseAsExpectTransition() { final int openTaskId = 1; final int closeTaskId = 2; mController.mApps = createAppAnimationTargets(openTaskId, closeTaskId); final IBinder mockBinder = mock(IBinder.class); final SurfaceControl.Transaction st = mock(SurfaceControl.Transaction.class); final SurfaceControl.Transaction ft = mock(SurfaceControl.Transaction.class); // Single close final TransitionInfo.Change open = createAppChange(openTaskId, TRANSIT_OPEN, FLAG_BACK_GESTURE_ANIMATED | FLAG_MOVED_TO_TOP); final TransitionInfo.Change close = createAppChange(closeTaskId, TRANSIT_CLOSE, FLAG_BACK_GESTURE_ANIMATED); TransitionInfo tInfo = createTransitionInfo(TRANSIT_CLOSE, open, close); mBackTransitionHandler.mCloseTransitionRequested = true; Transitions.TransitionFinishCallback callback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.startAnimation(mockBinder, tInfo, st, ft, callback); verify(mBackTransitionHandler).handleCloseTransition( eq(tInfo), eq(st), eq(ft), eq(callback)); mBackTransitionHandler.onAnimationFinished(); verify(callback).onTransitionFinished(any()); mBackTransitionHandler.mCloseTransitionRequested = false; // PREPARE + CLOSE tInfo = createTransitionInfo(TRANSIT_PREPARE_BACK_NAVIGATION, open); callback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.startAnimation(mockBinder, tInfo, st, ft, callback); verify(mBackTransitionHandler).handlePrepareTransition( eq(tInfo), eq(st), eq(ft), eq(callback)); mBackTransitionHandler.mCloseTransitionRequested = true; TransitionInfo tInfo2 = createTransitionInfo(TRANSIT_CLOSE, close); Transitions.TransitionFinishCallback mergeCallback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.mergeAnimation( mock(IBinder.class), tInfo2, st, mock(IBinder.class), mergeCallback); mBackTransitionHandler.onAnimationFinished(); verify(callback).onTransitionFinished(any()); verify(mergeCallback).onTransitionFinished(any()); mBackTransitionHandler.mCloseTransitionRequested = false; // PREPARE contains close info tInfo = createTransitionInfo(TRANSIT_PREPARE_BACK_NAVIGATION, open, close); callback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.mCloseTransitionRequested = true; mBackTransitionHandler.startAnimation(mockBinder, tInfo, st, ft, callback); verify(mBackTransitionHandler).handleCloseTransition( eq(tInfo), eq(st), eq(ft), eq(callback)); mBackTransitionHandler.onAnimationFinished(); verify(callback).onTransitionFinished(any()); mBackTransitionHandler.mCloseTransitionRequested = false; // PREPARE then Cancel tInfo = createTransitionInfo(TRANSIT_PREPARE_BACK_NAVIGATION, open); callback = mock(Transitions.TransitionFinishCallback.class); final TransitionRequestInfo requestInfo = new TransitionRequestInfo( TRANSIT_PREPARE_BACK_NAVIGATION, null /* triggerTask */, null /* remoteTransition */); mBackTransitionHandler.handleRequest(mockBinder, requestInfo); mBackTransitionHandler.startAnimation(mockBinder, tInfo, st, ft, callback); verify(mBackTransitionHandler).handlePrepareTransition( eq(tInfo), eq(st), eq(ft), eq(callback)); final TransitionInfo.Change openToClose = createAppChange(openTaskId, TRANSIT_CLOSE, FLAG_BACK_GESTURE_ANIMATED); tInfo2 = createTransitionInfo(TRANSIT_CLOSE_PREPARE_BACK_NAVIGATION, openToClose); mBackTransitionHandler.mClosePrepareTransition = mock(IBinder.class); mergeCallback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.mergeAnimation(mBackTransitionHandler.mClosePrepareTransition, tInfo2, st, mock(IBinder.class), mergeCallback); assertTrue("Change should be consumed", tInfo2.getChanges().isEmpty()); mBackTransitionHandler.onAnimationFinished(); verify(callback).onTransitionFinished(any()); } @Test public void testCancelUnexpectedTransition() { final int openTaskId = 1; final int closeTaskId = 2; mController.mApps = createAppAnimationTargets(openTaskId, closeTaskId); final IBinder mockBinder = mock(IBinder.class); final SurfaceControl.Transaction st = mock(SurfaceControl.Transaction.class); final SurfaceControl.Transaction ft = mock(SurfaceControl.Transaction.class); final TransitionInfo.Change open = createAppChange(openTaskId, TRANSIT_OPEN, FLAG_BACK_GESTURE_ANIMATED | FLAG_MOVED_TO_TOP); final TransitionInfo.Change close = createAppChange(closeTaskId, TRANSIT_CLOSE, FLAG_BACK_GESTURE_ANIMATED); // Didn't trigger close transition mBackTransitionHandler.mCloseTransitionRequested = false; TransitionInfo prepareInfo = createTransitionInfo(TRANSIT_PREPARE_BACK_NAVIGATION, open, close); final Transitions.TransitionFinishCallback callback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.handleRequest(mockBinder, mock(TransitionRequestInfo.class)); boolean canHandle = mBackTransitionHandler.startAnimation( mockBinder, prepareInfo, st, ft, callback); assertFalse("Should not handle transition", canHandle); assertNull(mBackTransitionHandler.mOnAnimationFinishCallback); // Didn't trigger close transition, but receive close target. final TransitionRequestInfo requestInfo = new TransitionRequestInfo( TRANSIT_PREPARE_BACK_NAVIGATION, null /* triggerTask */, null /* remoteTransition */); prepareInfo = createTransitionInfo(TRANSIT_PREPARE_BACK_NAVIGATION, open); final Transitions.TransitionFinishCallback callback2 = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.handleRequest(mockBinder, requestInfo); canHandle = mBackTransitionHandler.startAnimation(mockBinder, prepareInfo, st, ft, callback2); assertTrue("Handle prepare transition" , canHandle); verify(mBackTransitionHandler).handlePrepareTransition( eq(prepareInfo), eq(st), eq(ft), eq(callback2)); final TransitionInfo closeInfo = createTransitionInfo(TRANSIT_CLOSE, close); Transitions.TransitionFinishCallback mergeCallback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.mergeAnimation(mock(IBinder.class), closeInfo, ft, mock(IBinder.class), mergeCallback); verify(callback2).onTransitionFinished(any()); verify(mergeCallback, never()).onTransitionFinished(any()); // Didn't trigger close transition, but contains open target. final int openTaskId2 = 3; final Transitions.TransitionFinishCallback callback3 = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.handleRequest(mockBinder, requestInfo); canHandle = mBackTransitionHandler.startAnimation( mockBinder, prepareInfo, st, ft, callback3); assertTrue("Handle prepare transition" , canHandle); verify(mBackTransitionHandler).handlePrepareTransition( eq(prepareInfo), eq(st), eq(ft), eq(callback3)); final TransitionInfo.Change open2 = createAppChange( openTaskId2, TRANSIT_OPEN, FLAG_MOVED_TO_TOP); final TransitionInfo openInfo = createTransitionInfo(TRANSIT_OPEN, open2, close); mergeCallback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.mergeAnimation(mock(IBinder.class), openInfo, ft, mock(IBinder.class), mergeCallback); verify(callback3).onTransitionFinished(any()); verify(mergeCallback, never()).onTransitionFinished(any()); } private RemoteAnimationTarget[] createAppAnimationTargets(int openTaskId, int closeTaskId) { final RemoteAnimationTarget openT = createSingleAnimationTarget(openTaskId, RemoteAnimationTarget.MODE_OPENING); final RemoteAnimationTarget closeT = createSingleAnimationTarget(closeTaskId, RemoteAnimationTarget.MODE_CLOSING); return new RemoteAnimationTarget[]{openT, closeT}; } private RemoteAnimationTarget createSingleAnimationTarget(int taskId, int mode) { final Rect fakeR = new Rect(); final Point fakeP = new Point(); final ActivityManager.RunningTaskInfo openTaskInfo = new ActivityManager.RunningTaskInfo(); openTaskInfo.taskId = taskId; openTaskInfo.token = new WindowContainerToken(mock(IWindowContainerToken.class)); return new RemoteAnimationTarget( taskId, mode, mock(SurfaceControl.class), false, fakeR, fakeR, 0, fakeP, fakeR, fakeR, new WindowConfiguration(), false, mock(SurfaceControl.class), fakeR, openTaskInfo, false); } private TransitionInfo.Change createAppChange( int taskId, @TransitionInfo.TransitionMode int mode, @TransitionInfo.ChangeFlags int flags) { final TransitionInfo.Change change; SurfaceControl.Builder b = new SurfaceControl.Builder() .setName("test task"); if (taskId != INVALID_TASK_ID) { final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); taskInfo.taskId = taskId; taskInfo.token = new WindowContainerToken(mock(IWindowContainerToken.class)); change = new TransitionInfo.Change( taskInfo.token, b.build()); change.setTaskInfo(taskInfo); } else { change = new TransitionInfo.Change( null, b.build()); } change.setMode(mode); change.setFlags(flags); return change; } private static TransitionInfo createTransitionInfo( @WindowManager.TransitionType int type, TransitionInfo.Change ... changes) { final TransitionInfo info = new TransitionInfo(type, 0); for (int i = 0; i < changes.length; ++i) { info.addChange(changes[i]); } return info; } private void verifySystemBackBehavior(int type, BackAnimationRunner animation) throws RemoteException { final BackAnimationRunner animationRunner = spy(animation); Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java +8 −4 Original line number Diff line number Diff line Loading @@ -146,7 +146,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont private final Handler mBgHandler; private final WindowManager mWindowManager; private final Transitions mTransitions; private final BackTransitionHandler mBackTransitionHandler; @VisibleForTesting final BackTransitionHandler mBackTransitionHandler; @VisibleForTesting final Rect mTouchableArea = new Rect(); Loading Loading @@ -174,7 +175,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont @Nullable private IOnBackInvokedCallback mActiveCallback; @Nullable private RemoteAnimationTarget[] mApps; @VisibleForTesting RemoteAnimationTarget[] mApps; @VisibleForTesting final RemoteCallback mNavigationObserver = new RemoteCallback( Loading Loading @@ -1448,7 +1450,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont * Check whether this transition is prepare for predictive back animation, which could * happen when core make an activity become visible. */ private boolean handlePrepareTransition( @VisibleForTesting boolean handlePrepareTransition( @NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction st, @NonNull SurfaceControl.Transaction ft, Loading Loading @@ -1491,7 +1494,8 @@ public class BackAnimationController implements RemoteCallable<BackAnimationCont * Check whether this transition is triggered from back gesture commitment. * Reparent the transition targets to animation leashes, so the animation won't be broken. */ private boolean handleCloseTransition(@NonNull TransitionInfo info, @VisibleForTesting boolean handleCloseTransition(@NonNull TransitionInfo info, @NonNull SurfaceControl.Transaction st, @NonNull SurfaceControl.Transaction ft, @NonNull Transitions.TransitionFinishCallback finishCallback) { Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/back/BackAnimationControllerTest.java +215 −0 Original line number Diff line number Diff line Loading @@ -16,8 +16,19 @@ package com.android.wm.shell.back; import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static android.view.WindowManager.TRANSIT_CLOSE; import static android.view.WindowManager.TRANSIT_CLOSE_PREPARE_BACK_NAVIGATION; import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_PREPARE_BACK_NAVIGATION; import static android.window.BackNavigationInfo.KEY_NAVIGATION_FINISHED; import static android.window.TransitionInfo.FLAG_BACK_GESTURE_ANIMATED; import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyInt; Loading @@ -25,6 +36,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.doNothing; 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.spy; Loading @@ -32,6 +44,7 @@ import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.verifyNoMoreInteractions; import android.app.ActivityManager; import android.app.IActivityTaskManager; import android.app.WindowConfiguration; import android.content.pm.ApplicationInfo; Loading @@ -40,6 +53,7 @@ import android.graphics.Rect; import android.hardware.input.InputManager; import android.os.Bundle; import android.os.Handler; import android.os.IBinder; import android.os.RemoteCallback; import android.os.RemoteException; import android.provider.Settings; Loading @@ -51,11 +65,16 @@ import android.view.KeyEvent; import android.view.MotionEvent; import android.view.RemoteAnimationTarget; import android.view.SurfaceControl; import android.view.WindowManager; import android.window.BackEvent; import android.window.BackMotionEvent; import android.window.BackNavigationInfo; import android.window.IBackAnimationFinishedCallback; import android.window.IOnBackInvokedCallback; import android.window.IWindowContainerToken; import android.window.TransitionInfo; import android.window.TransitionRequestInfo; import android.window.WindowContainerToken; import androidx.annotation.Nullable; import androidx.test.filters.SmallTest; Loading Loading @@ -128,6 +147,8 @@ public class BackAnimationControllerTest extends ShellTestCase { private ShellBackAnimationRegistry mShellBackAnimationRegistry; private Rect mTouchableRegion; private BackAnimationController.BackTransitionHandler mBackTransitionHandler; @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); Loading Loading @@ -165,6 +186,8 @@ public class BackAnimationControllerTest extends ShellTestCase { mShellExecutor.flushAll(); mTouchableRegion = new Rect(0, 0, 100, 100); mController.mTouchableArea.set(mTouchableRegion); mBackTransitionHandler = mController.mBackTransitionHandler; spyOn(mBackTransitionHandler); } private void createNavigationInfo(int backType, Loading Loading @@ -606,6 +629,198 @@ public class BackAnimationControllerTest extends ShellTestCase { mCrossTaskBackAnimation.getRunner()); } @Test public void testCloseAsExpectTransition() { final int openTaskId = 1; final int closeTaskId = 2; mController.mApps = createAppAnimationTargets(openTaskId, closeTaskId); final IBinder mockBinder = mock(IBinder.class); final SurfaceControl.Transaction st = mock(SurfaceControl.Transaction.class); final SurfaceControl.Transaction ft = mock(SurfaceControl.Transaction.class); // Single close final TransitionInfo.Change open = createAppChange(openTaskId, TRANSIT_OPEN, FLAG_BACK_GESTURE_ANIMATED | FLAG_MOVED_TO_TOP); final TransitionInfo.Change close = createAppChange(closeTaskId, TRANSIT_CLOSE, FLAG_BACK_GESTURE_ANIMATED); TransitionInfo tInfo = createTransitionInfo(TRANSIT_CLOSE, open, close); mBackTransitionHandler.mCloseTransitionRequested = true; Transitions.TransitionFinishCallback callback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.startAnimation(mockBinder, tInfo, st, ft, callback); verify(mBackTransitionHandler).handleCloseTransition( eq(tInfo), eq(st), eq(ft), eq(callback)); mBackTransitionHandler.onAnimationFinished(); verify(callback).onTransitionFinished(any()); mBackTransitionHandler.mCloseTransitionRequested = false; // PREPARE + CLOSE tInfo = createTransitionInfo(TRANSIT_PREPARE_BACK_NAVIGATION, open); callback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.startAnimation(mockBinder, tInfo, st, ft, callback); verify(mBackTransitionHandler).handlePrepareTransition( eq(tInfo), eq(st), eq(ft), eq(callback)); mBackTransitionHandler.mCloseTransitionRequested = true; TransitionInfo tInfo2 = createTransitionInfo(TRANSIT_CLOSE, close); Transitions.TransitionFinishCallback mergeCallback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.mergeAnimation( mock(IBinder.class), tInfo2, st, mock(IBinder.class), mergeCallback); mBackTransitionHandler.onAnimationFinished(); verify(callback).onTransitionFinished(any()); verify(mergeCallback).onTransitionFinished(any()); mBackTransitionHandler.mCloseTransitionRequested = false; // PREPARE contains close info tInfo = createTransitionInfo(TRANSIT_PREPARE_BACK_NAVIGATION, open, close); callback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.mCloseTransitionRequested = true; mBackTransitionHandler.startAnimation(mockBinder, tInfo, st, ft, callback); verify(mBackTransitionHandler).handleCloseTransition( eq(tInfo), eq(st), eq(ft), eq(callback)); mBackTransitionHandler.onAnimationFinished(); verify(callback).onTransitionFinished(any()); mBackTransitionHandler.mCloseTransitionRequested = false; // PREPARE then Cancel tInfo = createTransitionInfo(TRANSIT_PREPARE_BACK_NAVIGATION, open); callback = mock(Transitions.TransitionFinishCallback.class); final TransitionRequestInfo requestInfo = new TransitionRequestInfo( TRANSIT_PREPARE_BACK_NAVIGATION, null /* triggerTask */, null /* remoteTransition */); mBackTransitionHandler.handleRequest(mockBinder, requestInfo); mBackTransitionHandler.startAnimation(mockBinder, tInfo, st, ft, callback); verify(mBackTransitionHandler).handlePrepareTransition( eq(tInfo), eq(st), eq(ft), eq(callback)); final TransitionInfo.Change openToClose = createAppChange(openTaskId, TRANSIT_CLOSE, FLAG_BACK_GESTURE_ANIMATED); tInfo2 = createTransitionInfo(TRANSIT_CLOSE_PREPARE_BACK_NAVIGATION, openToClose); mBackTransitionHandler.mClosePrepareTransition = mock(IBinder.class); mergeCallback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.mergeAnimation(mBackTransitionHandler.mClosePrepareTransition, tInfo2, st, mock(IBinder.class), mergeCallback); assertTrue("Change should be consumed", tInfo2.getChanges().isEmpty()); mBackTransitionHandler.onAnimationFinished(); verify(callback).onTransitionFinished(any()); } @Test public void testCancelUnexpectedTransition() { final int openTaskId = 1; final int closeTaskId = 2; mController.mApps = createAppAnimationTargets(openTaskId, closeTaskId); final IBinder mockBinder = mock(IBinder.class); final SurfaceControl.Transaction st = mock(SurfaceControl.Transaction.class); final SurfaceControl.Transaction ft = mock(SurfaceControl.Transaction.class); final TransitionInfo.Change open = createAppChange(openTaskId, TRANSIT_OPEN, FLAG_BACK_GESTURE_ANIMATED | FLAG_MOVED_TO_TOP); final TransitionInfo.Change close = createAppChange(closeTaskId, TRANSIT_CLOSE, FLAG_BACK_GESTURE_ANIMATED); // Didn't trigger close transition mBackTransitionHandler.mCloseTransitionRequested = false; TransitionInfo prepareInfo = createTransitionInfo(TRANSIT_PREPARE_BACK_NAVIGATION, open, close); final Transitions.TransitionFinishCallback callback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.handleRequest(mockBinder, mock(TransitionRequestInfo.class)); boolean canHandle = mBackTransitionHandler.startAnimation( mockBinder, prepareInfo, st, ft, callback); assertFalse("Should not handle transition", canHandle); assertNull(mBackTransitionHandler.mOnAnimationFinishCallback); // Didn't trigger close transition, but receive close target. final TransitionRequestInfo requestInfo = new TransitionRequestInfo( TRANSIT_PREPARE_BACK_NAVIGATION, null /* triggerTask */, null /* remoteTransition */); prepareInfo = createTransitionInfo(TRANSIT_PREPARE_BACK_NAVIGATION, open); final Transitions.TransitionFinishCallback callback2 = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.handleRequest(mockBinder, requestInfo); canHandle = mBackTransitionHandler.startAnimation(mockBinder, prepareInfo, st, ft, callback2); assertTrue("Handle prepare transition" , canHandle); verify(mBackTransitionHandler).handlePrepareTransition( eq(prepareInfo), eq(st), eq(ft), eq(callback2)); final TransitionInfo closeInfo = createTransitionInfo(TRANSIT_CLOSE, close); Transitions.TransitionFinishCallback mergeCallback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.mergeAnimation(mock(IBinder.class), closeInfo, ft, mock(IBinder.class), mergeCallback); verify(callback2).onTransitionFinished(any()); verify(mergeCallback, never()).onTransitionFinished(any()); // Didn't trigger close transition, but contains open target. final int openTaskId2 = 3; final Transitions.TransitionFinishCallback callback3 = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.handleRequest(mockBinder, requestInfo); canHandle = mBackTransitionHandler.startAnimation( mockBinder, prepareInfo, st, ft, callback3); assertTrue("Handle prepare transition" , canHandle); verify(mBackTransitionHandler).handlePrepareTransition( eq(prepareInfo), eq(st), eq(ft), eq(callback3)); final TransitionInfo.Change open2 = createAppChange( openTaskId2, TRANSIT_OPEN, FLAG_MOVED_TO_TOP); final TransitionInfo openInfo = createTransitionInfo(TRANSIT_OPEN, open2, close); mergeCallback = mock(Transitions.TransitionFinishCallback.class); mBackTransitionHandler.mergeAnimation(mock(IBinder.class), openInfo, ft, mock(IBinder.class), mergeCallback); verify(callback3).onTransitionFinished(any()); verify(mergeCallback, never()).onTransitionFinished(any()); } private RemoteAnimationTarget[] createAppAnimationTargets(int openTaskId, int closeTaskId) { final RemoteAnimationTarget openT = createSingleAnimationTarget(openTaskId, RemoteAnimationTarget.MODE_OPENING); final RemoteAnimationTarget closeT = createSingleAnimationTarget(closeTaskId, RemoteAnimationTarget.MODE_CLOSING); return new RemoteAnimationTarget[]{openT, closeT}; } private RemoteAnimationTarget createSingleAnimationTarget(int taskId, int mode) { final Rect fakeR = new Rect(); final Point fakeP = new Point(); final ActivityManager.RunningTaskInfo openTaskInfo = new ActivityManager.RunningTaskInfo(); openTaskInfo.taskId = taskId; openTaskInfo.token = new WindowContainerToken(mock(IWindowContainerToken.class)); return new RemoteAnimationTarget( taskId, mode, mock(SurfaceControl.class), false, fakeR, fakeR, 0, fakeP, fakeR, fakeR, new WindowConfiguration(), false, mock(SurfaceControl.class), fakeR, openTaskInfo, false); } private TransitionInfo.Change createAppChange( int taskId, @TransitionInfo.TransitionMode int mode, @TransitionInfo.ChangeFlags int flags) { final TransitionInfo.Change change; SurfaceControl.Builder b = new SurfaceControl.Builder() .setName("test task"); if (taskId != INVALID_TASK_ID) { final ActivityManager.RunningTaskInfo taskInfo = new ActivityManager.RunningTaskInfo(); taskInfo.taskId = taskId; taskInfo.token = new WindowContainerToken(mock(IWindowContainerToken.class)); change = new TransitionInfo.Change( taskInfo.token, b.build()); change.setTaskInfo(taskInfo); } else { change = new TransitionInfo.Change( null, b.build()); } change.setMode(mode); change.setFlags(flags); return change; } private static TransitionInfo createTransitionInfo( @WindowManager.TransitionType int type, TransitionInfo.Change ... changes) { final TransitionInfo info = new TransitionInfo(type, 0); for (int i = 0; i < changes.length; ++i) { info.addChange(changes[i]); } return info; } private void verifySystemBackBehavior(int type, BackAnimationRunner animation) throws RemoteException { final BackAnimationRunner animationRunner = spy(animation); Loading