diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index 721907c21904b..3d37278cd4003 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -798,6 +798,22 @@ public class AppTransitionController { } } + /** + * Returns {@code true} if a given {@link WindowContainer} is an embedded Task. + * + * Note that this is a short term workaround to support Android Auto until it migrate to + * ShellTransition. This should only be used by {@link #getAnimationTargets}. + * + * TODO(b/213312721): Remove this predicate and its callers once ShellTransition is enabled. + */ + private static boolean isEmbeddedTask(WindowContainer wc) { + // We use Task#mRemoveWithTaskOrganizer to identify an embedded Task, but this is a hack and + // it is not guaranteed to work this logic in the future version. + return !WindowManagerService.sEnableShellTransitions + && wc instanceof Task + && ((Task) wc).mRemoveWithTaskOrganizer; + } + /** * Find WindowContainers to be animated from a set of opening and closing apps. We will promote * animation targets to higher level in the window hierarchy if possible. @@ -844,7 +860,13 @@ public class AppTransitionController { siblings.add(current); boolean canPromote = true; - if (parent == null || !parent.canCreateRemoteAnimationTarget() + if (isEmbeddedTask(current)) { + // Don't animate an embedded Task in app transition. This is a short term workaround + // to prevent conflict of surface hierarchy changes between legacy app transition + // and TaskView (b/205189147). + // TODO(b/213312721): Remove this once ShellTransition is enabled. + continue; + } else if (parent == null || !parent.canCreateRemoteAnimationTarget() || !parent.canBeAnimationTarget() // We cannot promote the animation on Task's parent when the task is in // clearing task in case the animating get stuck when performing the opening @@ -887,7 +909,13 @@ public class AppTransitionController { for (int j = 0; j < parent.getChildCount(); ++j) { final WindowContainer sibling = parent.getChildAt(j); if (candidates.remove(sibling)) { - siblings.add(sibling); + if (!isEmbeddedTask(sibling)) { + // Don't animate an embedded Task in app transition. This is a short + // term workaround to prevent conflict of surface hierarchy changes + // between legacy app transition and TaskView (b/205189147). + // TODO(b/213312721): Remove this once ShellTransition is enabled. + siblings.add(sibling); + } } else if (sibling != current && sibling.isVisible()) { canPromote = false; } diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java index 506270657e42f..0d6794685f09b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -678,6 +678,66 @@ public class AppTransitionControllerTest extends WindowTestsBase { opening, closing, false /* visible */)); } + @Test + public void testGetAnimationTargets_embeddedTask() { + // [DisplayContent] -+- [Task1] - [ActivityRecord1] (opening, invisible) + // +- [Task2] (embedded) - [ActivityRecord2] (opening, invisible) + final ActivityRecord activity1 = createActivityRecord(mDisplayContent); + activity1.setVisible(false); + activity1.mVisibleRequested = true; + + final Task task2 = createTask(mDisplayContent); + task2.mRemoveWithTaskOrganizer = true; + final ActivityRecord activity2 = createActivityRecord(task2); + activity2.setVisible(false); + activity2.mVisibleRequested = true; + + final ArraySet opening = new ArraySet<>(); + opening.add(activity1); + opening.add(activity2); + final ArraySet closing = new ArraySet<>(); + + // No animation on the embedded task. + assertEquals( + new ArraySet<>(new WindowContainer[]{activity1.getTask()}), + AppTransitionController.getAnimationTargets( + opening, closing, true /* visible */)); + assertEquals( + new ArraySet<>(), + AppTransitionController.getAnimationTargets( + opening, closing, false /* visible */)); + } + + + @Test + public void testGetAnimationTargets_activityInEmbeddedTask() { + // [DisplayContent] - [Task] (embedded)-+- [ActivityRecord1] (opening, invisible) + // +- [ActivityRecord2] (closing, visible) + final Task task = createTask(mDisplayContent); + task.mRemoveWithTaskOrganizer = true; + + final ActivityRecord activity1 = createActivityRecord(task); + activity1.setVisible(false); + activity1.mVisibleRequested = true; + final ActivityRecord activity2 = createActivityRecord(task); + + final ArraySet opening = new ArraySet<>(); + opening.add(activity1); + final ArraySet closing = new ArraySet<>(); + closing.add(activity2); + + // Even though embedded task itself doesn't animate, activities in an embedded task + // animate. + assertEquals( + new ArraySet<>(new WindowContainer[]{activity1}), + AppTransitionController.getAnimationTargets( + opening, closing, true /* visible */)); + assertEquals( + new ArraySet<>(new WindowContainer[]{activity2}), + AppTransitionController.getAnimationTargets( + opening, closing, false /* visible */)); + } + static class TestRemoteAnimationRunner implements IRemoteAnimationRunner { @Override public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,