Loading libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java +29 −6 Original line number Diff line number Diff line Loading @@ -816,6 +816,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV } // Prepare taskViews for animation boolean isReadyForAnimation = true; for (int i = 0; i < taskViews.size(); ++i) { final TransitionInfo.Change task = taskViews.get(i); final ActivityManager.RunningTaskInfo taskInfo = task.getTaskInfo(); Loading Loading @@ -849,11 +850,13 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV // The task is being moved into taskView, so it is still "new" from // TaskView's perspective (e.g. task being moved into a bubble) stillNeedsMatchingLaunch = false; prepareOpenAnimation(pending.mTaskView, true /* isNewInTaskView */, startTransaction, finishTransaction, taskInfo, leash, wct); isReadyForAnimation &= prepareOpenAnimation(pending.mTaskView, true /* isNewInTaskView */, startTransaction, finishTransaction, taskInfo, leash, wct); } else { prepareOpenAnimation(infoTv, false /* isNewInTaskView */, startTransaction, finishTransaction, taskInfo, leash, wct); isReadyForAnimation &= prepareOpenAnimation(infoTv, false /* isNewInTaskView */, startTransaction, finishTransaction, taskInfo, leash, wct); } break; case TRANSIT_CHANGE: Loading Loading @@ -910,6 +913,11 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV } else if (wct == null && pending == null && taskViews.size() != info.getChanges().size()) { // Just some house-keeping, let another handler animate. return false; } else if (!isReadyForAnimation) { // Animation could not be fully prepared. The surface for one or more TaskViews was // destroyed before the animation could start, let another handler animate. Slog.w(TAG, "Animation not ready for all TaskViews, deferring to another handler."); return false; } if (changingDisplayId > -1) { // Wait for setTaskBoundsInTransition -> mergeAnimation to let DefaultTransitionHandler Loading Loading @@ -1092,8 +1100,21 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV return true; } /** * Prepares the TaskView for an open animation. * * @param taskView the {@link TaskViewTaskController} for the TaskView being opened. * @param newTask whether the task is considered new within this {@link TaskView}. * @param startTransaction the transaction to apply before the animation starts. * @param finishTransaction the transaction to apply after the animation finishes. * @param taskInfo information about the running task to animate. * @param leash the surface leash representing the task's surface. * @param wct a {@link WindowContainerTransaction} to apply changes. * @return {@code true} if the TaskView's surface is created and ready for animation, * {@code false} if the surface was destroyed and the animation should be deferred. */ @VisibleForTesting public void prepareOpenAnimation(TaskViewTaskController taskView, public boolean prepareOpenAnimation(TaskViewTaskController taskView, final boolean newTask, SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction finishTransaction, Loading @@ -1102,7 +1123,8 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV final Rect boundsOnScreen = taskView.prepareOpen(taskInfo, leash); ProtoLog.d(WM_SHELL_BUBBLES_NOISY, "Transitions.prepareOpenAnimation(): taskView=%d " + "newTask=%b bounds=%s", taskView.hashCode(), newTask, boundsOnScreen); if (boundsOnScreen != null) { final boolean isSurfaceCreated = boundsOnScreen != null; if (isSurfaceCreated) { updateBounds(taskView, boundsOnScreen, startTransaction, finishTransaction, taskInfo, leash, wct); } else { Loading @@ -1126,6 +1148,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV wct.setTaskTrimmableFromRecents(taskInfo.token, false /* isTrimmableFromRecents */); taskView.notifyAppeared(newTask); return isSurfaceCreated; } /** Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionStartAnimationTest.java +48 −0 Original line number Diff line number Diff line Loading @@ -345,6 +345,21 @@ public class TaskViewTransitionStartAnimationTest extends ShellTestCase { prepareOpenAnimationAssertions(pending, wct, true /* newTask */, mTokenBinder); } @Test public void openTask_onlyAlienChanges_notHandled() { // Builds a transition with ONLY a non-TaskView change. final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN) .addChange(getTask(TRANSIT_OPEN, false /* registered */)) .build(); final boolean handled = mTaskViewTransitions.startAnimation( mock(IBinder.class), info, mStartTransaction, mFinishTransaction, mFinishCallback); assertWithMessage("Handler should not consume alien-only transition") .that(handled).isFalse(); verify(mFinishCallback, never()).onTransitionFinished(any()); } @Test public void showTaskViewHandled() { TaskViewTransitions.PendingTransition pending = Loading @@ -364,6 +379,23 @@ public class TaskViewTransitionStartAnimationTest extends ShellTestCase { prepareOpenAnimationAssertions(pending, wct, false /* newTask */, mTokenBinder); } @Test public void showTaskView_whenSurfaceDestroyed_notHandled() { assumeTrue(taskViewTransitionsRefactor()); // Simulate the surface being destroyed (e.g. a collapsed bubble being relaunched). when(mTaskViewTaskController.prepareOpen(any(), any())).thenReturn(null); final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT) .addChange(getTaskView(TRANSIT_TO_FRONT)).build(); final boolean handled = mTaskViewTransitions.startAnimation(mock(IBinder.class), info, mStartTransaction, mFinishTransaction, mFinishCallback); assertWithMessage("Handler should defer the transition when the surface is not ready") .that(handled).isFalse(); verify(mFinishCallback, never()).onTransitionFinished(any()); } @Test public void taskToTaskViewHandled() { assumeTrue(BubbleAnythingFlagHelper.enableCreateAnyBubble()); Loading Loading @@ -460,6 +492,22 @@ public class TaskViewTransitionStartAnimationTest extends ShellTestCase { verify(mTaskViewTaskController, never()).prepareCloseAnimation(); } @Test public void closingTask_withMixedChanges_notHandled() { // Builds a transition with both a TaskView change and a non-TaskView change. final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE) .addChange(getTaskView(TRANSIT_CLOSE)) .addChange(getTask(TRANSIT_TO_FRONT, false /* registered */)) .build(); final boolean handled = mTaskViewTransitions.startAnimation( mock(IBinder.class), info, mStartTransaction, mFinishTransaction, mFinishCallback); assertWithMessage("Handler should not consume mixed changes transition") .that(handled).isFalse(); verify(mFinishCallback, never()).onTransitionFinished(any()); } /** * Refactor tests on non-taskViews */ Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java +29 −6 Original line number Diff line number Diff line Loading @@ -816,6 +816,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV } // Prepare taskViews for animation boolean isReadyForAnimation = true; for (int i = 0; i < taskViews.size(); ++i) { final TransitionInfo.Change task = taskViews.get(i); final ActivityManager.RunningTaskInfo taskInfo = task.getTaskInfo(); Loading Loading @@ -849,11 +850,13 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV // The task is being moved into taskView, so it is still "new" from // TaskView's perspective (e.g. task being moved into a bubble) stillNeedsMatchingLaunch = false; prepareOpenAnimation(pending.mTaskView, true /* isNewInTaskView */, startTransaction, finishTransaction, taskInfo, leash, wct); isReadyForAnimation &= prepareOpenAnimation(pending.mTaskView, true /* isNewInTaskView */, startTransaction, finishTransaction, taskInfo, leash, wct); } else { prepareOpenAnimation(infoTv, false /* isNewInTaskView */, startTransaction, finishTransaction, taskInfo, leash, wct); isReadyForAnimation &= prepareOpenAnimation(infoTv, false /* isNewInTaskView */, startTransaction, finishTransaction, taskInfo, leash, wct); } break; case TRANSIT_CHANGE: Loading Loading @@ -910,6 +913,11 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV } else if (wct == null && pending == null && taskViews.size() != info.getChanges().size()) { // Just some house-keeping, let another handler animate. return false; } else if (!isReadyForAnimation) { // Animation could not be fully prepared. The surface for one or more TaskViews was // destroyed before the animation could start, let another handler animate. Slog.w(TAG, "Animation not ready for all TaskViews, deferring to another handler."); return false; } if (changingDisplayId > -1) { // Wait for setTaskBoundsInTransition -> mergeAnimation to let DefaultTransitionHandler Loading Loading @@ -1092,8 +1100,21 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV return true; } /** * Prepares the TaskView for an open animation. * * @param taskView the {@link TaskViewTaskController} for the TaskView being opened. * @param newTask whether the task is considered new within this {@link TaskView}. * @param startTransaction the transaction to apply before the animation starts. * @param finishTransaction the transaction to apply after the animation finishes. * @param taskInfo information about the running task to animate. * @param leash the surface leash representing the task's surface. * @param wct a {@link WindowContainerTransaction} to apply changes. * @return {@code true} if the TaskView's surface is created and ready for animation, * {@code false} if the surface was destroyed and the animation should be deferred. */ @VisibleForTesting public void prepareOpenAnimation(TaskViewTaskController taskView, public boolean prepareOpenAnimation(TaskViewTaskController taskView, final boolean newTask, SurfaceControl.Transaction startTransaction, SurfaceControl.Transaction finishTransaction, Loading @@ -1102,7 +1123,8 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV final Rect boundsOnScreen = taskView.prepareOpen(taskInfo, leash); ProtoLog.d(WM_SHELL_BUBBLES_NOISY, "Transitions.prepareOpenAnimation(): taskView=%d " + "newTask=%b bounds=%s", taskView.hashCode(), newTask, boundsOnScreen); if (boundsOnScreen != null) { final boolean isSurfaceCreated = boundsOnScreen != null; if (isSurfaceCreated) { updateBounds(taskView, boundsOnScreen, startTransaction, finishTransaction, taskInfo, leash, wct); } else { Loading @@ -1126,6 +1148,7 @@ public class TaskViewTransitions implements Transitions.TransitionHandler, TaskV wct.setTaskTrimmableFromRecents(taskInfo.token, false /* isTrimmableFromRecents */); taskView.notifyAppeared(newTask); return isSurfaceCreated; } /** Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionStartAnimationTest.java +48 −0 Original line number Diff line number Diff line Loading @@ -345,6 +345,21 @@ public class TaskViewTransitionStartAnimationTest extends ShellTestCase { prepareOpenAnimationAssertions(pending, wct, true /* newTask */, mTokenBinder); } @Test public void openTask_onlyAlienChanges_notHandled() { // Builds a transition with ONLY a non-TaskView change. final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_OPEN) .addChange(getTask(TRANSIT_OPEN, false /* registered */)) .build(); final boolean handled = mTaskViewTransitions.startAnimation( mock(IBinder.class), info, mStartTransaction, mFinishTransaction, mFinishCallback); assertWithMessage("Handler should not consume alien-only transition") .that(handled).isFalse(); verify(mFinishCallback, never()).onTransitionFinished(any()); } @Test public void showTaskViewHandled() { TaskViewTransitions.PendingTransition pending = Loading @@ -364,6 +379,23 @@ public class TaskViewTransitionStartAnimationTest extends ShellTestCase { prepareOpenAnimationAssertions(pending, wct, false /* newTask */, mTokenBinder); } @Test public void showTaskView_whenSurfaceDestroyed_notHandled() { assumeTrue(taskViewTransitionsRefactor()); // Simulate the surface being destroyed (e.g. a collapsed bubble being relaunched). when(mTaskViewTaskController.prepareOpen(any(), any())).thenReturn(null); final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_TO_FRONT) .addChange(getTaskView(TRANSIT_TO_FRONT)).build(); final boolean handled = mTaskViewTransitions.startAnimation(mock(IBinder.class), info, mStartTransaction, mFinishTransaction, mFinishCallback); assertWithMessage("Handler should defer the transition when the surface is not ready") .that(handled).isFalse(); verify(mFinishCallback, never()).onTransitionFinished(any()); } @Test public void taskToTaskViewHandled() { assumeTrue(BubbleAnythingFlagHelper.enableCreateAnyBubble()); Loading Loading @@ -460,6 +492,22 @@ public class TaskViewTransitionStartAnimationTest extends ShellTestCase { verify(mTaskViewTaskController, never()).prepareCloseAnimation(); } @Test public void closingTask_withMixedChanges_notHandled() { // Builds a transition with both a TaskView change and a non-TaskView change. final TransitionInfo info = new TransitionInfoBuilder(TRANSIT_CLOSE) .addChange(getTaskView(TRANSIT_CLOSE)) .addChange(getTask(TRANSIT_TO_FRONT, false /* registered */)) .build(); final boolean handled = mTaskViewTransitions.startAnimation( mock(IBinder.class), info, mStartTransaction, mFinishTransaction, mFinishCallback); assertWithMessage("Handler should not consume mixed changes transition") .that(handled).isFalse(); verify(mFinishCallback, never()).onTransitionFinished(any()); } /** * Refactor tests on non-taskViews */ Loading