Add TaskTile concept to Window Manager

This adds the concept of a TaskTile to the WM. Due to
complexities in the current Stack/Task relationship, tiles
can't actually be part of the hierarchy, so the Stack
level has to internally resolve configurations as if they
were.

The TaskTiles themselves *are* ActivityStacks though from
the client/sysui perspective, though.

Bug: 133381284
Test: Added TaskTileTests
Change-Id: I9baad5ec899b4fab323a36c1533a40081727a2f7
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index dd9a2bc..58bff7f 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -158,6 +158,24 @@
                 }
             };
 
+    /** @hide */
+    @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_STACKS)
+    public static ITaskOrganizerController getTaskOrganizerController() {
+        return ITaskOrganizerControllerSingleton.get();
+    }
+
+    private static final Singleton<ITaskOrganizerController> ITaskOrganizerControllerSingleton =
+            new Singleton<ITaskOrganizerController>() {
+                @Override
+                protected ITaskOrganizerController create() {
+                    try {
+                        return getService().getTaskOrganizerController();
+                    } catch (RemoteException e) {
+                        return null;
+                    }
+                }
+            };
+
     /**
      * Sets the windowing mode for a specific task. Only works on tasks of type
      * {@link WindowConfiguration#ACTIVITY_TYPE_STANDARD}
diff --git a/core/java/android/app/IActivityTaskManager.aidl b/core/java/android/app/IActivityTaskManager.aidl
index 85fa7c1..503f5c5 100644
--- a/core/java/android/app/IActivityTaskManager.aidl
+++ b/core/java/android/app/IActivityTaskManager.aidl
@@ -29,6 +29,7 @@
 import android.app.IRequestFinishCallback;
 import android.app.IServiceConnection;
 import android.app.IStopUserCallback;
+import android.app.ITaskOrganizerController;
 import android.app.ITaskStackListener;
 import android.app.IUiAutomationConnection;
 import android.app.IUidObserver;
@@ -71,7 +72,6 @@
 import android.view.ITaskOrganizer;
 import android.view.RemoteAnimationDefinition;
 import android.view.RemoteAnimationAdapter;
-import android.view.WindowContainerTransaction;
 import com.android.internal.app.IVoiceInteractor;
 import com.android.internal.os.IResultReceiver;
 import com.android.internal.policy.IKeyguardDismissCallback;
@@ -123,8 +123,6 @@
             int requestCode, int flags, in ProfilerInfo profilerInfo, in Bundle options,
             IBinder permissionToken, boolean ignoreTargetSecurity, int userId);
 
-    void registerTaskOrganizer(in ITaskOrganizer organizer, int windowingMode);
-
     boolean isActivityStartAllowedOnDisplay(int displayId, in Intent intent, in String resolvedType,
             int userId);
 
@@ -224,7 +222,6 @@
     void setTaskResizeable(int taskId, int resizeableMode);
     void toggleFreeformWindowingMode(in IBinder token);
     void resizeTask(int taskId, in Rect bounds, int resizeMode);
-    void applyContainerTransaction(in WindowContainerTransaction t);
     void moveStackToDisplay(int stackId, int displayId);
     void removeStack(int stackId);
 
@@ -364,6 +361,11 @@
             in Rect tempOtherTaskBounds, in Rect tempOtherTaskInsetBounds);
 
     /**
+     * Returns an interface enabling the management of task organizers.
+     */
+    ITaskOrganizerController getTaskOrganizerController();
+
+    /**
      * Sets whether we are currently in an interactive split screen resize operation where we
      * are changing the docked stack size.
      */
diff --git a/core/java/android/app/ITaskOrganizerController.aidl b/core/java/android/app/ITaskOrganizerController.aidl
new file mode 100644
index 0000000..168f782
--- /dev/null
+++ b/core/java/android/app/ITaskOrganizerController.aidl
@@ -0,0 +1,51 @@
+/**
+ * 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.app;
+
+import android.app.ActivityManager;
+import android.view.ITaskOrganizer;
+import android.view.IWindowContainer;
+import android.view.WindowContainerTransaction;
+
+/** @hide */
+interface ITaskOrganizerController {
+
+    /**
+     * Register a TaskOrganizer to manage tasks as they enter the given windowing mode.
+     * If there was already a TaskOrganizer for this windowing mode it will be evicted
+     * and receive taskVanished callbacks in the process.
+     */
+    void registerTaskOrganizer(ITaskOrganizer organizer, int windowingMode);
+
+    /** Apply multiple WindowContainer operations at once. */
+    void applyContainerTransaction(in WindowContainerTransaction t);
+
+    /** Creates a persistent root task in WM for a particular windowing-mode. */
+    ActivityManager.RunningTaskInfo createRootTask(int displayId, int windowingMode);
+
+    /** Deletes a persistent root task in WM */
+    boolean deleteRootTask(IWindowContainer task);
+
+    /** Get the root task which contains the current ime target */
+    IWindowContainer getImeTarget(int display);
+
+    /**
+     * Set's the root task to launch new tasks into on a display. {@code null} means no launch root
+     * and thus new tasks just end up directly on the display.
+     */
+    void setLaunchRoot(int displayId, in IWindowContainer root);
+}
diff --git a/core/java/android/app/TaskInfo.java b/core/java/android/app/TaskInfo.java
index fe9c640..662ca6e 100644
--- a/core/java/android/app/TaskInfo.java
+++ b/core/java/android/app/TaskInfo.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import static android.content.pm.ActivityInfo.RESIZE_MODE_UNRESIZEABLE;
+
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.compat.annotation.UnsupportedAppUsage;
@@ -25,6 +27,7 @@
 import android.os.Parcel;
 import android.os.RemoteException;
 import android.util.Log;
