Introduce DisplayArea organizer

Similar to task organizer this allows for the organization of display
areas.

Test: they pass!
Bug: 147406652
Bug: 152113464
Bug: 152117221
Change-Id: Id0dbec20f0aedc5162f4ff7be81b2dafb0c8f3c9
diff --git a/core/java/android/window/IDisplayAreaOrganizer.aidl b/core/java/android/window/IDisplayAreaOrganizer.aidl
new file mode 100644
index 0000000..1045ab2
--- /dev/null
+++ b/core/java/android/window/IDisplayAreaOrganizer.aidl
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import android.window.IWindowContainer;
+
+/**
+ * Interface for WindowManager to delegate control of display areas.
+ * {@hide}
+ */
+oneway interface IDisplayAreaOrganizer {
+    void onDisplayAreaAppeared(in IWindowContainer displayArea);
+    void onDisplayAreaVanished(in IWindowContainer displayArea);
+}
diff --git a/core/java/android/window/IDisplayAreaOrganizerController.aidl b/core/java/android/window/IDisplayAreaOrganizerController.aidl
new file mode 100644
index 0000000..fc6fbef
--- /dev/null
+++ b/core/java/android/window/IDisplayAreaOrganizerController.aidl
@@ -0,0 +1,26 @@
+/**
+ * Copyright (c) 2020, The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.window;
+
+import android.window.IDisplayAreaOrganizer;
+
+/** @hide */
+interface IDisplayAreaOrganizerController {
+
+    /** Register a DisplayAreaOrganizer to manage display areas for a given feature. */
+    void registerOrganizer(in IDisplayAreaOrganizer organizer, int displayAreaFeature);
+}
diff --git a/core/java/android/window/ITaskOrganizer.aidl b/core/java/android/window/ITaskOrganizer.aidl
index 0a04462..fcf4830 100644
--- a/core/java/android/window/ITaskOrganizer.aidl
+++ b/core/java/android/window/ITaskOrganizer.aidl
@@ -25,8 +25,8 @@
  * {@hide}
  */
 oneway interface ITaskOrganizer {
-    void taskAppeared(in ActivityManager.RunningTaskInfo taskInfo);
-    void taskVanished(in ActivityManager.RunningTaskInfo taskInfo);
+    void onTaskAppeared(in ActivityManager.RunningTaskInfo taskInfo);
+    void onTaskVanished(in ActivityManager.RunningTaskInfo taskInfo);
 
     /**
      * Will fire when core attributes of a Task's info change. Relevant properties include the
diff --git a/core/java/android/window/IWindowOrganizerController.aidl b/core/java/android/window/IWindowOrganizerController.aidl
index 4b47924..7f4b26d 100644
--- a/core/java/android/window/IWindowOrganizerController.aidl
+++ b/core/java/android/window/IWindowOrganizerController.aidl
@@ -16,6 +16,7 @@
 
 package android.window;
 
+import android.window.IDisplayAreaOrganizerController;
 import android.window.ITaskOrganizerController;
 import android.window.IWindowContainerTransactionCallback;
 import android.window.WindowContainerTransaction;
@@ -43,4 +44,7 @@
 
     /** @return An interface enabling the management of task organizers. */
     ITaskOrganizerController getTaskOrganizerController();
+
+    /** @return An interface enabling the management of display area organizers. */
+    IDisplayAreaOrganizerController getDisplayAreaOrganizerController();
 }
diff --git a/core/java/android/window/WindowOrganizer.java b/core/java/android/window/WindowOrganizer.java
index b8969c1..4bd5b29 100644
--- a/core/java/android/window/WindowOrganizer.java
+++ b/core/java/android/window/WindowOrganizer.java
@@ -152,6 +152,50 @@
                         }
                     }
                 };
