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;
}