Merge "Allow children task of created-by-organizer task to be organized"
This commit is contained in:
@@ -290,6 +290,7 @@ package android.app {
|
||||
method @NonNull public android.content.res.Configuration getConfiguration();
|
||||
method @Nullable public android.app.PictureInPictureParams getPictureInPictureParams();
|
||||
method @NonNull public android.window.WindowContainerToken getToken();
|
||||
method public boolean hasParentTask();
|
||||
}
|
||||
|
||||
public class TimePickerDialog extends android.app.AlertDialog implements android.content.DialogInterface.OnClickListener android.widget.TimePicker.OnTimeChangedListener {
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
import static android.app.ActivityTaskManager.INVALID_TASK_ID;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.TestApi;
|
||||
@@ -204,6 +206,13 @@ public class TaskInfo {
|
||||
*/
|
||||
public ArrayList<IBinder> launchCookies = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* The identifier of the parent task that is created by organizer, otherwise
|
||||
* {@link ActivityTaskManager#INVALID_TASK_ID}.
|
||||
* @hide
|
||||
*/
|
||||
public int parentTaskId;
|
||||
|
||||
TaskInfo() {
|
||||
// Do nothing
|
||||
}
|
||||
@@ -253,6 +262,12 @@ public class TaskInfo {
|
||||
launchCookies.add(cookie);
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@TestApi
|
||||
public boolean hasParentTask() {
|
||||
return parentTaskId != INVALID_TASK_ID;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the TaskInfo from a parcel.
|
||||
*/
|
||||
@@ -283,6 +298,7 @@ public class TaskInfo {
|
||||
source.readBinderList(launchCookies);
|
||||
letterboxActivityBounds = source.readTypedObject(Rect.CREATOR);
|
||||
positionInParent = source.readTypedObject(Point.CREATOR);
|
||||
parentTaskId = source.readInt();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -316,6 +332,7 @@ public class TaskInfo {
|
||||
dest.writeBinderList(launchCookies);
|
||||
dest.writeTypedObject(letterboxActivityBounds, flags);
|
||||
dest.writeTypedObject(positionInParent, flags);
|
||||
dest.writeInt(parentTaskId);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -338,6 +355,7 @@ public class TaskInfo {
|
||||
+ " launchCookies" + launchCookies
|
||||
+ " letterboxActivityBounds=" + letterboxActivityBounds
|
||||
+ " positionInParent=" + positionInParent
|
||||
+ " parentTaskId: " + parentTaskId
|
||||
+ "}";
|
||||
}
|
||||
}
|
||||
|
||||
@@ -335,6 +335,12 @@ public class ShellTaskOrganizer extends TaskOrganizer {
|
||||
listener = mTaskListeners.get(taskId);
|
||||
if (listener != null) return listener;
|
||||
|
||||
// Next priority goes to the listener listening to its parent.
|
||||
if (runningTaskInfo.hasParentTask()) {
|
||||
listener = mTaskListeners.get(runningTaskInfo.parentTaskId);
|
||||
if (listener != null) return listener;
|
||||
}
|
||||
|
||||
// Next we try type specific listeners.
|
||||
final int taskListenerType = taskInfoToTaskListenerType(runningTaskInfo);
|
||||
return mTaskListeners.get(taskListenerType);
|
||||
|
||||
@@ -117,7 +117,7 @@ public class SplitScreenController implements SplitScreen,
|
||||
mTransactionPool = transactionPool;
|
||||
mWindowManagerProxy = new WindowManagerProxy(syncQueue, shellTaskOrganizer);
|
||||
mTaskOrganizer = shellTaskOrganizer;
|
||||
mSplits = new SplitScreenTaskListener(this, shellTaskOrganizer);
|
||||
mSplits = new SplitScreenTaskListener(this, shellTaskOrganizer, syncQueue);
|
||||
mImePositionProcessor = new DividerImeController(mSplits, mTransactionPool, mHandler,
|
||||
shellTaskOrganizer);
|
||||
mRotationController =
|
||||
|
||||
@@ -27,8 +27,10 @@ import static com.android.wm.shell.ShellTaskOrganizer.getWindowingMode;
|
||||
import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG;
|
||||
|
||||
import android.app.ActivityManager.RunningTaskInfo;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.SurfaceControl;
|
||||
import android.view.SurfaceSession;
|
||||
|
||||
@@ -36,6 +38,8 @@ import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.internal.protolog.common.ProtoLog;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.Transitions;
|
||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
|
||||
@@ -44,6 +48,8 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||
private static final boolean DEBUG = SplitScreenController.DEBUG;
|
||||
|
||||
private final ShellTaskOrganizer mTaskOrganizer;
|
||||
private final SyncTransactionQueue mSyncQueue;
|
||||
private final SparseArray<SurfaceControl> mLeashByTaskId = new SparseArray<>();
|
||||
|
||||
RunningTaskInfo mPrimary;
|
||||
RunningTaskInfo mSecondary;
|
||||
@@ -58,9 +64,11 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||
final SurfaceSession mSurfaceSession = new SurfaceSession();
|
||||
|
||||
SplitScreenTaskListener(SplitScreenController splitScreenController,
|
||||
ShellTaskOrganizer shellTaskOrganizer) {
|
||||
ShellTaskOrganizer shellTaskOrganizer,
|
||||
SyncTransactionQueue syncQueue) {
|
||||
mSplitScreenController = splitScreenController;
|
||||
mTaskOrganizer = shellTaskOrganizer;
|
||||
mSyncQueue = syncQueue;
|
||||
}
|
||||
|
||||
void init() {
|
||||
@@ -93,6 +101,11 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||
@Override
|
||||
public void onTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
|
||||
synchronized (this) {
|
||||
if (taskInfo.hasParentTask()) {
|
||||
handleChildTaskAppeared(taskInfo, leash);
|
||||
return;
|
||||
}
|
||||
|
||||
final int winMode = getWindowingMode(taskInfo);
|
||||
if (winMode == WINDOWING_MODE_SPLIT_SCREEN_PRIMARY) {
|
||||
ProtoLog.v(WM_SHELL_TASK_ORG,
|
||||
@@ -139,6 +152,11 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||
@Override
|
||||
public void onTaskVanished(RunningTaskInfo taskInfo) {
|
||||
synchronized (this) {
|
||||
if (taskInfo.hasParentTask()) {
|
||||
mLeashByTaskId.remove(taskInfo.taskId);
|
||||
return;
|
||||
}
|
||||
|
||||
final boolean isPrimaryTask = mPrimary != null
|
||||
&& taskInfo.token.equals(mPrimary.token);
|
||||
final boolean isSecondaryTask = mSecondary != null
|
||||
@@ -165,7 +183,41 @@ class SplitScreenTaskListener implements ShellTaskOrganizer.TaskListener {
|
||||
if (taskInfo.displayId != DEFAULT_DISPLAY) {
|
||||
return;
|
||||
}
|
||||
mSplitScreenController.post(() -> handleTaskInfoChanged(taskInfo));
|
||||
synchronized (this) {
|
||||
if (taskInfo.hasParentTask()) {
|
||||
handleChildTaskChanged(taskInfo);
|
||||
return;
|
||||
}
|
||||
|
||||
mSplitScreenController.post(() -> handleTaskInfoChanged(taskInfo));
|
||||
}
|
||||
}
|
||||
|
||||
private void handleChildTaskAppeared(RunningTaskInfo taskInfo, SurfaceControl leash) {
|
||||
mLeashByTaskId.put(taskInfo.taskId, leash);
|
||||
updateChildTaskSurface(taskInfo, leash, true /* firstAppeared */);
|
||||
}
|
||||
|
||||
private void handleChildTaskChanged(RunningTaskInfo taskInfo) {
|
||||
final SurfaceControl leash = mLeashByTaskId.get(taskInfo.taskId);
|
||||
updateChildTaskSurface(taskInfo, leash, false /* firstAppeared */);
|
||||
}
|
||||
|
||||
private void updateChildTaskSurface(
|
||||
RunningTaskInfo taskInfo, SurfaceControl leash, boolean firstAppeared) {
|
||||
final Rect taskBounds = taskInfo.getConfiguration().windowConfiguration.getBounds();
|
||||
final Point taskPositionInParent = taskInfo.positionInParent;
|
||||
final Rect corp = new Rect(taskBounds);
|
||||
corp.offset(-taskBounds.left, -taskBounds.top);
|
||||
mSyncQueue.runInSync(t -> {
|
||||
t.setWindowCrop(leash, corp);
|
||||
t.setPosition(leash, taskPositionInParent.x, taskPositionInParent.y);
|
||||
if (firstAppeared && !Transitions.ENABLE_SHELL_TRANSITIONS) {
|
||||
t.setAlpha(leash, 1f);
|
||||
t.setMatrix(leash, 1, 0, 0, 1);
|
||||
t.show(leash);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -247,6 +247,20 @@ public class ShellTaskOrganizerTests {
|
||||
assertTrue(gotException);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetParentTaskListener() {
|
||||
RunningTaskInfo task1 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
|
||||
TrackingTaskListener mwListener = new TrackingTaskListener();
|
||||
mOrganizer.onTaskAppeared(task1, null);
|
||||
mOrganizer.addListenerForTaskId(mwListener, task1.taskId);
|
||||
RunningTaskInfo task2 = createTaskInfo(1, WINDOWING_MODE_MULTI_WINDOW);
|
||||
task2.parentTaskId = task1.taskId;
|
||||
|
||||
mOrganizer.onTaskAppeared(task2, null);
|
||||
|
||||
assertTrue(mwListener.appeared.contains(task2));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testTaskInfoToTaskListenerType_whenLetterboxBoundsPassed_returnsLetterboxType() {
|
||||
RunningTaskInfo taskInfo = createTaskInfo(
|
||||
|
||||
@@ -125,7 +125,6 @@ import static com.android.server.wm.Task.ActivityState.PAUSED;
|
||||
import static com.android.server.wm.Task.ActivityState.PAUSING;
|
||||
import static com.android.server.wm.Task.ActivityState.RESUMED;
|
||||
import static com.android.server.wm.Task.ActivityState.STARTED;
|
||||
import static com.android.server.wm.Task.ActivityState.STOPPED;
|
||||
import static com.android.server.wm.Task.ActivityState.STOPPING;
|
||||
import static com.android.server.wm.TaskProto.ACTIVITY_TYPE;
|
||||
import static com.android.server.wm.TaskProto.BOUNDS;
|
||||
@@ -4127,6 +4126,10 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
forAllActivities(r -> {
|
||||
info.addLaunchCookie(r.mLaunchCookie);
|
||||
});
|
||||
final Task rootTask = getRootTask();
|
||||
info.parentTaskId = rootTask == getParent() && rootTask.mCreatedByOrganizer
|
||||
? rootTask.mTaskId
|
||||
: INVALID_TASK_ID;
|
||||
}
|
||||
|
||||
@Nullable PictureInPictureParams getPictureInPictureParams() {
|
||||
@@ -4843,6 +4846,17 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
return mTaskOrganizer != null;
|
||||
}
|
||||
|
||||
private boolean canBeOrganized() {
|
||||
// All root tasks can be organized
|
||||
if (isRootTask()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Task could be organized if it's the direct child of the root created by organizer.
|
||||
final Task rootTask = getRootTask();
|
||||
return rootTask == getParent() && rootTask.mCreatedByOrganizer;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean showSurfaceOnCreation() {
|
||||
// Organized tasks handle their own surface visibility
|
||||
@@ -4991,7 +5005,7 @@ class Task extends WindowContainer<WindowContainer> {
|
||||
// is created.
|
||||
return false;
|
||||
}
|
||||
if (!isRootTask()) {
|
||||
if (!canBeOrganized()) {
|
||||
return setTaskOrganizer(null);
|
||||
}
|
||||
|
||||
|
||||
@@ -976,6 +976,21 @@ public class WindowOrganizerTests extends WindowTestsBase {
|
||||
});
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReparentToOrganizedTask() {
|
||||
final ITaskOrganizer organizer = registerMockOrganizer();
|
||||
Task rootTask = mWm.mAtmService.mTaskOrganizerController.createRootTask(
|
||||
mDisplayContent, WINDOWING_MODE_SPLIT_SCREEN_PRIMARY, null);
|
||||
final Task task1 = createStack();
|
||||
final Task task2 = createTask(rootTask, false /* fakeDraw */);
|
||||
WindowContainerTransaction wct = new WindowContainerTransaction();
|
||||
wct.reparent(task1.mRemoteToken.toWindowContainerToken(),
|
||||
rootTask.mRemoteToken.toWindowContainerToken(), true /* onTop */);
|
||||
mWm.mAtmService.mWindowOrganizerController.applyTransaction(wct);
|
||||
assertTrue(task1.isOrganized());
|
||||
assertTrue(task2.isOrganized());
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies that task vanished is called for a specific task.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user