+    }
+
+    /** Class for organizing display areas. */
+    public static class DisplayAreaOrganizer {
+
+        public static final int FEATURE_UNDEFINED = -1;
+        public static final int FEATURE_SYSTEM_FIRST = 0;
+        // The Root display area on a display
+        public static final int FEATURE_ROOT = FEATURE_SYSTEM_FIRST;
+        // Display area hosting the task container.
+        public static final int FEATURE_TASK_CONTAINER = FEATURE_SYSTEM_FIRST + 1;
+        // Display area hosting non-activity window tokens.
+        public static final int FEATURE_WINDOW_TOKENS = FEATURE_SYSTEM_FIRST + 2;
+
+        public static final int FEATURE_SYSTEM_LAST = 10_000;
+
+        // Vendor specific display area definition can start with this value.
+        public static final int FEATURE_VENDOR_FIRST = FEATURE_SYSTEM_LAST + 1;
+
+        /** @hide */
+        @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+        public static void registerOrganizer(
+                IDisplayAreaOrganizer organizer, int displayAreaFeature) throws RemoteException {
+            getController().registerOrganizer(organizer, displayAreaFeature);
+        }
+
+        /** @hide */
+        private static IDisplayAreaOrganizerController getController() {
+            return IDisplayAreaOrganizerControllerSingleton.get();
+        }
+
+        private static final Singleton<IDisplayAreaOrganizerController>
+                IDisplayAreaOrganizerControllerSingleton =
+                new Singleton<IDisplayAreaOrganizerController>() {
+                    @Override
+                    protected IDisplayAreaOrganizerController create() {
+                        try {
+                            return getWindowOrganizerController()
+                                    .getDisplayAreaOrganizerController();
+                        } catch (RemoteException e) {
+                            return null;
+                        }
+                    }
+                };
 
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
index 7f14645..9a57683 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/PipTaskOrganizer.java
@@ -210,7 +210,7 @@
     }
 
     @Override
