diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java index 1bbd3679948b5..163cf501734c1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTaskController.java @@ -61,6 +61,16 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { private TaskViewBase mTaskViewBase; private final Context mContext; + /** + * There could be a situation where we have task info and receive + * {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)}, however, the + * activity might fail to open, and in this case we need to clean up the task view / notify + * listeners of a task removal. This requires task info, so we save the info from onTaskAppeared + * in this situation to allow us to notify listeners correctly if the task failed to open. + */ + private ActivityManager.RunningTaskInfo mPendingInfo; + /* Indicates that the task we attempted to launch in the task view failed to launch. */ + private boolean mTaskNotFound; protected ActivityManager.RunningTaskInfo mTaskInfo; private WindowContainerToken mTaskToken; private SurfaceControl mTaskLeash; @@ -236,6 +246,8 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { mTaskInfo = null; mTaskToken = null; mTaskLeash = null; + mPendingInfo = null; + mTaskNotFound = false; } private void updateTaskVisibility() { @@ -257,6 +269,12 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { public void onTaskAppeared(ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash) { if (isUsingShellTransitions()) { + mPendingInfo = taskInfo; + if (mTaskNotFound) { + // If we were already notified by shell transit that we don't have the + // the task, clean it up now. + cleanUpPendingTask(); + } // Everything else handled by enter transition. return; } @@ -455,6 +473,42 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { return mTaskInfo; } + /** + * Indicates that the task was not found in the start animation for the transition. + * In this case we should clean up the task if we have the pending info. If we don't + * have the pending info, we'll do it when we receive it in + * {@link #onTaskAppeared(ActivityManager.RunningTaskInfo, SurfaceControl)}. + */ + void setTaskNotFound() { + mTaskNotFound = true; + if (mPendingInfo != null) { + cleanUpPendingTask(); + } + } + + /** + * Called when a task failed to open and we need to clean up task view / + * notify users of task view. + */ + void cleanUpPendingTask() { + if (mPendingInfo != null) { + if (mListener != null) { + final int taskId = mPendingInfo.taskId; + mListenerExecutor.execute(() -> { + mListener.onTaskRemovalStarted(taskId); + }); + } + mTaskViewBase.onTaskVanished(mPendingInfo); + mTaskOrganizer.setInterceptBackPressedOnTaskRoot(mPendingInfo.token, false); + + // Make sure the task is removed + WindowContainerTransaction wct = new WindowContainerTransaction(); + wct.removeTask(mPendingInfo.token); + mTaskViewTransitions.closeTaskView(wct, this); + } + resetTaskInfo(); + } + void prepareHideAnimation(@NonNull SurfaceControl.Transaction finishTransaction) { if (mTaskToken == null) { // Nothing to update, task is not yet available @@ -492,6 +546,7 @@ public class TaskViewTaskController implements ShellTaskOrganizer.TaskListener { @NonNull SurfaceControl.Transaction finishTransaction, ActivityManager.RunningTaskInfo taskInfo, SurfaceControl leash, WindowContainerTransaction wct) { + mPendingInfo = null; mTaskInfo = taskInfo; mTaskToken = mTaskInfo.token; mTaskLeash = leash; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java index 2e7fca3f2b469..5baf2e3202272 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/taskview/TaskViewTransitions.java @@ -139,7 +139,8 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { * `taskView`. * @param taskView the pending transition should be for this. */ - private PendingTransition findPendingOpeningTransition(TaskViewTaskController taskView) { + @VisibleForTesting + PendingTransition findPendingOpeningTransition(TaskViewTaskController taskView) { for (int i = mPending.size() - 1; i >= 0; --i) { if (mPending.get(i).mTaskView != taskView) continue; if (TransitionUtil.isOpeningType(mPending.get(i).mType)) { @@ -398,10 +399,11 @@ public class TaskViewTransitions implements Transitions.TransitionHandler { } } if (stillNeedsMatchingLaunch) { - throw new IllegalStateException("Expected a TaskView launch in this transition but" - + " didn't get one."); - } - if (wct == null && pending == null && changesHandled != info.getChanges().size()) { + Slog.w(TAG, "Expected a TaskView launch in this transition but didn't get one, " + + "cleaning up the task view"); + // Didn't find a task so the task must have never launched + pending.mTaskView.setTaskNotFound(); + } else if (wct == null && pending == null && changesHandled != info.getChanges().size()) { // Just some house-keeping, let another handler animate. return false; } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java index 81fc8438eec0b..1b389565c066b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTest.java @@ -128,8 +128,8 @@ public class TaskViewTest extends ShellTestCase { doReturn(true).when(mTransitions).isRegistered(); } mTaskViewTransitions = spy(new TaskViewTransitions(mTransitions)); - mTaskViewTaskController = new TaskViewTaskController(mContext, mOrganizer, - mTaskViewTransitions, mSyncQueue); + mTaskViewTaskController = spy(new TaskViewTaskController(mContext, mOrganizer, + mTaskViewTransitions, mSyncQueue)); mTaskView = new TaskView(mContext, mTaskViewTaskController); mTaskView.setListener(mExecutor, mViewListener); } @@ -544,4 +544,23 @@ public class TaskViewTest extends ShellTestCase { mTaskView.removeTask(); verify(mTaskViewTransitions).closeTaskView(any(), eq(mTaskViewTaskController)); } + + @Test + public void testOnTaskAppearedWithTaskNotFound() { + assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); + + mTaskViewTaskController.setTaskNotFound(); + mTaskViewTaskController.onTaskAppeared(mTaskInfo, mLeash); + + verify(mTaskViewTaskController).cleanUpPendingTask(); + verify(mTaskViewTransitions).closeTaskView(any(), eq(mTaskViewTaskController)); + } + + @Test + public void testOnTaskAppeared_withoutTaskNotFound() { + assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); + + mTaskViewTaskController.onTaskAppeared(mTaskInfo, mLeash); + verify(mTaskViewTaskController, never()).cleanUpPendingTask(); + } } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java index 71ad0d79eaca3..03ed18c866082 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/taskview/TaskViewTransitionsTest.java @@ -17,6 +17,7 @@ package com.android.wm.shell.taskview; import static android.view.WindowManager.TRANSIT_CHANGE; +import static android.view.WindowManager.TRANSIT_OPEN; import static android.view.WindowManager.TRANSIT_TO_FRONT; import static com.google.common.truth.Truth.assertThat; @@ -25,16 +26,19 @@ import static org.junit.Assume.assumeTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; import android.app.ActivityManager; import android.graphics.Rect; +import android.os.IBinder; import android.test.suitebuilder.annotation.SmallTest; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.SurfaceControl; import android.window.TransitionInfo; import android.window.WindowContainerToken; +import android.window.WindowContainerTransaction; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.transition.Transitions; @@ -45,6 +49,7 @@ import org.junit.runner.RunWith; import org.mockito.Mock; import org.mockito.MockitoAnnotations; +import java.util.ArrayList; import java.util.List; @SmallTest @@ -295,4 +300,34 @@ public class TaskViewTransitionsTest extends ShellTestCase { mTaskViewTransitions.setTaskBounds(mTaskViewTaskController, new Rect(0, 0, 100, 100)); } + + @Test + public void test_startAnimation_setsTaskNotFound() { + assumeTrue(Transitions.ENABLE_SHELL_TRANSITIONS); + + TransitionInfo.Change change = mock(TransitionInfo.Change.class); + when(change.getTaskInfo()).thenReturn(mTaskInfo); + when(change.getMode()).thenReturn(TRANSIT_OPEN); + + List changes = new ArrayList<>(); + changes.add(change); + + TransitionInfo info = mock(TransitionInfo.class); + when(info.getChanges()).thenReturn(changes); + + mTaskViewTransitions.startTaskView(new WindowContainerTransaction(), + mTaskViewTaskController, + mock(IBinder.class)); + + TaskViewTransitions.PendingTransition pending = + mTaskViewTransitions.findPendingOpeningTransition(mTaskViewTaskController); + + mTaskViewTransitions.startAnimation(pending.mClaimed, + info, + new SurfaceControl.Transaction(), + new SurfaceControl.Transaction(), + mock(Transitions.TransitionFinishCallback.class)); + + verify(mTaskViewTaskController).setTaskNotFound(); + } }