Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 3c066ee8 authored by Chris Li's avatar Chris Li Committed by Android (Google) Code Review
Browse files

Merge "Add API to create new TaskDisplayArea at runtime"

parents 26acf279 dfeeea1b
Loading
Loading
Loading
Loading
+57 −0
Original line number Diff line number Diff line
@@ -100,6 +100,19 @@ public class DisplayAreaOrganizer extends WindowOrganizer {
     */
    public static final int FEATURE_VENDOR_FIRST = FEATURE_SYSTEM_LAST + 1;

    /**
     * Last possible vendor specific display area id.
     * @hide
     */
    public static final int FEATURE_VENDOR_LAST = FEATURE_VENDOR_FIRST + 10_000;

    /**
     * Task display areas that can be created at runtime start with this value.
     * @see #createTaskDisplayArea(int, int, String)
     * @hide
     */
    public static final int FEATURE_RUNTIME_TASK_CONTAINER_FIRST = FEATURE_VENDOR_LAST + 1;

    /**
     * Registers a DisplayAreaOrganizer to manage display areas for a given feature. A feature can
     * not be registered by multiple organizers at the same time.
@@ -131,6 +144,50 @@ 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.
     *
     * 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 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.
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
    @CallSuper
    @NonNull
    public DisplayAreaAppearedInfo createTaskDisplayArea(int displayId, int rootFeatureId,
            @NonNull String name) {
        try {
            return getController().createTaskDisplayArea(
                    mInterface, displayId, rootFeatureId, name);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Deletes a persistent task display area. It can only be one that created by an organizer.
     *
     * @throws IllegalArgumentException if failed to delete the task display area.
     * @hide
     */
    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
    @CallSuper
    public void deleteTaskDisplayArea(@NonNull WindowContainerToken taskDisplayArea) {
        try {
            getController().deleteTaskDisplayArea(taskDisplayArea);
        } catch (RemoteException e) {
            throw e.rethrowFromSystemServer();
        }
    }

    /**
     * Called when a DisplayArea of the registered window type can be controlled by this organizer.
     * It will not be called for the DisplayAreas that exist when {@link #registerOrganizer(int)} is
+25 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ package android.window;
import android.content.pm.ParceledListSlice;
import android.window.DisplayAreaAppearedInfo;
import android.window.IDisplayAreaOrganizer;
import android.window.WindowContainerToken;

/** @hide */
interface IDisplayAreaOrganizerController {
@@ -37,4 +38,28 @@ interface IDisplayAreaOrganizerController {
     * Unregisters a previously registered display area organizer.
     */
    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.
     *
     * 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 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);

    /**
     * Deletes a persistent task display area. It can only be one that created by an organizer.
     *
     * @throws IllegalArgumentException if failed to delete the task display area.
     */
    void deleteTaskDisplayArea(in WindowContainerToken taskDisplayArea);
}
+12 −12
Original line number Diff line number Diff line
@@ -961,6 +961,12 @@
      "group": "WM_DEBUG_WINDOW_ORGANIZER",
      "at": "com\/android\/server\/wm\/TaskOrganizerController.java"
    },
    "-948446688": {
      "message": "Create TaskDisplayArea uid=%d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_ORGANIZER",
      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
    },
    "-937498525": {
      "message": "Executing finish of failed to pause activity: %s",
      "level": "VERBOSE",
@@ -1273,6 +1279,12 @@
      "group": "WM_DEBUG_STATES",
      "at": "com\/android\/server\/wm\/Task.java"
    },
    "-597091183": {
      "message": "Delete TaskDisplayArea uid=%d",
      "level": "VERBOSE",
      "group": "WM_DEBUG_WINDOW_ORGANIZER",
      "at": "com\/android\/server\/wm\/DisplayAreaOrganizerController.java"
    },
    "-593535526": {
      "message": "Binding proc %s with config %s",
      "level": "VERBOSE",
@@ -1495,12 +1507,6 @@
      "group": "WM_DEBUG_APP_TRANSITIONS",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "-371630969": {
      "message": "New wallpaper target=%s, oldWallpaper=%s, openingApps=%s, closingApps=%s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_APP_TRANSITIONS",
      "at": "com\/android\/server\/wm\/AppTransitionController.java"
    },
    "-354571697": {
      "message": "Existence Changed in transition %d: %s",
      "level": "VERBOSE",
@@ -2101,12 +2107,6 @@
      "group": "WM_DEBUG_ORIENTATION",
      "at": "com\/android\/server\/wm\/WindowManagerService.java"
    },
    "355940361": {
      "message": "Config is destroying non-running %s",
      "level": "VERBOSE",
      "group": "WM_DEBUG_CONFIGURATION",
      "at": "com\/android\/server\/wm\/ActivityRecord.java"
    },
    "371173718": {
      "message": "finishSync cancel=%b for %s",
      "level": "VERBOSE",
+7 −0
Original line number Diff line number Diff line
@@ -380,6 +380,13 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> {
        return result;
    }

    @Nullable
    @Override
    <R> R getItemFromDisplayAreas(Function<DisplayArea, R> callback) {
        final R item = super.getItemFromDisplayAreas(callback);
        return item != null ? item : callback.apply(this);
    }

    @Nullable
    @Override
    <R> R getItemFromTaskDisplayAreas(Function<TaskDisplayArea, R> callback,
+147 −5
Original line number Diff line number Diff line
@@ -16,7 +16,10 @@

package com.android.server.wm;

import static android.window.DisplayAreaOrganizer.FEATURE_RUNTIME_TASK_CONTAINER_FIRST;

import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER;
import static com.android.server.wm.DisplayArea.Type.ANY;

import android.content.pm.ParceledListSlice;
import android.os.Binder;
@@ -26,6 +29,7 @@ import android.view.SurfaceControl;
import android.window.DisplayAreaAppearedInfo;
import android.window.IDisplayAreaOrganizer;
import android.window.IDisplayAreaOrganizerController;
import android.window.WindowContainerToken;

import com.android.internal.protolog.common.ProtoLog;

@@ -36,6 +40,12 @@ import java.util.List;
public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerController.Stub {
    private static final String TAG = "DisplayAreaOrganizerController";

    /**
     * Next available feature id for a runtime task display area.
     * @see #createTaskDisplayArea(IDisplayAreaOrganizer organizer, int, int, String)
     */
    private int mNextTaskDisplayAreaFeatureId = FEATURE_RUNTIME_TASK_CONTAINER_FIRST;

    final ActivityTaskManagerService mService;
    private final WindowManagerGlobalLock mGlobalLock;
    private final HashMap<Integer, IDisplayAreaOrganizer> mOrganizersByFeatureIds = new HashMap();
@@ -92,10 +102,8 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
                final List<DisplayAreaAppearedInfo> displayAreaInfos = new ArrayList<>();
                mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
                    if (da.mFeatureId != feature) return;
                    da.setOrganizer(organizer, true /* skipDisplayAreaAppeared */);
                    displayAreaInfos.add(new DisplayAreaAppearedInfo(da.getDisplayAreaInfo(),
                            new SurfaceControl(da.getSurfaceControl(),
                                    "DisplayAreaOrganizerController.registerOrganizer")));
                    displayAreaInfos.add(organizeDisplayArea(organizer, da,
                            "DisplayAreaOrganizerController.registerOrganizer"));
                });

                mOrganizersByFeatureIds.put(feature, organizer);
@@ -124,6 +132,77 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
        }
    }

    @Override
    public DisplayAreaAppearedInfo createTaskDisplayArea(IDisplayAreaOrganizer organizer,
            int displayId, int rootFeatureId, String name) {
        enforceTaskPermission("createTaskDisplayArea()");
        final long uid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        try {
            synchronized (mGlobalLock) {
                ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Create TaskDisplayArea uid=%d", uid);

                final DisplayContent display =
                        mService.mRootWindowContainer.getDisplayContent(displayId);
                if (display == null) {
                    throw new IllegalArgumentException("createTaskDisplayArea unknown displayId="
                            + displayId);
                }

                final DisplayArea root = display.getItemFromDisplayAreas(da ->
                        da.asRootDisplayArea() != null && da.mFeatureId == rootFeatureId
                                ? da
                                : null);
                if (root == null) {
                    throw new IllegalArgumentException("Can't find RootDisplayArea with featureId="
                            + rootFeatureId);
                }

                final int taskDisplayAreaFeatureId = mNextTaskDisplayAreaFeatureId++;
                final DeathRecipient dr = new DeathRecipient(organizer, taskDisplayAreaFeatureId);
                try {
                    organizer.asBinder().linkToDeath(dr, 0);
                } catch (RemoteException e) {
                    // Oh well...
                }

                final TaskDisplayArea tda = createTaskDisplayArea(root.asRootDisplayArea(), name,
                        taskDisplayAreaFeatureId);
                return organizeDisplayArea(organizer, tda,
                        "DisplayAreaOrganizerController.createTaskDisplayArea");
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

    @Override
    public void deleteTaskDisplayArea(WindowContainerToken token) {
        enforceTaskPermission("deleteTaskDisplayArea()");
        final long uid = Binder.getCallingUid();
        final long origId = Binder.clearCallingIdentity();
        try {
            synchronized (mGlobalLock) {
                ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "Delete TaskDisplayArea uid=%d", uid);

                final WindowContainer wc = WindowContainer.fromBinder(token.asBinder());
                if (wc == null || wc.asTaskDisplayArea() == null) {
                    throw new IllegalArgumentException("Can't resolve TaskDisplayArea from token");
                }
                final TaskDisplayArea taskDisplayArea = wc.asTaskDisplayArea();
                if (!taskDisplayArea.mCreatedByOrganizer) {
                    throw new IllegalArgumentException(
                            "Attempt to delete TaskDisplayArea not created by organizer "
                                    + "TaskDisplayArea=" + taskDisplayArea);
                }

                deleteTaskDisplayArea(taskDisplayArea);
            }
        } finally {
            Binder.restoreCallingIdentity(origId);
        }
    }

    void onDisplayAreaAppeared(IDisplayAreaOrganizer organizer, DisplayArea da) {
        ProtoLog.v(WM_DEBUG_WINDOW_ORGANIZER, "DisplayArea appeared name=%s", da.getName());
        try {
@@ -157,8 +236,71 @@ public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerControl
        IBinder organizerBinder = organizer.asBinder();
        mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
            if (da.mOrganizer != null && da.mOrganizer.asBinder().equals(organizerBinder)) {
                if (da.isTaskDisplayArea() && da.asTaskDisplayArea().mCreatedByOrganizer) {
                    // Delete the organizer created TDA when unregister.
                    deleteTaskDisplayArea(da.asTaskDisplayArea());
                } else {
                    da.setOrganizer(null);
                }
            }
        });
    }

    private DisplayAreaAppearedInfo organizeDisplayArea(IDisplayAreaOrganizer organizer,
            DisplayArea displayArea, String callsite) {
        displayArea.setOrganizer(organizer, true /* skipDisplayAreaAppeared */);
        return new DisplayAreaAppearedInfo(displayArea.getDisplayAreaInfo(),
                new SurfaceControl(displayArea.getSurfaceControl(), callsite));
    }

    private TaskDisplayArea createTaskDisplayArea(RootDisplayArea root, String name,
            int taskDisplayAreaFeatureId) {
        final TaskDisplayArea taskDisplayArea = new TaskDisplayArea(root.mDisplayContent,
                root.mWmService, name, taskDisplayAreaFeatureId, true /* createdByOrganizer */);

        // Find the top most DA that can contain Task (either a TDA or a DisplayAreaGroup).
        final DisplayArea topTaskContainer = root.getItemFromDisplayAreas(da -> {
            if (da.mType != ANY) {
                return null;
            }

            final RootDisplayArea rootDA = da.getRootDisplayArea();
            if (rootDA == root || rootDA == da) {
                // Either it is the top TDA below the root or it is a DisplayAreaGroup.
                return da;
            }
            return null;
        });
        if (topTaskContainer == null) {
            throw new IllegalStateException("Root must either contain TDA or DAG root=" + root);
        }

        // Insert the TaskDisplayArea as the top Task container.
        final WindowContainer parent = topTaskContainer.getParent();
        final int index = parent.mChildren.indexOf(topTaskContainer) + 1;
        parent.addChild(taskDisplayArea, index);

        return taskDisplayArea;
    }

    private void deleteTaskDisplayArea(TaskDisplayArea taskDisplayArea) {
        taskDisplayArea.setOrganizer(null);
        mService.mRootWindowContainer.mTaskSupervisor.beginDeferResume();

        // TaskDisplayArea#remove() move the stacks to the default TaskDisplayArea.
        Task lastReparentedStack;
        try {
            lastReparentedStack = taskDisplayArea.remove();
        } finally {
            mService.mRootWindowContainer.mTaskSupervisor.endDeferResume();
        }

        taskDisplayArea.removeImmediately();

        // Only update focus/visibility for the last one because there may be many stacks are
        // reparented and the intermediate states are unnecessary.
        if (lastReparentedStack != null) {
            lastReparentedStack.postReparent();
        }
    }
}
Loading