-    public void taskAppeared(ActivityManager.RunningTaskInfo info) {
+    public void onTaskAppeared(ActivityManager.RunningTaskInfo info) {
         Objects.requireNonNull(info, "Requires RunningTaskInfo");
         final Rect destinationBounds = mPipBoundsHandler.getDestinationBounds(
                 getAspectRatioOrDefault(info.pictureInPictureParams),
@@ -243,7 +243,7 @@
     }
 
     @Override
-    public void taskVanished(ActivityManager.RunningTaskInfo info) {
+    public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
         IWindowContainer token = info.token;
         Objects.requireNonNull(token, "Requires valid IWindowContainer");
         if (token.asBinder() != mToken.asBinder()) {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
index 8bbb548..c4089e5 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/SplitScreenTaskOrganizer.java
@@ -82,11 +82,11 @@
     }
 
     @Override
-    public void taskAppeared(RunningTaskInfo taskInfo) {
+    public void onTaskAppeared(RunningTaskInfo taskInfo) {
     }
 
     @Override
-    public void taskVanished(RunningTaskInfo taskInfo) {
+    public void onTaskVanished(RunningTaskInfo taskInfo) {
     }
 
     @Override
diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java
index d9e41af..8cac487 100644
--- a/services/core/java/com/android/server/wm/DisplayArea.java
+++ b/services/core/java/com/android/server/wm/DisplayArea.java
@@ -21,6 +21,9 @@
 import static android.content.pm.ActivityInfo.SCREEN_ORIENTATION_UNSPECIFIED;
 import static android.view.WindowManager.TRANSIT_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManagerPolicyConstants.APPLICATION_LAYER;
+import static android.window.WindowOrganizer.DisplayAreaOrganizer.FEATURE_ROOT;
+import static android.window.WindowOrganizer.DisplayAreaOrganizer.FEATURE_UNDEFINED;
+import static android.window.WindowOrganizer.DisplayAreaOrganizer.FEATURE_WINDOW_TOKENS;
 
 import static com.android.internal.util.Preconditions.checkState;
 import static com.android.server.wm.DisplayAreaProto.NAME;
@@ -28,13 +31,16 @@
 import static com.android.server.wm.ProtoLogGroup.WM_DEBUG_ORIENTATION;
 import static com.android.server.wm.WindowContainerChildProto.DISPLAY_AREA;
 
+import android.graphics.Point;
 import android.graphics.Rect;
 import android.util.proto.ProtoOutputStream;
+import android.window.IDisplayAreaOrganizer;
 
 import com.android.server.policy.WindowManagerPolicy;
 import com.android.server.protolog.common.ProtoLog;
 
 import java.util.Comparator;
+import java.util.function.Consumer;
 import java.util.function.Predicate;
 
 /**
@@ -57,13 +63,24 @@
 
     protected final Type mType;
     private final String mName;
+    final int mFeatureId;
+    private final DisplayAreaOrganizerController mOrganizerController;
+    IDisplayAreaOrganizer mOrganizer;
 
     DisplayArea(WindowManagerService wms, Type type, String name) {
+        this(wms, type, name, FEATURE_UNDEFINED);
+    }
+
+    DisplayArea(WindowManagerService wms, Type type, String name, int featureId) {
         super(wms);
         // TODO(display-area): move this up to ConfigurationContainer
         mOrientation = SCREEN_ORIENTATION_UNSET;
         mType = type;
         mName = name;
+        mFeatureId = featureId;
+        mRemoteToken = new RemoteToken(this);
+        mOrganizerController =
+                wms.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController;
     }
 
     @Override
@@ -116,6 +133,33 @@
         return DISPLAY_AREA;
     }
 
+    void forAllDisplayAreas(Consumer<DisplayArea> callback) {
+        super.forAllDisplayAreas(callback);
+        callback.accept(this);
+    }
+
+    void setOrganizer(IDisplayAreaOrganizer organizer) {
+        if (mOrganizer == organizer) return;
+        sendDisplayAreaVanished();
+        mOrganizer = organizer;
+        sendDisplayAreaAppeared();
+    }
+
+    void sendDisplayAreaAppeared() {
+        if (mOrganizer == null) return;
+        mOrganizerController.onDisplayAreaAppeared(mOrganizer, this);
+    }
+
+    void sendDisplayAreaVanished() {
+        if (mOrganizer == null) return;
+        mOrganizerController.onDisplayAreaVanished(mOrganizer, this);
+    }
+
+    @Override
+    boolean isOrganized() {
+        return mOrganizer != null;
+    }
+
     /**
      * DisplayArea that contains WindowTokens, and orders them according to their type.
      */
@@ -152,7 +196,7 @@
         };
 
         Tokens(WindowManagerService wms, Type type, String name) {
-            super(wms, type, name);
+            super(wms, type, name, FEATURE_WINDOW_TOKENS);
         }
 
         void addChild(WindowToken token) {
@@ -191,7 +235,7 @@
         private final Rect mTmpDimBoundsRect = new Rect();
 
         Root(WindowManagerService wms) {
-            super(wms, Type.ANY, "DisplayArea.Root");
+            super(wms, Type.ANY, "DisplayArea.Root", FEATURE_ROOT);
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
new file mode 100644
index 0000000..464b127
--- /dev/null
+++ b/services/core/java/com/android/server/wm/DisplayAreaOrganizerController.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2020 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.wm;
+
+import static android.Manifest.permission.MANAGE_ACTIVITY_STACKS;
+
+import android.os.Binder;
+import android.os.IBinder;
+import android.os.RemoteException;
+import android.window.IDisplayAreaOrganizer;
+import android.window.IDisplayAreaOrganizerController;
+
+import java.util.HashMap;
+
+public class DisplayAreaOrganizerController extends IDisplayAreaOrganizerController.Stub {
+    private static final String TAG = "DisplayAreaOrganizerController";
+
+    final ActivityTaskManagerService mService;
+    private final WindowManagerGlobalLock mGlobalLock;
+    private final HashMap<Integer, IDisplayAreaOrganizer> mOrganizersByFeatureIds = new HashMap();
+
+    private class DeathRecipient implements IBinder.DeathRecipient {
+        int mFeature;
+        IDisplayAreaOrganizer mOrganizer;
+
+        DeathRecipient(IDisplayAreaOrganizer organizer, int feature) {
+            mOrganizer = organizer;
+            mFeature = feature;
+        }
+
+        @Override
+        public void binderDied() {
+            synchronized (mGlobalLock) {
+                mOrganizersByFeatureIds.remove(mFeature);
+                mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
+                    if (da.mOrganizer != mOrganizer) return;
+                    da.setOrganizer(null);
+                });
+            }
+        }
+    }
+
+    DisplayAreaOrganizerController(ActivityTaskManagerService atm) {
+        mService = atm;
+        mGlobalLock = atm.mGlobalLock;
+    }
+
+    private void enforceStackPermission(String func) {
+        mService.mAmInternal.enforceCallingPermission(MANAGE_ACTIVITY_STACKS, func);
+    }
+
+    @Override
+    public void registerOrganizer(IDisplayAreaOrganizer organizer, int feature) {
+        enforceStackPermission("registerOrganizer()");
+        final long origId = Binder.clearCallingIdentity();
+        try {
+            synchronized (mGlobalLock) {
+                if (mOrganizersByFeatureIds.get(feature) != null) {
+                    throw new IllegalStateException(
+                            "Replacing existing organizer currently unsupported");
+                }
+
+                final DeathRecipient dr = new DeathRecipient(organizer, feature);
+                try {
+                    organizer.asBinder().linkToDeath(dr, 0);
+                } catch (RemoteException e) {
+                    // Oh well...
+                }
+                mService.mRootWindowContainer.forAllDisplayAreas((da) -> {
+                    if (da.mFeatureId != feature) return;
+                    da.setOrganizer(organizer);
+                });
+
+                mOrganizersByFeatureIds.put(feature, organizer);
+            }
+        } finally {
+            Binder.restoreCallingIdentity(origId);
+        }
+    }
+
+    void onDisplayAreaAppeared(IDisplayAreaOrganizer organizer, DisplayArea da) {
+        try {
+            organizer.onDisplayAreaAppeared(da.mRemoteToken);
+        } catch (RemoteException e) {
+            // Oh well...
+        }
+    }
+
+    void onDisplayAreaVanished(IDisplayAreaOrganizer organizer, DisplayArea da) {
+        try {
+            organizer.onDisplayAreaVanished(da.mRemoteToken);
+        } catch (RemoteException e) {
+            // Oh well...
+        }
+    }
+}
diff --git a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
index 885456a..0c6e483 100644
--- a/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
+++ b/services/core/java/com/android/server/wm/DisplayAreaPolicyBuilder.java
@@ -73,16 +73,36 @@
      */
     static class Feature {
         private final String mName;
+        private final int mId;
         private final boolean[] mWindowLayers;
 
-        private Feature(String name, boolean[] windowLayers) {
+        private Feature(String name, int id, boolean[] windowLayers) {
             mName = name;
+            mId = id;
             mWindowLayers = windowLayers;
         }
 
+        /**
+         * Returns the id of the feature.
+         *
+         * Must be unique among the features added to a {@link DisplayAreaPolicyBuilder}.
+         *
+         * @see android.window.WindowOrganizer.DisplayAreaOrganizer#FEATURE_SYSTEM_FIRST
+         * @see android.window.WindowOrganizer.DisplayAreaOrganizer#FEATURE_VENDOR_FIRST
+         */
+        public int getId() {
+            return mId;
+        }
+
+        @Override
+        public String toString() {
+            return "Feature(\"" + mName + "\", " + mId + '}';
+        }
+
         static class Builder {
             private final WindowManagerPolicy mPolicy;
             private final String mName;
+            private final int mId;
             private final boolean[] mLayers;
 
             /**
@@ -96,10 +116,12 @@
              * The builder starts out with the feature not applying to any types.
              *
              * @param name the name of the feature.
+             * @param id of the feature. {@see Feature#getId}
              */
-            Builder(WindowManagerPolicy policy, String name) {
+            Builder(WindowManagerPolicy policy, String name, int id) {
                 mPolicy = policy;
                 mName = name;
+                mId = id;
                 mLayers = new boolean[mPolicy.getMaxWindowLayer()];
             }
 
@@ -147,7 +169,7 @@
             }
 
             Feature build() {
-                return new Feature(mName, mLayers.clone());
+                return new Feature(mName, mId, mLayers.clone());
             }
 
             private void set(int type, boolean value) {
@@ -364,7 +386,7 @@
                 return leaf;
             } else {
                 return new DisplayArea(parent.mWmService, type, mFeature.mName + ":"
-                        + mMinLayer + ":" + mMaxLayer);
+                        + mMinLayer + ":" + mMaxLayer, mFeature.mId);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 236a62b7..cb5e84c 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -79,6 +79,7 @@
 import static android.view.WindowManager.TRANSIT_ACTIVITY_OPEN;
 import static android.view.WindowManager.TRANSIT_TASK_OPEN;
 import static android.view.WindowManager.TRANSIT_TASK_TO_FRONT;
+import static android.window.WindowOrganizer.DisplayAreaOrganizer.FEATURE_TASK_CONTAINER;
 
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_ANIM;
 import static com.android.server.policy.WindowManagerPolicy.FINISH_LAYOUT_REDO_CONFIG;
@@ -4293,7 +4294,7 @@
         private ActivityStack mRootSplitScreenPrimaryTask = null;
 
         TaskContainers(WindowManagerService service) {
-            super(service, Type.ANY, "TaskContainers");
+            super(service, Type.ANY, "TaskContainers", FEATURE_TASK_CONTAINER);
         }
 
         /**
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index e2c7d52..88cdd17 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -301,7 +301,7 @@
          * we may have some issues with modal-windows, but I guess we can
          * cross that bridge when we come to implementing full-screen TaskOrg
          */
-        if (child.getTask() != null && child.getTask().isControlledByTaskOrganizer()) {
+        if (child.getTask() != null && child.getTask().isOrganized()) {
             inputWindowHandle.replaceTouchableRegionWithCrop(null /* Use this surfaces crop */);
         }
 
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index eca7d2e..55dc694 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -509,22 +509,6 @@
                 _voiceSession, _voiceInteractor, stack);
     }
 
-    class TaskToken extends RemoteToken {
-        TaskToken(WindowContainer container) {
-            super(container);
-        }
-
-        @Override
-        public SurfaceControl getLeash() {
-            // We need to copy the SurfaceControl instead of returning the original
-            // because the Parcel FLAGS PARCELABLE_WRITE_RETURN_VALUE cause SurfaceControls
-            // to release themselves.
-            SurfaceControl sc = new SurfaceControl();
-            sc.copyFrom(getSurfaceControl());
-            return sc;
-        }
-    }
-
     /** Don't use constructor directly. This is only used by XML parser. */
     Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent, Intent _affinityIntent,
             String _affinity, String _rootAffinity, ComponentName _realActivity,
@@ -550,7 +534,7 @@
         mTaskDescription = _lastTaskDescription;
         // Tasks have no set orientation value (including SCREEN_ORIENTATION_UNSPECIFIED).
         setOrientation(SCREEN_ORIENTATION_UNSET);
-        mRemoteToken = new TaskToken(this);
+        mRemoteToken = new RemoteToken(this);
         affinityIntent = _affinityIntent;
         affinity = _affinity;
         rootAffinity = _rootAffinity;
@@ -3110,7 +3094,7 @@
         /**
          * Animations are handled by the TaskOrganizer implementation.
          */
-        if (isControlledByTaskOrganizer()) {
+        if (isOrganized()) {
             return false;
         }
         // Don't animate while the task runs recents animation but only if we are in the mode
@@ -4014,7 +3998,8 @@
         }
     }
 
-    boolean isControlledByTaskOrganizer() {
+    @Override
+    boolean isOrganized() {
         final Task rootTask = getRootTask();
         // if the rootTask is a "child" of a tile, then don't consider it a root task.
         // TODO: remove this along with removing tile.
@@ -4030,7 +4015,7 @@
          * Avoid yanking back control from the TaskOrganizer, which has presumably reparented the
          * Surface in to its own hierarchy.
          */
-        if (isControlledByTaskOrganizer()) {
+        if (isOrganized()) {
             return;
         }
         super.reparentSurfaceControl(t, newParent);
@@ -4117,27 +4102,6 @@
         sendTaskAppeared();
     }
 
-    @Override
-    public void updateSurfacePosition() {
-        // Avoid fighting with the TaskOrganizer over Surface position.
-        if (isControlledByTaskOrganizer()) {
-            return;
-        } else {
-            super.updateSurfacePosition();
-        }
-    }
-
-    @Override
-    void getRelativeDisplayedPosition(Point outPos) {
-        // In addition to updateSurfacePosition, we keep other code that sets
-        // position from fighting with the TaskOrganizer
-        if (isControlledByTaskOrganizer()) {
-            outPos.set(0, 0);
-            return;
-        }
-        super.getRelativeDisplayedPosition(outPos);
-    }
-
     /**
      * @return true if the task is currently focused.
      */
diff --git a/services/core/java/com/android/server/wm/TaskOrganizerController.java b/services/core/java/com/android/server/wm/TaskOrganizerController.java
index fc58ee7..5523678 100644
--- a/services/core/java/com/android/server/wm/TaskOrganizerController.java
+++ b/services/core/java/com/android/server/wm/TaskOrganizerController.java
@@ -111,7 +111,7 @@
         void addTask(Task t) {
             mOrganizedTasks.add(t);
             try {
-                mOrganizer.taskAppeared(t.getTaskInfo());
+                mOrganizer.onTaskAppeared(t.getTaskInfo());
             } catch (Exception e) {
                 Slog.e(TAG, "Exception sending taskAppeared callback" + e);
             }
@@ -119,7 +119,7 @@
 
         void removeTask(Task t) {
             try {
-                mOrganizer.taskVanished(t.getTaskInfo());
+                mOrganizer.onTaskVanished(t.getTaskInfo());
             } catch (Exception e) {
                 Slog.e(TAG, "Exception sending taskVanished callback" + e);
             }
diff --git a/services/core/java/com/android/server/wm/TaskTile.java b/services/core/java/com/android/server/wm/TaskTile.java
index 822f840..51142b1 100644
--- a/services/core/java/com/android/server/wm/TaskTile.java
+++ b/services/core/java/com/android/server/wm/TaskTile.java
@@ -218,7 +218,7 @@
 
     static TaskTile forToken(IBinder token) {
         try {
-            return (TaskTile) ((TaskToken) token).getContainer();
+            return (TaskTile) ((RemoteToken) token).getContainer();
         } catch (ClassCastException e) {
             Slog.w(TAG, "Bad tile token: " + token, e);
             return null;
diff --git a/services/core/java/com/android/server/wm/WindowContainer.java b/services/core/java/com/android/server/wm/WindowContainer.java
index 6c69dc6..b60cd99 100644
--- a/services/core/java/com/android/server/wm/WindowContainer.java
+++ b/services/core/java/com/android/server/wm/WindowContainer.java
@@ -1608,6 +1608,12 @@
         return null;
     }
 
+    void forAllDisplayAreas(Consumer<DisplayArea> callback) {
+        for (int i = mChildren.size() - 1; i >= 0; --i) {
+            mChildren.get(i).forAllDisplayAreas(callback);
+        }
+    }
+
     /**
      * Returns 1, 0, or -1 depending on if this container is greater than, equal to, or lesser than
      * the input container in terms of z-order.
@@ -2321,6 +2327,9 @@
     }
 
     void updateSurfacePosition() {
+        // Avoid fighting with the organizer over Surface position.
+        if (isOrganized()) return;
+
         if (mSurfaceControl == null) {
             return;
         }
@@ -2370,6 +2379,13 @@
     }
 
     void getRelativeDisplayedPosition(Point outPos) {
+        // In addition to updateSurfacePosition, we keep other code that sets
+        // position from fighting with the organizer
+        if (isOrganized()) {
+            outPos.set(0, 0);
+            return;
+        }
+
         final Rect dispBounds = getDisplayedBounds();
         outPos.set(dispBounds.left, dispBounds.top);
         final WindowContainer parent = getParent();
@@ -2410,8 +2426,12 @@
         return null;
     }
 
-    RemoteToken getRemoteToken() {
-        return mRemoteToken;
+    /**
+     * @return {@code true} if window container is manage by a
+     *          {@link android.window.WindowOrganizer}
+     */
+    boolean isOrganized() {
+        return false;
     }
 
     static WindowContainer fromBinder(IBinder binder) {
@@ -2435,7 +2455,14 @@
 
         @Override
         public SurfaceControl getLeash() {
-            throw new RuntimeException("Not implemented");
+            final WindowContainer wc = getContainer();
+            if (wc == null) return null;
+            // We need to copy the SurfaceControl instead of returning the original
+            // because the Parcel FLAGS PARCELABLE_WRITE_RETURN_VALUE cause SurfaceControls
+            // to release themselves.
+            SurfaceControl sc = new SurfaceControl();
+            sc.copyFrom(wc.getSurfaceControl());
+            return sc;
         }
 
         @Override
diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java
index ebfe109..e416e80 100644
--- a/services/core/java/com/android/server/wm/WindowOrganizerController.java
+++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java
@@ -33,6 +33,7 @@
 import android.util.ArraySet;
 import android.util.Slog;
 import android.view.SurfaceControl;
+import android.window.IDisplayAreaOrganizerController;
 import android.window.ITaskOrganizerController;
 import android.window.IWindowContainerTransactionCallback;
 import android.window.IWindowOrganizerController;
@@ -76,11 +77,13 @@
             mTransactionCallbacksByPendingSyncId = new HashMap();
 
     final TaskOrganizerController mTaskOrganizerController;
+    final DisplayAreaOrganizerController mDisplayAreaOrganizerController;
 
     WindowOrganizerController(ActivityTaskManagerService atm) {
         mService = atm;
         mGlobalLock = atm.mGlobalLock;
         mTaskOrganizerController = new TaskOrganizerController(mService);
+        mDisplayAreaOrganizerController = new DisplayAreaOrganizerController(mService);
     }
 
     @Override
@@ -318,6 +321,12 @@
         return mTaskOrganizerController;
     }
 
+    @Override
+    public IDisplayAreaOrganizerController getDisplayAreaOrganizerController() {
+        enforceStackPermission("getDisplayAreaOrganizerController()");
+        return mDisplayAreaOrganizerController;
+    }
+
     int startSyncWithOrganizer(IWindowContainerTransactionCallback callback) {
         int id = mBLASTSyncEngine.startSyncSet(this);
         mTransactionCallbacksByPendingSyncId.put(id, callback);
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 658ba1b..6ec0f91 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityStarterTests.java
@@ -1020,10 +1020,10 @@
             mSecondary = TaskTile.forToken(secondary.asBinder());
         }
         @Override
-        public void taskAppeared(ActivityManager.RunningTaskInfo info) {
+        public void onTaskAppeared(ActivityManager.RunningTaskInfo info) {
         }
         @Override
-        public void taskVanished(ActivityManager.RunningTaskInfo info) {
+        public void onTaskVanished(ActivityManager.RunningTaskInfo info) {
         }
         @Override
         public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
index cc9173a..12bdec6 100644
--- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaPolicyBuilderTest.java
@@ -78,11 +78,11 @@
         final Feature bar;
 
         DisplayAreaPolicyBuilder.Result policy = new DisplayAreaPolicyBuilder()
-                .addFeature(foo = new Feature.Builder(mPolicy, "Foo")
+                .addFeature(foo = new Feature.Builder(mPolicy, "Foo", 0)
                         .upTo(TYPE_STATUS_BAR)
                         .and(TYPE_NAVIGATION_BAR)
                         .build())
-                .addFeature(bar = new Feature.Builder(mPolicy, "Bar")
+                .addFeature(bar = new Feature.Builder(mPolicy, "Bar", 1)
                         .all()
                         .except(TYPE_STATUS_BAR)
                         .build())
diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
index 5359bd3..a96f401 100644
--- a/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/TaskOrganizerTests.java
@@ -60,7 +60,6 @@
 import android.util.ArrayMap;
 import android.util.Rational;
 import android.view.Display;
-import android.view.SurfaceControl;
 import android.window.ITaskOrganizer;
 import android.window.WindowContainerTransaction;
 
@@ -103,10 +102,10 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
 
         task.setTaskOrganizer(organizer);
-        verify(organizer).taskAppeared(any());
+        verify(organizer).onTaskAppeared(any());
 
         task.removeImmediately();
-        verify(organizer).taskVanished(any());
+        verify(organizer).onTaskVanished(any());
     }
 
     @Test
@@ -117,10 +116,10 @@
         final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
 
         task.setTaskOrganizer(organizer);
-        verify(organizer).taskAppeared(any());
+        verify(organizer).onTaskAppeared(any());
         task.setTaskOrganizer(organizer2);
-        verify(organizer).taskVanished(any());
-        verify(organizer2).taskAppeared(any());
+        verify(organizer).onTaskVanished(any());
+        verify(organizer2).onTaskAppeared(any());
     }
 
     @Test
@@ -131,10 +130,10 @@
         final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_PINNED);
 
         stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
-        verify(organizer).taskAppeared(any());
+        verify(organizer).onTaskAppeared(any());
         stack.setWindowingMode(WINDOWING_MODE_PINNED);
-        verify(organizer).taskVanished(any());
-        verify(organizer2).taskAppeared(any());
+        verify(organizer).onTaskVanished(any());
+        verify(organizer2).onTaskAppeared(any());
     }
 
     @Test
@@ -144,12 +143,12 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
 
         stack.setTaskOrganizer(organizer);
-        verify(organizer).taskAppeared(any());
-        assertTrue(stack.isControlledByTaskOrganizer());
+        verify(organizer).onTaskAppeared(any());
+        assertTrue(stack.isOrganized());
 
         stack.setTaskOrganizer(null);
-        verify(organizer).taskVanished(any());
-        assertFalse(stack.isControlledByTaskOrganizer());
+        verify(organizer).onTaskVanished(any());
+        assertFalse(stack.isOrganized());
     }
 
     @Test
@@ -159,12 +158,12 @@
         final ITaskOrganizer organizer = registerMockOrganizer();
 
         stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
-        verify(organizer).taskAppeared(any());
-        assertTrue(stack.isControlledByTaskOrganizer());
+        verify(organizer).onTaskAppeared(any());
+        assertTrue(stack.isOrganized());
 
         mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer);
-        verify(organizer).taskVanished(any());
-        assertFalse(stack.isControlledByTaskOrganizer());
+        verify(organizer).onTaskVanished(any());
+        assertFalse(stack.isOrganized());
     }
 
     @Test
@@ -179,23 +178,23 @@
 
         // First organizer is registered, verify a task appears when changing windowing mode
         stack.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
-        verify(organizer, times(1)).taskAppeared(any());
-        assertTrue(stack.isControlledByTaskOrganizer());
+        verify(organizer, times(1)).onTaskAppeared(any());
+        assertTrue(stack.isOrganized());
 
         // Now we replace the registration and1 verify the new organizer receives tasks
         // newly entering the windowing mode.
         final ITaskOrganizer organizer2 = registerMockOrganizer(WINDOWING_MODE_MULTI_WINDOW);
         stack2.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
-        verify(organizer2).taskAppeared(any());
-        assertTrue(stack2.isControlledByTaskOrganizer());
+        verify(organizer2).onTaskAppeared(any());
+        assertTrue(stack2.isOrganized());
 
         // Now we unregister the second one, the first one should automatically be reregistered
         // so we verify that it's now seeing changes.
         mWm.mAtmService.mTaskOrganizerController.unregisterTaskOrganizer(organizer2);
 
         stack3.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
-        verify(organizer, times(2)).taskAppeared(any());
-        assertTrue(stack3.isControlledByTaskOrganizer());
+        verify(organizer, times(2)).onTaskAppeared(any());
+        assertTrue(stack3.isOrganized());
     }
 
     @Test
@@ -206,10 +205,10 @@
         final Task task = createTaskInStack(stack, 0 /* userId */);
         final Task task2 = createTaskInStack(stack, 0 /* userId */);
         stack.setWindowingMode(WINDOWING_MODE_PINNED);
-        verify(organizer, times(1)).taskAppeared(any());
+        verify(organizer, times(1)).onTaskAppeared(any());
 
         stack.setWindowingMode(WINDOWING_MODE_FULLSCREEN);
-        verify(organizer, times(1)).taskVanished(any());
+        verify(organizer, times(1)).onTaskVanished(any());
     }
 
     @Test
@@ -219,7 +218,7 @@
         stack.setWindowingMode(WINDOWING_MODE_PINNED);
 
         final ITaskOrganizer organizer = registerMockOrganizer(WINDOWING_MODE_PINNED);
-        verify(organizer, times(1)).taskAppeared(any());
+        verify(organizer, times(1)).onTaskAppeared(any());
     }
 
     @Test
@@ -396,10 +395,10 @@
         final boolean[] called = {false};
         ITaskOrganizer listener = new ITaskOrganizer.Stub() {
             @Override
-            public void taskAppeared(RunningTaskInfo taskInfo) { }
+            public void onTaskAppeared(RunningTaskInfo taskInfo) { }
 
             @Override
-            public void taskVanished(RunningTaskInfo container) { }
+            public void onTaskVanished(RunningTaskInfo container) { }
 
             @Override
             public void onTaskInfoChanged(RunningTaskInfo info) throws RemoteException {
@@ -447,10 +446,10 @@
         final ArrayMap<IBinder, RunningTaskInfo> lastReportedTiles = new ArrayMap<>();
         ITaskOrganizer listener = new ITaskOrganizer.Stub() {
             @Override
-            public void taskAppeared(RunningTaskInfo taskInfo) { }
+            public void onTaskAppeared(RunningTaskInfo taskInfo) { }
 
             @Override
-            public void taskVanished(RunningTaskInfo container) { }
+            public void onTaskVanished(RunningTaskInfo container) { }
 
             @Override
             public void onTaskInfoChanged(RunningTaskInfo info) {
@@ -667,11 +666,11 @@
         RunningTaskInfo mInfo;
 
         @Override
-        public void taskAppeared(RunningTaskInfo info) {
+        public void onTaskAppeared(RunningTaskInfo info) {
             mInfo = info;
         }
         @Override
-        public void taskVanished(RunningTaskInfo info) {
+        public void onTaskVanished(RunningTaskInfo info) {
         }
         @Override
         public void onTaskInfoChanged(RunningTaskInfo info) {
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
index f186ed3..5afd39e 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerMultiWindowTest.java
@@ -150,7 +150,7 @@
         };
 
         @Override
-        public void taskAppeared(ActivityManager.RunningTaskInfo ti) {
+        public void onTaskAppeared(ActivityManager.RunningTaskInfo ti) {
             if (!gotFirstTask) {
                 mTaskView1.reparentTask(ti.token);
                 gotFirstTask = true;
@@ -158,7 +158,7 @@
                 mTaskView2.reparentTask(ti.token);
             }
         }
-        public void taskVanished(ActivityManager.RunningTaskInfo ti) {
+        public void onTaskVanished(ActivityManager.RunningTaskInfo ti) {
         }
         @Override
         public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
diff --git a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
index a2f40dc..520bc25 100644
--- a/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
+++ b/tests/TaskOrganizerTest/src/com/android/test/taskembed/TaskOrganizerPipTest.java
@@ -38,7 +38,7 @@
     TaskView mTaskView;
 
     class Organizer extends ITaskOrganizer.Stub {
-        public void taskAppeared(ActivityManager.RunningTaskInfo ti) {
+        public void onTaskAppeared(ActivityManager.RunningTaskInfo ti) {
             mTaskView.reparentTask(ti.token);
 
             final WindowContainerTransaction wct = new WindowContainerTransaction();
@@ -48,7 +48,7 @@
             } catch (Exception e) {
             }
         }
-        public void taskVanished(ActivityManager.RunningTaskInfo ti) {
+        public void onTaskVanished(ActivityManager.RunningTaskInfo ti) {
         }
         public void onTaskInfoChanged(ActivityManager.RunningTaskInfo info) {
         }