diff --git a/core/java/android/window/DisplayAreaOrganizer.java b/core/java/android/window/DisplayAreaOrganizer.java index 8a1d4a0b48237..1254647379b59 100644 --- a/core/java/android/window/DisplayAreaOrganizer.java +++ b/core/java/android/window/DisplayAreaOrganizer.java @@ -164,15 +164,19 @@ public class DisplayAreaOrganizer extends WindowOrganizer { } /** - * Creates a persistent task display area. It will be added to be the top most task display area - * in the root. + * Creates a persistent {@link com.android.server.wm.TaskDisplayArea}. * * The new created TDA is organized by the organizer, and will be deleted on calling * {@link #deleteTaskDisplayArea(WindowContainerToken)} or {@link #unregisterOrganizer()}. * - * @param displayId the display to create the new task display area in. - * @param rootFeatureId the root display area to create the new task display area in. Caller can - * use {@link #FEATURE_ROOT} as the root of the logical display. + * @param displayId the display to create the new TDA in. + * @param parentFeatureId the parent to create the new TDA in. If it is a + * {@link com.android.server.wm.RootDisplayArea}, the new TDA will be + * placed as the topmost TDA. If it is another TDA, the new TDA will be + * placed as the topmost child. + * Caller can use {@link #FEATURE_ROOT} as the root of the logical + * display, or {@link #FEATURE_DEFAULT_TASK_CONTAINER} as the default + * TDA. * @param name the name for the new task display area. * @return the new created task display area. * @throws IllegalArgumentException if failed to create a new task display area. @@ -181,11 +185,11 @@ public class DisplayAreaOrganizer extends WindowOrganizer { @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) @CallSuper @NonNull - public DisplayAreaAppearedInfo createTaskDisplayArea(int displayId, int rootFeatureId, + public DisplayAreaAppearedInfo createTaskDisplayArea(int displayId, int parentFeatureId, @NonNull String name) { try { return getController().createTaskDisplayArea( - mInterface, displayId, rootFeatureId, name); + mInterface, displayId, parentFeatureId, name); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } diff --git a/core/java/android/window/IDisplayAreaOrganizerController.aidl b/core/java/android/window/IDisplayAreaOrganizerController.aidl index 26fa434506cf8..6c097bbd80bbe 100644 --- a/core/java/android/window/IDisplayAreaOrganizerController.aidl +++ b/core/java/android/window/IDisplayAreaOrganizerController.aidl @@ -40,21 +40,25 @@ interface IDisplayAreaOrganizerController { void unregisterOrganizer(in IDisplayAreaOrganizer organizer); /** - * Creates a persistent task display area. It will be added to be the top most task display area - * in the root. + * Creates a persistent {@link com.android.server.wm.TaskDisplayArea}. * * The new created TDA is organized by the organizer, and will be deleted on calling * {@link #deleteTaskDisplayArea(WindowContainerToken)} or {@link #unregisterOrganizer()}. * - * @param displayId the display to create the new task display area in. - * @param rootFeatureId the root display area to create the new task display area in. Caller can - * use {@link #FEATURE_ROOT} as the root of the logical display. + * @param displayId the display to create the new TDA in. + * @param parentFeatureId the parent to create the new TDA in. If it is a + * {@link com.android.server.wm.RootDisplayArea}, the new TDA will be + * placed as the topmost TDA. If it is another TDA, the new TDA will be + * placed as the topmost child. + * Caller can use {@link #FEATURE_ROOT} as the root of the logical + * display, or {@link #FEATURE_DEFAULT_TASK_CONTAINER} as the default + * TDA. * @param name the name for the new task display area. * @return the new created task display area. * @throws IllegalArgumentException if failed to create a new task display area. */ DisplayAreaAppearedInfo createTaskDisplayArea(in IDisplayAreaOrganizer organizer, int displayId, - int rootFeatureId, in String name); + int parentFeatureId, in String name); /** * Deletes a persistent task display area. It can only be one that created by an organizer. diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java index c475da354dda4..53f700938bf17 100644 --- a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java +++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java @@ -134,7 +134,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl @Override public DisplayAreaAppearedInfo createTaskDisplayArea(IDisplayAreaOrganizer organizer, - int displayId, int rootFeatureId, String name) { + int displayId, int parentFeatureId, String name) { enforceTaskPermission("createTaskDisplayArea()"); final long uid = Binder.getCallingUid(); final long origId = Binder.clearCallingIdentity(); @@ -149,13 +149,26 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl + displayId); } - final DisplayArea root = display.getItemFromDisplayAreas(da -> - da.asRootDisplayArea() != null && da.mFeatureId == rootFeatureId - ? da + // The parentFeatureId can be either a RootDisplayArea or a TaskDisplayArea. + // Check if there is a RootDisplayArea with the given parentFeatureId. + final RootDisplayArea parentRoot = display.getItemFromDisplayAreas(da -> + da.asRootDisplayArea() != null && da.mFeatureId == parentFeatureId + ? da.asRootDisplayArea() : null); - if (root == null) { - throw new IllegalArgumentException("Can't find RootDisplayArea with featureId=" - + rootFeatureId); + final TaskDisplayArea parentTda; + if (parentRoot == null) { + // There is no RootDisplayArea matching the parentFeatureId. + // Check if there is a TaskDisplayArea with the given parentFeatureId. + parentTda = display.getItemFromTaskDisplayAreas(taskDisplayArea -> + taskDisplayArea.mFeatureId == parentFeatureId + ? taskDisplayArea + : null); + } else { + parentTda = null; + } + if (parentRoot == null && parentTda == null) { + throw new IllegalArgumentException( + "Can't find a parent DisplayArea with featureId=" + parentFeatureId); } final int taskDisplayAreaFeatureId = mNextTaskDisplayAreaFeatureId++; @@ -166,10 +179,13 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl // Oh well... } - final TaskDisplayArea tda = createTaskDisplayArea(root.asRootDisplayArea(), name, - taskDisplayAreaFeatureId); - return organizeDisplayArea(organizer, tda, + final TaskDisplayArea tda = parentRoot != null + ? createTaskDisplayArea(parentRoot, name, taskDisplayAreaFeatureId) + : createTaskDisplayArea(parentTda, name, taskDisplayAreaFeatureId); + final DisplayAreaAppearedInfo tdaInfo = organizeDisplayArea(organizer, tda, "DisplayAreaOrganizerController.createTaskDisplayArea"); + mOrganizersByFeatureIds.put(taskDisplayAreaFeatureId, organizer); + return tdaInfo; } } finally { Binder.restoreCallingIdentity(origId); @@ -196,6 +212,7 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl + "TaskDisplayArea=" + taskDisplayArea); } + mOrganizersByFeatureIds.remove(taskDisplayArea.mFeatureId); deleteTaskDisplayArea(taskDisplayArea); } } finally { @@ -253,6 +270,9 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl new SurfaceControl(displayArea.getSurfaceControl(), callsite)); } + /** + * Creates a {@link TaskDisplayArea} as the topmost TDA below the given {@link RootDisplayArea}. + */ private TaskDisplayArea createTaskDisplayArea(RootDisplayArea root, String name, int taskDisplayAreaFeatureId) { final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(root.mDisplayContent, @@ -283,6 +303,21 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl return taskDisplayArea; } + /** + * Creates a {@link TaskDisplayArea} as the topmost child of the given {@link TaskDisplayArea}. + */ + private TaskDisplayArea createTaskDisplayArea(TaskDisplayArea parentTda, String name, + int taskDisplayAreaFeatureId) { + final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(parentTda.mDisplayContent, + parentTda.mWmService, name, taskDisplayAreaFeatureId, + true /* createdByOrganizer */); + + // Insert the TaskDisplayArea on the top. + parentTda.addChild(taskDisplayArea, WindowContainer.POSITION_TOP); + + return taskDisplayArea; + } + private void deleteTaskDisplayArea(TaskDisplayArea taskDisplayArea) { taskDisplayArea.setOrganizer(null); mService.mRootWindowContainer.mTaskSupervisor.beginDeferResume(); diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java index 1198ee2ba5f41..5597be93c1f11 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaOrganizerTest.java @@ -17,6 +17,7 @@ package com.android.server.wm; import static android.view.Display.DEFAULT_DISPLAY; +import static android.window.DisplayAreaOrganizer.FEATURE_DEFAULT_TASK_CONTAINER; import static android.window.DisplayAreaOrganizer.FEATURE_ROOT; import static android.window.DisplayAreaOrganizer.FEATURE_RUNTIME_TASK_CONTAINER_FIRST; import static android.window.DisplayAreaOrganizer.FEATURE_VENDOR_FIRST; @@ -117,7 +118,7 @@ public class DisplayAreaOrganizerTest extends WindowTestsBase { } @Test - public void testCreateTaskDisplayArea() { + public void testCreateTaskDisplayArea_topBelowRoot() { final String newTdaName = "testTda"; final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder()); final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea( @@ -141,6 +142,30 @@ public class DisplayAreaOrganizerTest extends WindowTestsBase { assertThat(tda.mOrganizer).isEqualTo(organizer); } + @Test + public void testCreateTaskDisplayArea_topBelowAnotherTaskDisplayArea() { + final String newTdaName = "testTda"; + final TaskDisplayArea parentTda = mDisplayContent.getDefaultTaskDisplayArea(); + final IDisplayAreaOrganizer organizer = createMockOrganizer(new Binder()); + final DisplayAreaAppearedInfo tdaInfo = mOrganizerController.createTaskDisplayArea( + organizer, DEFAULT_DISPLAY, FEATURE_DEFAULT_TASK_CONTAINER, newTdaName); + + final WindowContainer wc = parentTda.getChildAt(parentTda.getChildCount() - 1); + + // A new TaskDisplayArea is created on the top. + assertThat(wc).isInstanceOf(TaskDisplayArea.class); + assertThat(tdaInfo.getDisplayAreaInfo().displayId).isEqualTo(DEFAULT_DISPLAY); + assertThat(tdaInfo.getDisplayAreaInfo().token) + .isEqualTo(wc.mRemoteToken.toWindowContainerToken()); + + final TaskDisplayArea tda = wc.asTaskDisplayArea(); + + assertThat(tda.getName()).isEqualTo(newTdaName); + assertThat(tda.mFeatureId).isEqualTo(tdaInfo.getDisplayAreaInfo().featureId); + assertThat(tda.mCreatedByOrganizer).isTrue(); + assertThat(tda.mOrganizer).isEqualTo(organizer); + } + @Test public void testCreateTaskDisplayArea_incrementalTdaFeatureId() { final String newTdaName = "testTda";