+import android.view.IWindowContainer;
 
 /**
  * Stores information about a particular Task.
@@ -138,6 +141,19 @@
     @UnsupportedAppUsage
     public final Configuration configuration = new Configuration();
 
+    /**
+     * Used as an opaque identifier for this task.
+     * @hide
+     */
+    @NonNull
+    public IWindowContainer token;
+
+    /**
+     * The activity type of the top activity in this task.
+     * @hide
+     */
+    public @WindowConfiguration.ActivityType int topActivityType;
+
     TaskInfo() {
         // Do nothing
     }
@@ -160,6 +176,11 @@
         }
     }
 
+    /** @hide */
+    public boolean isResizable() {
+        return resizeMode != RESIZE_MODE_UNRESIZEABLE;
+    }
+
     /**
      * Reads the TaskInfo from a parcel.
      */
@@ -186,6 +207,8 @@
         supportsSplitScreenMultiWindow = source.readBoolean();
         resizeMode = source.readInt();
         configuration.readFromParcel(source);
+        token = IWindowContainer.Stub.asInterface(source.readStrongBinder());
+        topActivityType = source.readInt();
     }
 
     /**
@@ -221,6 +244,8 @@
         dest.writeBoolean(supportsSplitScreenMultiWindow);
         dest.writeInt(resizeMode);
         configuration.writeToParcel(dest, flags);
+        dest.writeStrongInterface(token);
+        dest.writeInt(topActivityType);
     }
 
     @Override
@@ -234,6 +259,8 @@
                 + " numActivities=" + numActivities
                 + " lastActiveTime=" + lastActiveTime
                 + " supportsSplitScreenMultiWindow=" + supportsSplitScreenMultiWindow
-                + " resizeMode=" + resizeMode;
+                + " resizeMode=" + resizeMode
+                + " token=" + token
+                + " topActivityType=" + topActivityType;
     }
 }
diff --git a/core/java/android/view/ITaskOrganizer.aidl b/core/java/android/view/ITaskOrganizer.aidl
index e92aafe..5ccdd30 100644
--- a/core/java/android/view/ITaskOrganizer.aidl
+++ b/core/java/android/view/ITaskOrganizer.aidl
@@ -26,8 +26,7 @@
  * {@hide}
  */
 oneway interface ITaskOrganizer {
-    void taskAppeared(in IWindowContainer container,
-        in ActivityManager.RunningTaskInfo taskInfo);
+    void taskAppeared(in ActivityManager.RunningTaskInfo taskInfo);
     void taskVanished(in IWindowContainer container);
 
     /**
@@ -35,4 +34,19 @@
      * ActivityTaskManagerService#applyTaskOrganizerTransaction
      */
     void transactionReady(int id, in SurfaceControl.Transaction t);
+
+    /**
+     * Will fire when core attributes of a Task's info change. Relevant properties include the
+     * {@link WindowConfiguration.ActivityType} and whether it is resizable.
+     *
+     * This is used, for example, during split-screen. The flow for starting is: Something sends an
+     * Intent with windowingmode. Then WM finds a matching root task and launches the new task into
+     * it. This causes the root task's info to change because now it has a task when it didn't
+     * before. The default Divider implementation interprets this as a request to enter
+     * split-screen mode and will move all other Tasks into the secondary root task. When WM
+     * applies this change, it triggers an info change in the secondary root task because it now
+     * has children. The Divider impl looks at the info and can see that the secondary root task
+     * has adopted an ActivityType of HOME and proceeds to show the minimized dock UX.
+     */
+    void onTaskInfoChanged(in ActivityManager.RunningTaskInfo info);
 }
\ No newline at end of file
diff --git a/core/java/android/view/WindowContainerTransaction.java b/core/java/android/view/WindowContainerTransaction.java
index c55caa3..33f21f2 100644
--- a/core/java/android/view/WindowContainerTransaction.java
+++ b/core/java/android/view/WindowContainerTransaction.java
@@ -86,6 +86,17 @@
         return this;
     }
 
+    /**
+     * Set the smallestScreenWidth of a container.
+     */
+    public WindowContainerTransaction setSmallestScreenWidthDp(IWindowContainer container,
+            int widthDp) {
+        Change cfg = getOrCreateChange(container.asBinder());
+        cfg.mConfiguration.smallestScreenWidthDp = widthDp;
+        cfg.mConfigSetMask |= ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE;
+        return this;
+    }
+
     public Map<IBinder, Change> getChanges() {
         return mChanges;
     }