diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 1063532af44f9..89be2ee2fa016 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -826,6 +826,26 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + /** + * Sets/removes the reparent leaf task flag for this {@code windowContainer}. + * When this is set, the server side will try to reparent the leaf task to task display area + * if there is an existing activity in history during the activity launch. This operation only + * support on the organized root task. + * @hide + */ + @NonNull + public WindowContainerTransaction setReparentLeafTaskIfRelaunch( + @NonNull WindowContainerToken windowContainer, boolean reparentLeafTaskIfRelaunch) { + final HierarchyOp hierarchyOp = + new HierarchyOp.Builder( + HierarchyOp.HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH) + .setContainer(windowContainer.asBinder()) + .setReparentLeafTaskIfRelaunch(reparentLeafTaskIfRelaunch) + .build(); + mHierarchyOps.add(hierarchyOp); + return this; + } + /** * Merges another WCT into this one. * @param transfer When true, this will transfer everything from other potentially leaving @@ -1242,6 +1262,7 @@ public final class WindowContainerTransaction implements Parcelable { public static final int HIERARCHY_OP_TYPE_FINISH_ACTIVITY = 21; public static final int HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT = 22; public static final int HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS = 23; + public static final int HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH = 24; // The following key(s) are for use with mLaunchOptions: // When launching a task (eg. from recents), this is the taskId to be launched. @@ -1294,6 +1315,8 @@ public final class WindowContainerTransaction implements Parcelable { private boolean mAlwaysOnTop; + private boolean mReparentLeafTaskIfRelaunch; + public static HierarchyOp createForReparent( @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) { return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT) @@ -1406,6 +1429,7 @@ public final class WindowContainerTransaction implements Parcelable { mPendingIntent = copy.mPendingIntent; mShortcutInfo = copy.mShortcutInfo; mAlwaysOnTop = copy.mAlwaysOnTop; + mReparentLeafTaskIfRelaunch = copy.mReparentLeafTaskIfRelaunch; } protected HierarchyOp(Parcel in) { @@ -1428,6 +1452,7 @@ public final class WindowContainerTransaction implements Parcelable { mPendingIntent = in.readTypedObject(PendingIntent.CREATOR); mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR); mAlwaysOnTop = in.readBoolean(); + mReparentLeafTaskIfRelaunch = in.readBoolean(); } public int getType() { @@ -1502,6 +1527,10 @@ public final class WindowContainerTransaction implements Parcelable { return mAlwaysOnTop; } + public boolean isReparentLeafTaskIfRelaunch() { + return mReparentLeafTaskIfRelaunch; + } + @Nullable public TaskFragmentCreationParams getTaskFragmentCreationOptions() { return mTaskFragmentCreationOptions; @@ -1582,6 +1611,9 @@ public final class WindowContainerTransaction implements Parcelable { + mReparent + "}"; case HIERARCHY_OP_TYPE_CLEAR_ADJACENT_ROOTS: return "{ClearAdjacentRoot: container=" + mContainer + "}"; + case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH: + return "{setReparentLeafTaskIfRelaunch: container= " + mContainer + + " reparentLeafTaskIfRelaunch= " + mReparentLeafTaskIfRelaunch + "}"; default: return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent + " mToTop=" + mToTop @@ -1612,6 +1644,7 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeTypedObject(mPendingIntent, flags); dest.writeTypedObject(mShortcutInfo, flags); dest.writeBoolean(mAlwaysOnTop); + dest.writeBoolean(mReparentLeafTaskIfRelaunch); } @Override @@ -1672,6 +1705,8 @@ public final class WindowContainerTransaction implements Parcelable { private boolean mAlwaysOnTop; + private boolean mReparentLeafTaskIfRelaunch; + Builder(int type) { mType = type; } @@ -1742,6 +1777,11 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + Builder setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch) { + mReparentLeafTaskIfRelaunch = reparentLeafTaskIfRelaunch; + return this; + } + Builder setShortcutInfo(@Nullable ShortcutInfo shortcutInfo) { mShortcutInfo = shortcutInfo; return this; @@ -1767,6 +1807,7 @@ public final class WindowContainerTransaction implements Parcelable { hierarchyOp.mAlwaysOnTop = mAlwaysOnTop; hierarchyOp.mTaskFragmentCreationOptions = mTaskFragmentCreationOptions; hierarchyOp.mShortcutInfo = mShortcutInfo; + hierarchyOp.mReparentLeafTaskIfRelaunch = mReparentLeafTaskIfRelaunch; return hierarchyOp; } diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 356cbdacbed6a..a93767ec8646f 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -498,6 +498,12 @@ class Task extends TaskFragment { */ boolean mInRemoveTask; + /** + * When set, disassociate the leaf task if relaunched and reparented it to TDA as root task if + * possible. + */ + boolean mReparentLeafTaskIfRelaunch; + private final AnimatingActivityRegistry mAnimatingActivityRegistry = new AnimatingActivityRegistry(); @@ -6064,6 +6070,12 @@ class Task extends TaskFragment { } } + void setReparentLeafTaskIfRelaunch(boolean reparentLeafTaskIfRelaunch) { + if (isOrganized()) { + mReparentLeafTaskIfRelaunch = reparentLeafTaskIfRelaunch; + } + } + @Override public void dumpDebug(ProtoOutputStream proto, long fieldId, @WindowTraceLogLevel int logLevel) { diff --git a/services/core/java/com/android/server/wm/TaskDisplayArea.java b/services/core/java/com/android/server/wm/TaskDisplayArea.java index f3ed937ce9240..25b58fa622e76 100644 --- a/services/core/java/com/android/server/wm/TaskDisplayArea.java +++ b/services/core/java/com/android/server/wm/TaskDisplayArea.java @@ -899,15 +899,16 @@ final class TaskDisplayArea extends DisplayArea { } } else if (candidateTask != null) { final int position = onTop ? POSITION_TOP : POSITION_BOTTOM; - final Task launchRootTask = getLaunchRootTask(resolvedWindowingMode, activityType, + final Task launchParentTask = getLaunchRootTask(resolvedWindowingMode, activityType, options, sourceTask, launchFlags, candidateTask); - if (launchRootTask != null) { + if (launchParentTask != null) { if (candidateTask.getParent() == null) { - launchRootTask.addChild(candidateTask, position); - } else if (candidateTask.getParent() != launchRootTask) { - candidateTask.reparent(launchRootTask, position); + launchParentTask.addChild(candidateTask, position); + } else if (candidateTask.getParent() != launchParentTask) { + candidateTask.reparent(launchParentTask, position); } - } else if (candidateTask.getDisplayArea() != this) { + } else if (candidateTask.getDisplayArea() != this + || candidateTask.getRootTask().mReparentLeafTaskIfRelaunch) { if (candidateTask.getParent() == null) { addChild(candidateTask, position); } else { diff --git a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java index da73fad99eb7a..ad46770432a10 100644 --- a/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java +++ b/services/core/java/com/android/server/wm/TaskLaunchParamsModifier.java @@ -165,9 +165,11 @@ class TaskLaunchParamsModifier implements LaunchParamsModifier { } // If the launch windowing mode is still undefined, inherit from the target task if the // task is already on the right display area (otherwise, the task may be on a different - // display area that has incompatible windowing mode). + // display area that has incompatible windowing mode or the task organizer request to + // disassociate the leaf task if relaunched and reparented it to TDA as root task). if (launchMode == WINDOWING_MODE_UNDEFINED - && task != null && task.getTaskDisplayArea() == suggestedDisplayArea) { + && task != null && task.getTaskDisplayArea() == suggestedDisplayArea + && !task.getRootTask().mReparentLeafTaskIfRelaunch) { launchMode = task.getWindowingMode(); if (DEBUG) { appendLog("inherit-from-task=" diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index aa1cf563da0bf..738adc360683d 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -43,6 +43,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_COMPANION_TASK_FRAGMENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_SHORTCUT; @@ -1233,7 +1234,7 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub WindowContainer.fromBinder(hop.getContainer()) .removeLocalInsetsSourceProvider(hop.getInsetsTypes()); break; - case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: + case HIERARCHY_OP_TYPE_SET_ALWAYS_ON_TOP: { final WindowContainer container = WindowContainer.fromBinder(hop.getContainer()); if (container == null || container.asDisplayArea() == null || !container.isAttached()) { @@ -1244,7 +1245,26 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub container.setAlwaysOnTop(hop.isAlwaysOnTop()); effects |= TRANSACT_EFFECTS_LIFECYCLE; break; - + } + case HIERARCHY_OP_TYPE_SET_REPARENT_LEAF_TASK_IF_RELAUNCH: { + final WindowContainer container = WindowContainer.fromBinder(hop.getContainer()); + final Task task = container != null ? container.asTask() : null; + if (task == null || !task.isAttached()) { + Slog.e(TAG, "Attempt to operate on unknown or detached container: " + + container); + break; + } + if (!task.mCreatedByOrganizer) { + throw new UnsupportedOperationException( + "Cannot set reparent leaf task flag on non-organized task : " + task); + } + if (!task.isRootTask()) { + throw new UnsupportedOperationException( + "Cannot set reparent leaf task flag on non-root task : " + task); + } + task.setReparentLeafTaskIfRelaunch(hop.isReparentLeafTaskIfRelaunch()); + break; + } } return effects; }