Merge "Allow children task of created-by-organizer task to be organized"

This commit is contained in:
Jerry Chang
2020-11-02 03:40:38 +00:00
committed by Android (Google) Code Review
8 changed files with 125 additions and 5 deletions

View File

@@ -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 {

View File

@@ -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
+ "}";
}
}

View File

@@ -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);

View File

@@ -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 =

View File

@@ -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);
}
});
}
/**

View File

@@ -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(

View File

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

View File

@@ -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.
*/