diff options
18 files changed, 445 insertions, 69 deletions
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java index 9b3550477aaa..329ea4a02145 100644 --- a/core/java/android/view/WindowManager.java +++ b/core/java/android/view/WindowManager.java @@ -320,6 +320,19 @@ public interface WindowManager extends ViewManager { int TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE = 27; /** + * A window in a new task fragment is being opened. + * @hide + */ + int TRANSIT_OLD_TASK_FRAGMENT_OPEN = 28; + + /** + * A window in the top-most activity of task fragment is being closed to reveal the activity + * below. + * @hide + */ + int TRANSIT_OLD_TASK_FRAGMENT_CLOSE = 29; + + /** * @hide */ @IntDef(prefix = { "TRANSIT_OLD_" }, value = { @@ -344,7 +357,9 @@ public interface WindowManager extends ViewManager { TRANSIT_OLD_TRANSLUCENT_ACTIVITY_OPEN, TRANSIT_OLD_TRANSLUCENT_ACTIVITY_CLOSE, TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE, - TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE + TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE, + TRANSIT_OLD_TASK_FRAGMENT_OPEN, + TRANSIT_OLD_TASK_FRAGMENT_CLOSE }) @Retention(RetentionPolicy.SOURCE) @interface TransitionOldType {} diff --git a/services/core/java/com/android/server/wm/AccessibilityController.java b/services/core/java/com/android/server/wm/AccessibilityController.java index f1644e9cfa5a..a4d2348d03f1 100644 --- a/services/core/java/com/android/server/wm/AccessibilityController.java +++ b/services/core/java/com/android/server/wm/AccessibilityController.java @@ -756,6 +756,7 @@ final class AccessibilityController { if (magnifying) { switch (transition) { case WindowManager.TRANSIT_OLD_ACTIVITY_OPEN: + case WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN: case WindowManager.TRANSIT_OLD_TASK_OPEN: case WindowManager.TRANSIT_OLD_TASK_TO_FRONT: case WindowManager.TRANSIT_OLD_WALLPAPER_OPEN: diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java index 174b3965f11a..6aea848b12f7 100644 --- a/services/core/java/com/android/server/wm/AppTransition.java +++ b/services/core/java/com/android/server/wm/AppTransition.java @@ -40,6 +40,8 @@ import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE; import static android.view.WindowManager.TRANSIT_OLD_NONE; import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; +import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; +import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_BACK; @@ -1005,6 +1007,21 @@ public class AppTransition implements Dump { animAttr = enter ? WindowAnimation_launchTaskBehindSourceAnimation : WindowAnimation_launchTaskBehindTargetAnimation; + break; + // TODO(b/189386466): Use activity transition as the fallback. Investigate if we + // need new TaskFragment transition. + case TRANSIT_OLD_TASK_FRAGMENT_OPEN: + animAttr = enter + ? WindowAnimation_activityOpenEnterAnimation + : WindowAnimation_activityOpenExitAnimation; + break; + // TODO(b/189386466): Use activity transition as the fallback. Investigate if we + // need new TaskFragment transition. + case TRANSIT_OLD_TASK_FRAGMENT_CLOSE: + animAttr = enter + ? WindowAnimation_activityCloseEnterAnimation + : WindowAnimation_activityCloseExitAnimation; + break; } a = animAttr != 0 ? loadAnimationAttr(lp, animAttr, transit) : null; ProtoLog.v(WM_DEBUG_APP_TRANSITIONS_ANIM, @@ -1315,6 +1332,12 @@ public class AppTransition implements Dump { case TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE: { return "TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE"; } + case TRANSIT_OLD_TASK_FRAGMENT_OPEN: { + return "TRANSIT_OLD_TASK_FRAGMENT_OPEN"; + } + case TRANSIT_OLD_TASK_FRAGMENT_CLOSE: { + return "TRANSIT_OLD_TASK_FRAGMENT_CLOSE"; + } default: { return "<UNKNOWN: " + transition + ">"; } diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java index d6b0086d8dd9..eeadabde1476 100644 --- a/services/core/java/com/android/server/wm/AppTransitionController.java +++ b/services/core/java/com/android/server/wm/AppTransitionController.java @@ -39,6 +39,8 @@ import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE; import static android.view.WindowManager.TRANSIT_OLD_NONE; import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE; import static android.view.WindowManager.TRANSIT_OLD_TASK_CLOSE; +import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; +import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN; import static android.view.WindowManager.TRANSIT_OLD_TASK_OPEN_BEHIND; import static android.view.WindowManager.TRANSIT_OLD_TASK_TO_BACK; @@ -68,6 +70,7 @@ import static com.android.server.wm.WindowManagerDebugConfig.SHOW_LIGHT_TRANSACT import static com.android.server.wm.WindowManagerDebugConfig.TAG_WITH_CLASS_NAME; import static com.android.server.wm.WindowManagerDebugConfig.TAG_WM; +import android.annotation.IntDef; import android.annotation.Nullable; import android.os.Trace; import android.util.ArrayMap; @@ -86,6 +89,8 @@ import android.view.animation.Animation; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; import java.util.ArrayList; import java.util.LinkedList; import java.util.function.Predicate; @@ -102,6 +107,20 @@ public class AppTransitionController { private RemoteAnimationDefinition mRemoteAnimationDefinition = null; private static final int KEYGUARD_GOING_AWAY_ANIMATION_DURATION = 400; + private static final int TYPE_NONE = 0; + private static final int TYPE_ACTIVITY = 1; + private static final int TYPE_TASK_FRAGMENT = 2; + private static final int TYPE_TASK = 3; + + @IntDef(prefix = { "TYPE_" }, value = { + TYPE_NONE, + TYPE_ACTIVITY, + TYPE_TASK_FRAGMENT, + TYPE_TASK + }) + @Retention(RetentionPolicy.SOURCE) + @interface TransitContainerType {} + private final ArrayMap<WindowContainer, Integer> mTempTransitionReasons = new ArrayMap<>(); AppTransitionController(WindowManagerService service, DisplayContent displayContent) { @@ -387,33 +406,38 @@ public class AppTransitionController { openingApps, closingApps, true /* visible */); final ArraySet<WindowContainer> closingWcs = getAnimationTargets( openingApps, closingApps, false /* visible */); - final boolean isActivityOpening = !openingWcs.isEmpty() - && openingWcs.valueAt(0).asActivityRecord() != null; - final boolean isActivityClosing = !closingWcs.isEmpty() - && closingWcs.valueAt(0).asActivityRecord() != null; - final boolean isTaskOpening = !openingWcs.isEmpty() && !isActivityOpening; - final boolean isTaskClosing = !closingWcs.isEmpty() && !isActivityClosing; - - if (appTransition.containsTransitRequest(TRANSIT_TO_FRONT) && isTaskOpening) { + final WindowContainer<?> openingContainer = !openingWcs.isEmpty() + ? openingWcs.valueAt(0) : null; + final WindowContainer<?> closingContainer = !closingWcs.isEmpty() + ? closingWcs.valueAt(0) : null; + @TransitContainerType int openingType = getTransitContainerType(openingContainer); + @TransitContainerType int closingType = getTransitContainerType(closingContainer); + if (appTransition.containsTransitRequest(TRANSIT_TO_FRONT) && openingType == TYPE_TASK) { return TRANSIT_OLD_TASK_TO_FRONT; } - if (appTransition.containsTransitRequest(TRANSIT_TO_BACK) && isTaskClosing) { + if (appTransition.containsTransitRequest(TRANSIT_TO_BACK) && closingType == TYPE_TASK) { return TRANSIT_OLD_TASK_TO_BACK; } if (appTransition.containsTransitRequest(TRANSIT_OPEN)) { - if (isTaskOpening) { + if (openingType == TYPE_TASK) { return (appTransition.getTransitFlags() & TRANSIT_FLAG_OPEN_BEHIND) != 0 ? TRANSIT_OLD_TASK_OPEN_BEHIND : TRANSIT_OLD_TASK_OPEN; } - if (isActivityOpening) { + if (openingType == TYPE_ACTIVITY) { return TRANSIT_OLD_ACTIVITY_OPEN; } + if (openingType == TYPE_TASK_FRAGMENT) { + return TRANSIT_OLD_TASK_FRAGMENT_OPEN; + } } if (appTransition.containsTransitRequest(TRANSIT_CLOSE)) { - if (isTaskClosing) { + if (closingType == TYPE_TASK) { return TRANSIT_OLD_TASK_CLOSE; } - if (isActivityClosing) { + if (closingType == TYPE_TASK_FRAGMENT) { + return TRANSIT_OLD_TASK_FRAGMENT_CLOSE; + } + if (closingType == TYPE_ACTIVITY) { for (int i = closingApps.size() - 1; i >= 0; i--) { if (closingApps.valueAt(i).visibleIgnoringKeyguard) { return TRANSIT_OLD_ACTIVITY_CLOSE; @@ -430,6 +454,23 @@ public class AppTransitionController { return TRANSIT_OLD_NONE; } + @TransitContainerType + private static int getTransitContainerType(@Nullable WindowContainer<?> container) { + if (container == null) { + return TYPE_NONE; + } + if (container.asTask() != null) { + return TYPE_TASK; + } + if (container.asTaskFragment() != null) { + return TYPE_TASK_FRAGMENT; + } + if (container.asActivityRecord() != null) { + return TYPE_ACTIVITY; + } + return TYPE_NONE; + } + private static WindowManager.LayoutParams getAnimLp(ActivityRecord activity) { final WindowState mainWindow = activity != null ? activity.findMainWindow() : null; return mainWindow != null ? mainWindow.mAttrs : null; diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 9ca09d20cd49..b35f74876eeb 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -218,7 +218,7 @@ public class ActivityRecordTests extends WindowTestsBase { public void testNoCleanupMovingActivityInSameStack() { final ActivityRecord activity = createActivityWith2LevelTask(); final Task rootTask = activity.getRootTask(); - final Task newTask = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask).build(); + final Task newTask = createTaskInRootTask(rootTask, 0 /* userId */); activity.reparent(newTask, 0, null /*reason*/); verify(rootTask, times(0)).cleanUpActivityReferences(any()); } diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java index 1b4d0a4ab5a4..3e8a2e9b7b17 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java @@ -478,7 +478,7 @@ public class ActivityStarterTests extends WindowTestsBase { final ActivityRecord splitSecondActivity = new ActivityBuilder(mAtm).setCreateTask(true).build(); final ActivityRecord splitPrimaryActivity = new TaskBuilder(mSupervisor) - .setParentTask(splitOrg.mPrimary) + .setParentTaskFragment(splitOrg.mPrimary) .setCreateActivity(true) .build() .getTopMostActivity(); @@ -856,7 +856,7 @@ public class ActivityStarterTests extends WindowTestsBase { // Create another activity on top of the secondary display. final Task topStack = secondaryTaskContainer.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); - final Task topTask = new TaskBuilder(mSupervisor).setParentTask(topStack).build(); + final Task topTask = new TaskBuilder(mSupervisor).setParentTaskFragment(topStack).build(); new ActivityBuilder(mAtm).setTask(topTask).build(); doReturn(mActivityMetricsLogger).when(mSupervisor).getActivityMetricsLogger(); @@ -920,7 +920,7 @@ public class ActivityStarterTests extends WindowTestsBase { DEFAULT_COMPONENT_PACKAGE_NAME + ".SingleTaskActivity"); final Task task = new TaskBuilder(mSupervisor) .setComponent(componentName) - .setParentTask(stack) + .setParentTaskFragment(stack) .build(); return new ActivityBuilder(mAtm) .setComponent(componentName) @@ -1056,8 +1056,8 @@ public class ActivityStarterTests extends WindowTestsBase { final ActivityStarter starter = prepareStarter(0 /* flags */); starter.mStartActivity = new ActivityBuilder(mAtm).build(); final Task task = new TaskBuilder(mAtm.mTaskSupervisor) - .setParentTask(mAtm.mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask( - WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */)) + .setParentTaskFragment(createTask(mDisplayContent, WINDOWING_MODE_FULLSCREEN, + ACTIVITY_TYPE_STANDARD)) .setUserId(10) .build(); 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 3a6aac9d03d5..11e3fd4e050a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionControllerTest.java @@ -375,7 +375,7 @@ public class AppTransitionControllerTest extends WindowTestsBase { final ArraySet<ActivityRecord> closing = new ArraySet<>(); closing.add(activity3); - // Promote animation targets to TaskStack level. Invisible ActivityRecords don't affect + // Promote animation targets to root Task level. Invisible ActivityRecords don't affect // promotion decision. assertEquals( new ArraySet<>(new WindowContainer[]{activity1.getRootTask()}), @@ -520,6 +520,128 @@ public class AppTransitionControllerTest extends WindowTestsBase { opening, closing, false /* visible */)); } + @Test + public void testGetAnimationTargets_openingClosingTaskFragment() { + // [DefaultTDA] - [Task] -+- [TaskFragment1] - [ActivityRecord1] (opening, invisible) + // +- [TaskFragment2] - [ActivityRecord2] (closing, visible) + final Task parentTask = createTask(mDisplayContent); + final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(parentTask, + false /* createEmbeddedTask */); + final ActivityRecord activity1 = taskFragment1.getTopMostActivity(); + activity1.setVisible(false); + activity1.mVisibleRequested = true; + + final TaskFragment taskFragment2 = createTaskFragmentWithParentTask(parentTask, + false /* createEmbeddedTask */); + final ActivityRecord activity2 = taskFragment2.getTopMostActivity(); + activity2.setVisible(true); + activity2.mVisibleRequested = false; + + final ArraySet<ActivityRecord> opening = new ArraySet<>(); + opening.add(activity1); + final ArraySet<ActivityRecord> closing = new ArraySet<>(); + closing.add(activity2); + + // Promote animation targets up to TaskFragment level, not beyond. + assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment1}), + AppTransitionController.getAnimationTargets( + opening, closing, true /* visible */)); + assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment2}), + AppTransitionController.getAnimationTargets( + opening, closing, false /* visible */)); + } + + @Test + public void testGetAnimationTargets_openingClosingTaskFragmentWithEmbeddedTask() { + // [DefaultTDA] - [Task] -+- [TaskFragment1] - [ActivityRecord1] (opening, invisible) + // +- [TaskFragment2] - [ActivityRecord2] (closing, visible) + final Task parentTask = createTask(mDisplayContent); + final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(parentTask, + true /* createEmbeddedTask */); + final ActivityRecord activity1 = taskFragment1.getTopMostActivity(); + activity1.setVisible(false); + activity1.mVisibleRequested = true; + + final TaskFragment taskFragment2 = createTaskFragmentWithParentTask(parentTask, + true /* createEmbeddedTask */); + final ActivityRecord activity2 = taskFragment2.getTopMostActivity(); + activity2.setVisible(true); + activity2.mVisibleRequested = false; + + final ArraySet<ActivityRecord> opening = new ArraySet<>(); + opening.add(activity1); + final ArraySet<ActivityRecord> closing = new ArraySet<>(); + closing.add(activity2); + + // Promote animation targets up to TaskFragment level, not beyond. + assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment1}), + AppTransitionController.getAnimationTargets( + opening, closing, true /* visible */)); + assertEquals(new ArraySet<>(new WindowContainer[]{taskFragment2}), + AppTransitionController.getAnimationTargets( + opening, closing, false /* visible */)); + } + + @Test + public void testGetAnimationTargets_openingTheOnlyTaskFragmentInTask() { + // [DefaultTDA] -+- [Task1] - [TaskFragment1] - [ActivityRecord1] (opening, invisible) + // +- [Task2] - [ActivityRecord2] (closing, visible) + final Task task1 = createTask(mDisplayContent); + final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(task1, + false /* createEmbeddedTask */); + final ActivityRecord activity1 = taskFragment1.getTopMostActivity(); + activity1.setVisible(false); + activity1.mVisibleRequested = true; + + final ActivityRecord activity2 = createActivityRecord(mDisplayContent); + activity2.setVisible(true); + activity2.mVisibleRequested = false; + + final ArraySet<ActivityRecord> opening = new ArraySet<>(); + opening.add(activity1); + final ArraySet<ActivityRecord> closing = new ArraySet<>(); + closing.add(activity2); + + // Promote animation targets up to leaf Task level because there's only one TaskFragment in + // the Task. + assertEquals(new ArraySet<>(new WindowContainer[]{task1}), + AppTransitionController.getAnimationTargets( + opening, closing, true /* visible */)); + assertEquals(new ArraySet<>(new WindowContainer[]{activity2.getTask()}), + AppTransitionController.getAnimationTargets( + opening, closing, false /* visible */)); + } + + @Test + public void testGetAnimationTargets_closingTheOnlyTaskFragmentInTask() { + // [DefaultTDA] -+- [Task1] - [TaskFragment1] - [ActivityRecord1] (closing, visible) + // +- [Task2] - [ActivityRecord2] (opening, invisible) + final Task task1 = createTask(mDisplayContent); + final TaskFragment taskFragment1 = createTaskFragmentWithParentTask(task1, + false /* createEmbeddedTask */); + final ActivityRecord activity1 = taskFragment1.getTopMostActivity(); + activity1.setVisible(true); + activity1.mVisibleRequested = false; + + final ActivityRecord activity2 = createActivityRecord(mDisplayContent); + activity2.setVisible(false); + activity2.mVisibleRequested = true; + + final ArraySet<ActivityRecord> opening = new ArraySet<>(); + opening.add(activity2); + final ArraySet<ActivityRecord> closing = new ArraySet<>(); + closing.add(activity1); + + // Promote animation targets up to leaf Task level because there's only one TaskFragment in + // the Task. + assertEquals(new ArraySet<>(new WindowContainer[]{activity2.getTask()}), + AppTransitionController.getAnimationTargets( + opening, closing, true /* visible */)); + assertEquals(new ArraySet<>(new WindowContainer[]{task1}), + AppTransitionController.getAnimationTargets( + opening, closing, false /* visible */)); + } + static class TestRemoteAnimationRunner implements IRemoteAnimationRunner { @Override public void onAnimationStart(int transit, RemoteAnimationTarget[] apps, diff --git a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java index c3279bf05737..67aac13e3734 100644 --- a/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/AppTransitionTests.java @@ -23,6 +23,8 @@ import static android.view.WindowManager.TRANSIT_FLAG_APP_CRASHED; import static android.view.WindowManager.TRANSIT_KEYGUARD_GOING_AWAY; import static android.view.WindowManager.TRANSIT_OLD_CRASHING_ACTIVITY_CLOSE; import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY; +import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_CLOSE; +import static android.view.WindowManager.TRANSIT_OLD_TASK_FRAGMENT_OPEN; import static android.view.WindowManager.TRANSIT_OLD_UNSET; import static android.view.WindowManager.TRANSIT_OPEN; @@ -40,6 +42,7 @@ import static org.mockito.ArgumentMatchers.any; import android.os.IBinder; import android.os.RemoteException; import android.platform.test.annotations.Presubmit; +import android.util.ArraySet; import android.view.Display; import android.view.IRemoteAnimationFinishedCallback; import android.view.IRemoteAnimationRunner; @@ -147,6 +150,91 @@ public class AppTransitionTests extends WindowTestsBase { } @Test + public void testTaskFragmentOpeningTransition() { + final ActivityRecord activity = createHierarchyForTaskFragmentTest( + false /* createEmbeddedTask */); + activity.setVisible(false); + + mDisplayContent.prepareAppTransition(TRANSIT_OPEN); + mDisplayContent.mOpeningApps.add(activity); + assertEquals(TRANSIT_OLD_TASK_FRAGMENT_OPEN, + AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, + mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, + null /* wallpaperTarget */, null /* oldWallpaper */, + false /* skipAppTransitionAnimation */)); + } + + @Test + public void testEmbeddedTaskOpeningTransition() { + final ActivityRecord activity = createHierarchyForTaskFragmentTest( + true /* createEmbeddedTask */); + activity.setVisible(false); + + mDisplayContent.prepareAppTransition(TRANSIT_OPEN); + mDisplayContent.mOpeningApps.add(activity); + assertEquals(TRANSIT_OLD_TASK_FRAGMENT_OPEN, + AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, + mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, + null /* wallpaperTarget */, null /* oldWallpaper */, + false /* skipAppTransitionAnimation */)); + } + + @Test + public void testTaskFragmentClosingTransition() { + final ActivityRecord activity = createHierarchyForTaskFragmentTest( + false /* createEmbeddedTask */); + activity.setVisible(true); + + mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); + mDisplayContent.mClosingApps.add(activity); + assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, + AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, + mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, + null /* wallpaperTarget */, null /* oldWallpaper */, + false /* skipAppTransitionAnimation */)); + } + + @Test + public void testEmbeddedTaskClosingTransition() { + final ActivityRecord activity = createHierarchyForTaskFragmentTest( + true /* createEmbeddedTask */); + activity.setVisible(true); + + mDisplayContent.prepareAppTransition(TRANSIT_CLOSE); + mDisplayContent.mClosingApps.add(activity); + assertEquals(TRANSIT_OLD_TASK_FRAGMENT_CLOSE, + AppTransitionController.getTransitCompatType(mDisplayContent.mAppTransition, + mDisplayContent.mOpeningApps, mDisplayContent.mClosingApps, + null /* wallpaperTarget */, null /* oldWallpaper */, + false /* skipAppTransitionAnimation */)); + } + + /** + * Creates a {@link Task} with two {@link TaskFragment TaskFragments}. + * The bottom TaskFragment is to prevent + * {@link AppTransitionController#getAnimationTargets(ArraySet, ArraySet, boolean) the animation + * target} to promote to Task or above. + * + * @param createEmbeddedTask {@code true} to create embedded Task for verified TaskFragment + * @return The Activity to be put in either opening or closing Activity + */ + private ActivityRecord createHierarchyForTaskFragmentTest(boolean createEmbeddedTask) { + final Task parentTask = createTask(mDisplayContent); + final TaskFragment bottomTaskFragment = createTaskFragmentWithParentTask(parentTask, + false /* createEmbeddedTask */); + final ActivityRecord bottomActivity = bottomTaskFragment.getTopMostActivity(); + bottomActivity.setOccludesParent(true); + bottomActivity.setVisible(true); + + final TaskFragment verifiedTaskFragment = createTaskFragmentWithParentTask(parentTask, + createEmbeddedTask); + final ActivityRecord activity = verifiedTaskFragment.getTopMostActivity(); + activity.setOccludesParent(true); + + return activity; + } + + @Test public void testAppTransitionStateForMultiDisplay() { // Create 2 displays & presume both display the state is ON for ready to display & animate. final DisplayContent dc1 = createNewDisplay(Display.STATE_ON); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java index 473d3038e3dc..14dc33e5840b 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayContentTests.java @@ -2352,10 +2352,10 @@ public class DisplayContentTests extends WindowTestsBase { ACTIVITY_TYPE_STANDARD, ON_TOP); final Task rootTask4 = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, ON_TOP); - final Task task1 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask1).build(); - final Task task2 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask2).build(); - final Task task3 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask3).build(); - final Task task4 = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(rootTask4).build(); + final Task task1 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask1).build(); + final Task task2 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask2).build(); + final Task task3 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask3).build(); + final Task task4 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask4).build(); // Reordering root tasks while removing root tasks. doAnswer(invocation -> { diff --git a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java index 7cb7c79d63a0..8a6db2c62a10 100644 --- a/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/LaunchParamsPersisterTests.java @@ -117,7 +117,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase { Task rootTask = mTestDisplay.getDefaultTaskDisplayArea() .createRootTask(TEST_WINDOWING_MODE, ACTIVITY_TYPE_STANDARD, /* onTop */ true); mTestTask = new TaskBuilder(mSupervisor).setComponent(TEST_COMPONENT) - .setParentTask(rootTask).build(); + .setParentTaskFragment(rootTask).build(); mTestTask.mUserId = TEST_USER_ID; mTestTask.mLastNonFullscreenBounds = TEST_BOUNDS; mTestTask.setHasBeenVisible(true); @@ -353,7 +353,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase { final Task anotherTaskOfTheSameUser = new TaskBuilder(mSupervisor) .setComponent(ALTERNATIVE_COMPONENT) .setUserId(TEST_USER_ID) - .setParentTask(stack) + .setParentTaskFragment(stack) .build(); anotherTaskOfTheSameUser.setWindowingMode(WINDOWING_MODE_FREEFORM); anotherTaskOfTheSameUser.setBounds(200, 300, 400, 500); @@ -365,7 +365,7 @@ public class LaunchParamsPersisterTests extends WindowTestsBase { final Task anotherTaskOfDifferentUser = new TaskBuilder(mSupervisor) .setComponent(TEST_COMPONENT) .setUserId(ALTERNATIVE_USER_ID) - .setParentTask(stack) + .setParentTaskFragment(stack) .build(); anotherTaskOfDifferentUser.setWindowingMode(WINDOWING_MODE_FREEFORM); anotherTaskOfDifferentUser.setBounds(300, 400, 500, 600); diff --git a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java index 1b078b7454b2..22e687a0bb15 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RecentTasksTest.java @@ -331,7 +331,7 @@ public class RecentTasksTest extends WindowTestsBase { // other task Task task1 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) - .setParentTask(mTaskContainer.getRootHomeTask()).build(); + .setParentTaskFragment(mTaskContainer.getRootHomeTask()).build(); Task task2 = createTaskBuilder(".Task1") .setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_MULTIPLE_TASK) .build(); @@ -471,8 +471,8 @@ public class RecentTasksTest extends WindowTestsBase { final Task root = createTaskBuilder(".CreatedByOrganizerRoot").build(); root.mCreatedByOrganizer = true; // Add organized and non-organized child. - final Task child1 = createTaskBuilder(".Task1").setParentTask(root).build(); - final Task child2 = createTaskBuilder(".Task2").setParentTask(root).build(); + final Task child1 = createTaskBuilder(".Task1").setParentTaskFragment(root).build(); + final Task child2 = createTaskBuilder(".Task2").setParentTaskFragment(root).build(); doReturn(true).when(child1).isOrganized(); doReturn(false).when(child2).isOrganized(); mRecentTasks.add(root); @@ -508,7 +508,8 @@ public class RecentTasksTest extends WindowTestsBase { // tasks because their intents are identical. mRecentTasks.add(task1); // Go home to trigger the removal of untracked tasks. - mRecentTasks.add(createTaskBuilder(".Home").setParentTask(mTaskContainer.getRootHomeTask()) + mRecentTasks.add(createTaskBuilder(".Home") + .setParentTaskFragment(mTaskContainer.getRootHomeTask()) .build()); triggerIdleToTrim(); @@ -675,7 +676,7 @@ public class RecentTasksTest extends WindowTestsBase { public void testVisibleTasks_excludedFromRecents_firstTaskNotVisible() { // Create some set of tasks, some of which are visible and some are not Task homeTask = createTaskBuilder("com.android.pkg1", ".HomeTask") - .setParentTask(mTaskContainer.getRootHomeTask()) + .setParentTaskFragment(mTaskContainer.getRootHomeTask()) .build(); homeTask.mUserSetupComplete = true; mRecentTasks.add(homeTask); @@ -696,7 +697,7 @@ public class RecentTasksTest extends WindowTestsBase { t1.mUserSetupComplete = true; mRecentTasks.add(t1); Task homeTask = createTaskBuilder("com.android.pkg1", ".HomeTask") - .setParentTask(mTaskContainer.getRootHomeTask()) + .setParentTaskFragment(mTaskContainer.getRootHomeTask()) .build(); homeTask.mUserSetupComplete = true; mRecentTasks.add(homeTask); @@ -949,10 +950,10 @@ public class RecentTasksTest extends WindowTestsBase { // Add a number of tasks (beyond the max) but ensure that nothing is trimmed because all // the tasks belong in stacks above the home stack - mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build()); - mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(aboveHomeStack).build()); - mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(aboveHomeStack).build()); - mRecentTasks.add(createTaskBuilder(".Task3").setParentTask(aboveHomeStack).build()); + mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTaskFragment(homeStack).build()); + mRecentTasks.add(createTaskBuilder(".Task1").setParentTaskFragment(aboveHomeStack).build()); + mRecentTasks.add(createTaskBuilder(".Task2").setParentTaskFragment(aboveHomeStack).build()); + mRecentTasks.add(createTaskBuilder(".Task3").setParentTaskFragment(aboveHomeStack).build()); triggerTrimAndAssertNoTasksTrimmed(); } @@ -970,11 +971,11 @@ public class RecentTasksTest extends WindowTestsBase { // Add a number of tasks (beyond the max) but ensure that only the task in the stack behind // the home stack is trimmed once a new task is added final Task behindHomeTask = createTaskBuilder(".Task1") - .setParentTask(behindHomeStack) + .setParentTaskFragment(behindHomeStack) .build(); mRecentTasks.add(behindHomeTask); - mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeStack).build()); - mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(aboveHomeStack).build()); + mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTaskFragment(homeStack).build()); + mRecentTasks.add(createTaskBuilder(".Task2").setParentTaskFragment(aboveHomeStack).build()); triggerTrimAndAssertTrimmed(behindHomeTask); } @@ -990,10 +991,12 @@ public class RecentTasksTest extends WindowTestsBase { // Add a number of tasks (beyond the max) on each display, ensure that the tasks are not // removed - mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTask(homeTask).build()); - mRecentTasks.add(createTaskBuilder(".Task1").setParentTask(otherDisplayRootTask).build()); - mRecentTasks.add(createTaskBuilder(".Task2").setParentTask(otherDisplayRootTask).build()); - mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTask(homeTask).build()); + mRecentTasks.add(createTaskBuilder(".HomeTask1").setParentTaskFragment(homeTask).build()); + mRecentTasks.add(createTaskBuilder(".Task1").setParentTaskFragment(otherDisplayRootTask) + .build()); + mRecentTasks.add(createTaskBuilder(".Task2").setParentTaskFragment(otherDisplayRootTask) + .build()); + mRecentTasks.add(createTaskBuilder(".HomeTask2").setParentTaskFragment(homeTask).build()); triggerTrimAndAssertNoTasksTrimmed(); } @@ -1023,7 +1026,7 @@ public class RecentTasksTest extends WindowTestsBase { Task t1 = createTaskBuilder("com.android.pkg1", ".Task1").build(); mRecentTasks.add(t1); mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".HomeTask") - .setParentTask(mTaskContainer.getRootHomeTask()).build()); + .setParentTaskFragment(mTaskContainer.getRootHomeTask()).build()); Task t2 = createTaskBuilder("com.android.pkg2", ".Task2").build(); mRecentTasks.add(t2); mRecentTasks.add(createTaskBuilder("com.android.pkg1", ".PipTask") diff --git a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java index 56d01cd34e01..030733bf4424 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootTaskTests.java @@ -329,7 +329,7 @@ public class RootTaskTests extends WindowTestsBase { // Create primary splitscreen root task. final Task primarySplitScreen = new TaskBuilder(mAtm.mTaskSupervisor) - .setParentTask(organizer.mPrimary) + .setParentTaskFragment(organizer.mPrimary) .setOnTop(true) .build(); @@ -505,8 +505,8 @@ public class RootTaskTests extends WindowTestsBase { targetActivity); final ComponentName alias = new ComponentName(DEFAULT_COMPONENT_PACKAGE_NAME, aliasActivity); - final Task parentTask = new TaskBuilder(mAtm.mTaskSupervisor).build(); - final Task task = new TaskBuilder(mAtm.mTaskSupervisor).setParentTask(parentTask).build(); + final Task parentTask = new TaskBuilder(mSupervisor).build(); + final Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(parentTask).build(); task.origActivity = alias; task.realActivity = target; new ActivityBuilder(mAtm).setComponent(target).setTask(task).setTargetActivity( diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 8d4acbbac993..f2eb709b4bb8 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -168,7 +168,7 @@ public class RootWindowContainerTests extends WindowTestsBase { @Test public void testTaskLayerRank() { final Task rootTask = new TaskBuilder(mSupervisor).build(); - final Task task1 = new TaskBuilder(mSupervisor).setParentTask(rootTask).build(); + final Task task1 = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build(); new ActivityBuilder(mAtm).setTask(task1).build().mVisibleRequested = true; mWm.mRoot.rankTaskLayers(); @@ -523,7 +523,8 @@ public class RootWindowContainerTests extends WindowTestsBase { final TaskDisplayArea taskDisplayArea = mRootWindowContainer.getDefaultTaskDisplayArea(); final Task targetRootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, false /* onTop */); - final Task targetTask = new TaskBuilder(mSupervisor).setParentTask(targetRootTask).build(); + final Task targetTask = new TaskBuilder(mSupervisor).setParentTaskFragment(targetRootTask) + .build(); // Create Recents on secondary display. final TestDisplayContent secondDisplay = addNewDisplayContentAt( diff --git a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java index c44c22fefd7a..cb858845e03e 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/RunningTasksTest.java @@ -166,7 +166,7 @@ public class RunningTasksTest extends WindowTestsBase { final Task task = new TaskBuilder(mAtm.mTaskSupervisor) .setComponent(new ComponentName(mContext.getPackageName(), className)) .setTaskId(taskId) - .setParentTask(stack) + .setParentTaskFragment(stack) .build(); task.lastActiveTime = lastActiveTime; final ActivityRecord activity = new ActivityBuilder(mAtm) diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java index c45c18d16c38..d68edbafb592 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskDisplayAreaTests.java @@ -620,7 +620,7 @@ public class TaskDisplayAreaTests extends WindowTestsBase { final Task pinnedRootTask = mRootWindowContainer.getDefaultTaskDisplayArea() .createRootTask(WINDOWING_MODE_PINNED, ACTIVITY_TYPE_STANDARD, ON_TOP); final Task pinnedTask = new TaskBuilder(mAtm.mTaskSupervisor) - .setParentTask(pinnedRootTask).build(); + .setParentTaskFragment(pinnedRootTask).build(); new ActivityBuilder(mAtm).setActivityFlags(FLAG_ALWAYS_FOCUSABLE) .setTask(pinnedTask).build(); pinnedRootTask.moveToFront("movePinnedRootTaskToFront"); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java index 5e4c67ce9e5c..e528a4a23e45 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskLaunchParamsModifierTests.java @@ -1716,7 +1716,7 @@ public class TaskLaunchParamsModifierTests extends WindowTestsBase { final Task rootTask = display.getDefaultTaskDisplayArea() .createRootTask(display.getWindowingMode(), ACTIVITY_TYPE_STANDARD, true); rootTask.setWindowingMode(WINDOWING_MODE_FREEFORM); - final Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build(); + final Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build(); // Just work around the unnecessary adjustments for bounds. task.getWindowConfiguration().setBounds(bounds); } diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java index 807494429999..67e8c879a3e0 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskTests.java @@ -427,7 +427,7 @@ public class TaskTests extends WindowTestsBase { TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea(); Task rootTask = taskDisplayArea.createRootTask(WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */); - Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build(); + Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build(); final Configuration parentConfig = rootTask.getConfiguration(); parentConfig.windowConfiguration.setBounds(parentBounds); parentConfig.densityDpi = DisplayMetrics.DENSITY_DEFAULT; @@ -757,7 +757,7 @@ public class TaskTests extends WindowTestsBase { DisplayInfo displayInfo = new DisplayInfo(); mAtm.mContext.getDisplay().getDisplayInfo(displayInfo); final int displayHeight = displayInfo.logicalHeight; - final Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build(); + final Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build(); final Configuration inOutConfig = new Configuration(); final Configuration parentConfig = new Configuration(); final int longSide = 1200; @@ -1375,7 +1375,7 @@ public class TaskTests extends WindowTestsBase { TaskDisplayArea taskDisplayArea = mAtm.mRootWindowContainer.getDefaultTaskDisplayArea(); Task rootTask = taskDisplayArea.createRootTask(windowingMode, ACTIVITY_TYPE_STANDARD, true /* onTop */); - Task task = new TaskBuilder(mSupervisor).setParentTask(rootTask).build(); + Task task = new TaskBuilder(mSupervisor).setParentTaskFragment(rootTask).build(); final Configuration parentConfig = rootTask.getConfiguration(); parentConfig.windowConfiguration.setAppBounds(parentBounds); diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java index 050fd80411fc..e7ef6ae7cc0a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +++ b/services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java @@ -56,6 +56,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn; import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn; import static com.android.server.wm.StartingSurfaceController.DEBUG_ENABLE_SHELL_DRAWER; import static com.android.server.wm.WindowContainer.POSITION_BOTTOM; +import static com.android.server.wm.WindowContainer.POSITION_TOP; import static com.android.server.wm.WindowStateAnimator.HAS_DRAWN; import static org.junit.Assert.assertEquals; @@ -589,7 +590,7 @@ class WindowTestsBase extends SystemServiceTestsBase { Task createTaskInRootTask(Task rootTask, int userId) { final Task task = new TaskBuilder(rootTask.mTaskSupervisor) .setUserId(userId) - .setParentTask(rootTask) + .setParentTaskFragment(rootTask) .build(); return task; } @@ -675,6 +676,26 @@ class WindowTestsBase extends SystemServiceTestsBase { activity.mVisibleRequested = true; } + /** + * Creates a {@link TaskFragment} and attach it to the {@code parentTask}. + * + * @param parentTask the {@link Task} this TaskFragment is going to be attached + * @param createEmbeddedTask Sets to {@code true} to create an embedded Task for this + * TaskFragment. Otherwise, create a {@link ActivityRecord}. + * @return the created TaskFragment + */ + static TaskFragment createTaskFragmentWithParentTask(@NonNull Task parentTask, + boolean createEmbeddedTask) { + final TaskFragmentBuilder builder = new TaskFragmentBuilder(parentTask.mAtmService) + .setParentTask(parentTask); + if (createEmbeddedTask) { + builder.createEmbeddedTask(); + } else { + builder.createActivityCount(1); + } + return builder.build(); + } + /** Creates a {@link DisplayContent} that supports IME and adds it to the system. */ DisplayContent createNewDisplay() { return createNewDisplayWithImeSupport(DISPLAY_IME_POLICY_LOCAL); @@ -1042,7 +1063,7 @@ class WindowTestsBase extends SystemServiceTestsBase { // Apply the root activity info and intent .setActivityInfo(aInfo) .setIntent(intent) - .setParentTask(mParentTask).build(); + .setParentTaskFragment(mParentTask).build(); } else if (mTask == null && mParentTask != null && DisplayContent.alwaysCreateRootTask( mParentTask.getWindowingMode(), mParentTask.getActivityType())) { // The parent task can be the task root. @@ -1101,6 +1122,64 @@ class WindowTestsBase extends SystemServiceTestsBase { } } + static class TaskFragmentBuilder { + private final ActivityTaskManagerService mAtm; + private Task mParentTask; + private boolean mCreateParentTask; + private boolean mCreateEmbeddedTask; + private int mCreateActivityCount = 0; + + TaskFragmentBuilder(ActivityTaskManagerService service) { + mAtm = service; + } + + TaskFragmentBuilder setCreateParentTask() { + mCreateParentTask = true; + return this; + } + + TaskFragmentBuilder setParentTask(Task task) { + mParentTask = task; + return this; + } + + /** Creates a child embedded Task and its Activity */ + TaskFragmentBuilder createEmbeddedTask() { + mCreateEmbeddedTask = true; + return this; + } + + TaskFragmentBuilder createActivityCount(int count) { + mCreateActivityCount = count; + return this; + } + + TaskFragment build() { + SystemServicesTestRule.checkHoldsLock(mAtm.mGlobalLock); + + final TaskFragment taskFragment = new TaskFragment(mAtm, null /* fragmentToken */, + false /* createdByOrganizer */); + if (mParentTask == null && mCreateParentTask) { + mParentTask = new TaskBuilder(mAtm.mTaskSupervisor).build(); + } + if (mParentTask != null) { + mParentTask.addChild(taskFragment, POSITION_TOP); + } + if (mCreateEmbeddedTask) { + new TaskBuilder(mAtm.mTaskSupervisor) + .setParentTaskFragment(taskFragment) + .setCreateActivity(true) + .build(); + } + while (mCreateActivityCount > 0) { + final ActivityRecord activity = new ActivityBuilder(mAtm).build(); + taskFragment.addChild(activity); + mCreateActivityCount--; + } + return taskFragment; + } + } + /** * Builder for creating new tasks. */ @@ -1121,7 +1200,7 @@ class WindowTestsBase extends SystemServiceTestsBase { private IVoiceInteractionSession mVoiceSession; private boolean mCreateParentTask = false; - private Task mParentTask; + private TaskFragment mParentTaskFragment; private boolean mCreateActivity = false; @@ -1205,8 +1284,8 @@ class WindowTestsBase extends SystemServiceTestsBase { return this; } - TaskBuilder setParentTask(Task parentTask) { - mParentTask = parentTask; + TaskBuilder setParentTaskFragment(TaskFragment parentTaskFragment) { + mParentTaskFragment = parentTaskFragment; return this; } @@ -1219,12 +1298,13 @@ class WindowTestsBase extends SystemServiceTestsBase { SystemServicesTestRule.checkHoldsLock(mSupervisor.mService.mGlobalLock); // Create parent task. - if (mParentTask == null && mCreateParentTask) { - mParentTask = mTaskDisplayArea.createRootTask( + if (mParentTaskFragment == null && mCreateParentTask) { + mParentTaskFragment = mTaskDisplayArea.createRootTask( WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */); } - if (mParentTask != null && !Mockito.mockingDetails(mParentTask).isSpy()) { - spyOn(mParentTask); + if (mParentTaskFragment != null + && !Mockito.mockingDetails(mParentTaskFragment).isSpy()) { + spyOn(mParentTaskFragment); } // Create task. @@ -1252,13 +1332,15 @@ class WindowTestsBase extends SystemServiceTestsBase { .setOnTop(mOnTop) .setVoiceSession(mVoiceSession); final Task task; - if (mParentTask == null) { + if (mParentTaskFragment == null) { task = builder.setActivityType(mActivityType) .setParent(mTaskDisplayArea) .build(); } else { - task = builder.setParent(mParentTask).build(); - mParentTask.moveToFront("build-task"); + task = builder.setParent(mParentTaskFragment).build(); + if (mParentTaskFragment.asTask() != null) { + mParentTaskFragment.asTask().moveToFront("build-task"); + } } spyOn(task); task.mUserId = mUserId; |