Loading core/java/android/window/ITaskOrganizerController.aidl +6 −1 Original line number Diff line number Diff line Loading @@ -39,7 +39,12 @@ interface ITaskOrganizerController { */ void unregisterTaskOrganizer(ITaskOrganizer organizer); /** Creates a persistent root task in WM for a particular windowing-mode. */ /** * Creates a persistent root task in WM for a particular windowing-mode. * * It may be removed using {@link #deleteRootTask} or through * {@link WindowContainerTransaction#removeRootTask}. */ void createRootTask(int displayId, int windowingMode, IBinder launchCookie, boolean removeWithTaskOrganizer); Loading core/java/android/window/WindowContainerTransaction.java +36 −1 Original line number Diff line number Diff line Loading @@ -614,6 +614,10 @@ public final class WindowContainerTransaction implements Parcelable { /** * Finds and removes a task and its children using its container token. The task is removed * from recents. * * If the task is a root task, its leaves are removed but the root task is not. Use * {@link #removeRootTask(WindowContainerToken)} to remove the root task. * * @param containerToken ContainerToken of Task to be removed */ @NonNull Loading @@ -622,6 +626,19 @@ public final class WindowContainerTransaction implements Parcelable { return this; } /** * Finds and removes a root task created by an organizer and its leaves using its container * token. * * @param containerToken ContainerToken of the root task to be removed * @hide */ @NonNull public WindowContainerTransaction removeRootTask(@NonNull WindowContainerToken containerToken) { mHierarchyOps.add(HierarchyOp.createForRemoveRootTask(containerToken.asBinder())); return this; } /** * Sets whether a container is being drag-resized. * When {@code true}, the client will reuse a single (larger) surface size to avoid Loading Loading @@ -1573,6 +1590,7 @@ public final class WindowContainerTransaction implements Parcelable { public static final int HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES = 21; public static final int HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE = 22; public static final int HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT = 23; public static final int HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK = 24; @IntDef(prefix = {"HIERARCHY_OP_TYPE_"}, value = { HIERARCHY_OP_TYPE_REPARENT, Loading @@ -1598,7 +1616,8 @@ public final class WindowContainerTransaction implements Parcelable { HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION, HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES, HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE, HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT, HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK, }) @Retention(RetentionPolicy.SOURCE) public @interface HierarchyOpType { Loading Loading @@ -1795,6 +1814,18 @@ public final class WindowContainerTransaction implements Parcelable { .build(); } /** * Creates a hierarchy op for deleting a root task * * @hide **/ @NonNull public static HierarchyOp createForRemoveRootTask(@NonNull IBinder container) { return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK) .setContainer(container) .build(); } /** Creates a hierarchy op for clearing adjacent root tasks. */ @NonNull public static HierarchyOp createForClearAdjacentRoots(@NonNull IBinder root) { Loading Loading @@ -2012,6 +2043,7 @@ public final class WindowContainerTransaction implements Parcelable { return "removeInsetsFrameProvider"; case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: return "setAlwaysOnTop"; case HIERARCHY_OP_TYPE_REMOVE_TASK: return "removeTask"; case HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK: return "removeRootTask"; case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: return "finishActivity"; case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "clearAdjacentRoots"; case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH: Loading Loading @@ -2096,6 +2128,9 @@ public final class WindowContainerTransaction implements Parcelable { case HIERARCHY_OP_TYPE_REMOVE_TASK: sb.append("task=").append(mContainer); break; case HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK: sb.append("rootTask=").append(mContainer); break; case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: sb.append("activity=").append(mContainer); break; Loading services/core/java/com/android/server/wm/WindowOrganizerController.java +18 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ import static android.window.WindowContainerTransaction.Change.CHANGE_FOCUSABLE; import static android.window.WindowContainerTransaction.Change.CHANGE_FORCE_TRANSLUCENT; import static android.window.WindowContainerTransaction.Change.CHANGE_HIDDEN; import static android.window.WindowContainerTransaction.Change.CHANGE_RELATIVE_BOUNDS; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION; Loading Loading @@ -1131,6 +1132,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } break; } case HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK: { final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); if (wc == null || wc.asTask() == null || !wc.isAttached() || !wc.asTask().isRootTask() || !wc.asTask().mCreatedByOrganizer) { Slog.e(TAG, "Attempt to remove invalid task: " + wc); break; } final Task task = wc.asTask(); if (task.isVisibleRequested() || task.isVisible()) { effects |= TRANSACT_EFFECTS_LIFECYCLE; } // Removes its leaves, but not itself. mService.mTaskSupervisor.removeRootTask(task); // Now that the root has no leaves, remove it too. . task.remove(true /* withTransition */, "remove-root-task-through-hierarchyOp"); break; } case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: { final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); if (wc == null || !wc.isAttached()) { Loading services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java +28 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,34 @@ public class WindowContainerTransactionTests extends WindowTestsBase { verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(rootTask); } @Test public void testRemoveRootTask() { final Task rootTask = createTask(mDisplayContent); final Task task = createTaskInRootTask(rootTask, 0 /* userId */); final ActivityRecord activity = createActivityRecord(mDisplayContent, task); final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); WindowContainerTransaction wct = new WindowContainerTransaction(); WindowContainerToken token = rootTask.getTaskInfo().token; wct.removeTask(token); applyTransaction(wct); // There is still an activity to be destroyed, so the task is not removed immediately. assertNotNull(task.getParent()); assertTrue(rootTask.hasChild()); assertTrue(task.hasChild()); assertTrue(activity.finishing); activity.destroyed("testRemoveRootTask"); // Assert that the container was removed after the activity is destroyed. assertNull(task.getParent()); assertEquals(0, task.getChildCount()); assertNull(activity.getParent()); assertNull(taskDisplayArea.getTask(task1 -> task1.mTaskId == rootTask.mTaskId)); verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(task); verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(rootTask); } @Test public void testDesktopMode_tasksAreBroughtToFront() { final TestDesktopOrganizer desktopOrganizer = new TestDesktopOrganizer(mAtm); Loading Loading
core/java/android/window/ITaskOrganizerController.aidl +6 −1 Original line number Diff line number Diff line Loading @@ -39,7 +39,12 @@ interface ITaskOrganizerController { */ void unregisterTaskOrganizer(ITaskOrganizer organizer); /** Creates a persistent root task in WM for a particular windowing-mode. */ /** * Creates a persistent root task in WM for a particular windowing-mode. * * It may be removed using {@link #deleteRootTask} or through * {@link WindowContainerTransaction#removeRootTask}. */ void createRootTask(int displayId, int windowingMode, IBinder launchCookie, boolean removeWithTaskOrganizer); Loading
core/java/android/window/WindowContainerTransaction.java +36 −1 Original line number Diff line number Diff line Loading @@ -614,6 +614,10 @@ public final class WindowContainerTransaction implements Parcelable { /** * Finds and removes a task and its children using its container token. The task is removed * from recents. * * If the task is a root task, its leaves are removed but the root task is not. Use * {@link #removeRootTask(WindowContainerToken)} to remove the root task. * * @param containerToken ContainerToken of Task to be removed */ @NonNull Loading @@ -622,6 +626,19 @@ public final class WindowContainerTransaction implements Parcelable { return this; } /** * Finds and removes a root task created by an organizer and its leaves using its container * token. * * @param containerToken ContainerToken of the root task to be removed * @hide */ @NonNull public WindowContainerTransaction removeRootTask(@NonNull WindowContainerToken containerToken) { mHierarchyOps.add(HierarchyOp.createForRemoveRootTask(containerToken.asBinder())); return this; } /** * Sets whether a container is being drag-resized. * When {@code true}, the client will reuse a single (larger) surface size to avoid Loading Loading @@ -1573,6 +1590,7 @@ public final class WindowContainerTransaction implements Parcelable { public static final int HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES = 21; public static final int HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE = 22; public static final int HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT = 23; public static final int HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK = 24; @IntDef(prefix = {"HIERARCHY_OP_TYPE_"}, value = { HIERARCHY_OP_TYPE_REPARENT, Loading @@ -1598,7 +1616,8 @@ public final class WindowContainerTransaction implements Parcelable { HIERARCHY_OP_TYPE_RESTORE_BACK_NAVIGATION, HIERARCHY_OP_TYPE_SET_EXCLUDE_INSETS_TYPES, HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE, HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT HIERARCHY_OP_TYPE_SET_DISABLE_LAUNCH_ADJACENT, HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK, }) @Retention(RetentionPolicy.SOURCE) public @interface HierarchyOpType { Loading Loading @@ -1795,6 +1814,18 @@ public final class WindowContainerTransaction implements Parcelable { .build(); } /** * Creates a hierarchy op for deleting a root task * * @hide **/ @NonNull public static HierarchyOp createForRemoveRootTask(@NonNull IBinder container) { return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK) .setContainer(container) .build(); } /** Creates a hierarchy op for clearing adjacent root tasks. */ @NonNull public static HierarchyOp createForClearAdjacentRoots(@NonNull IBinder root) { Loading Loading @@ -2012,6 +2043,7 @@ public final class WindowContainerTransaction implements Parcelable { return "removeInsetsFrameProvider"; case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: return "setAlwaysOnTop"; case HIERARCHY_OP_TYPE_REMOVE_TASK: return "removeTask"; case HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK: return "removeRootTask"; case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: return "finishActivity"; case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "clearAdjacentRoots"; case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH: Loading Loading @@ -2096,6 +2128,9 @@ public final class WindowContainerTransaction implements Parcelable { case HIERARCHY_OP_TYPE_REMOVE_TASK: sb.append("task=").append(mContainer); break; case HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK: sb.append("rootTask=").append(mContainer); break; case HIERARCHY_OP_TYPE_FINISH_ACTIVITY: sb.append("activity=").append(mContainer); break; Loading
services/core/java/com/android/server/wm/WindowOrganizerController.java +18 −0 Original line number Diff line number Diff line Loading @@ -52,6 +52,7 @@ import static android.window.WindowContainerTransaction.Change.CHANGE_FOCUSABLE; import static android.window.WindowContainerTransaction.Change.CHANGE_FORCE_TRANSLUCENT; import static android.window.WindowContainerTransaction.Change.CHANGE_HIDDEN; import static android.window.WindowContainerTransaction.Change.CHANGE_RELATIVE_BOUNDS; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_KEYGUARD_STATE; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_INSETS_FRAME_PROVIDER; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_ADD_TASK_FRAGMENT_OPERATION; Loading Loading @@ -1131,6 +1132,23 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub } break; } case HIERARCHY_OP_TYPE_REMOVE_ROOT_TASK: { final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); if (wc == null || wc.asTask() == null || !wc.isAttached() || !wc.asTask().isRootTask() || !wc.asTask().mCreatedByOrganizer) { Slog.e(TAG, "Attempt to remove invalid task: " + wc); break; } final Task task = wc.asTask(); if (task.isVisibleRequested() || task.isVisible()) { effects |= TRANSACT_EFFECTS_LIFECYCLE; } // Removes its leaves, but not itself. mService.mTaskSupervisor.removeRootTask(task); // Now that the root has no leaves, remove it too. . task.remove(true /* withTransition */, "remove-root-task-through-hierarchyOp"); break; } case HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT: { final WindowContainer wc = WindowContainer.fromBinder(hop.getContainer()); if (wc == null || !wc.isAttached()) { Loading
services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java +28 −0 Original line number Diff line number Diff line Loading @@ -78,6 +78,34 @@ public class WindowContainerTransactionTests extends WindowTestsBase { verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(rootTask); } @Test public void testRemoveRootTask() { final Task rootTask = createTask(mDisplayContent); final Task task = createTaskInRootTask(rootTask, 0 /* userId */); final ActivityRecord activity = createActivityRecord(mDisplayContent, task); final TaskDisplayArea taskDisplayArea = mDisplayContent.getDefaultTaskDisplayArea(); WindowContainerTransaction wct = new WindowContainerTransaction(); WindowContainerToken token = rootTask.getTaskInfo().token; wct.removeTask(token); applyTransaction(wct); // There is still an activity to be destroyed, so the task is not removed immediately. assertNotNull(task.getParent()); assertTrue(rootTask.hasChild()); assertTrue(task.hasChild()); assertTrue(activity.finishing); activity.destroyed("testRemoveRootTask"); // Assert that the container was removed after the activity is destroyed. assertNull(task.getParent()); assertEquals(0, task.getChildCount()); assertNull(activity.getParent()); assertNull(taskDisplayArea.getTask(task1 -> task1.mTaskId == rootTask.mTaskId)); verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(task); verify(mAtm.getLockTaskController(), atLeast(1)).clearLockedTask(rootTask); } @Test public void testDesktopMode_tasksAreBroughtToFront() { final TestDesktopOrganizer desktopOrganizer = new TestDesktopOrganizer(mAtm); Loading