summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/window/ITaskOrganizerController.aidl7
-rw-r--r--core/java/android/window/WindowContainerTransaction.java37
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java18
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java28
4 files changed, 88 insertions, 2 deletions
diff --git a/core/java/android/window/ITaskOrganizerController.aidl b/core/java/android/window/ITaskOrganizerController.aidl
index 1748b9d38538..8934cf67b380 100644
--- a/core/java/android/window/ITaskOrganizerController.aidl
+++ b/core/java/android/window/ITaskOrganizerController.aidl
@@ -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);
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java
index 02f8e2f59b33..ce0ccd5c6d0d 100644
--- a/core/java/android/window/WindowContainerTransaction.java
+++ b/core/java/android/window/WindowContainerTransaction.java
@@ -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
@@ -623,6 +627,19 @@ public final class WindowContainerTransaction implements Parcelable {
}
/**
+ * 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
* continuous allocations on every size change.
@@ -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,
@@ -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 {
@@ -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) {
@@ -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:
@@ -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;
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index ad19b9a44670..a1755e4d9d3b 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -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;
@@ -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()) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java
index e9ece5dbdcc4..369600c3f8d7 100644
--- a/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/WindowContainerTransactionTests.java
@@ -79,6 +79,34 @@ public class WindowContainerTransactionTests extends WindowTestsBase {
}
@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);
TaskDisplayArea tda = desktopOrganizer.mDefaultTDA;