summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/api/test-current.txt1
-rw-r--r--core/java/android/app/ActivityTaskManager.java3
-rw-r--r--core/proto/android/server/windowmanagerservice.proto1
-rw-r--r--services/core/java/com/android/server/wm/ActivityRecord.java41
-rw-r--r--services/core/java/com/android/server/wm/RecentTasks.java3
-rw-r--r--services/core/java/com/android/server/wm/RootWindowContainer.java2
-rw-r--r--services/core/java/com/android/server/wm/Task.java45
7 files changed, 87 insertions, 9 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt
index 0541934fd665..a77bf32544e4 100644
--- a/core/api/test-current.txt
+++ b/core/api/test-current.txt
@@ -161,6 +161,7 @@ package android.app {
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void moveTaskToRootTask(int, int, boolean);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void removeRootTasksInWindowingModes(@NonNull int[]);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void removeRootTasksWithActivityTypes(@NonNull int[]);
+ method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public boolean removeTask(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void resizeTask(int, android.graphics.Rect);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void startSystemLockTaskMode(int);
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void stopSystemLockTaskMode();
diff --git a/core/java/android/app/ActivityTaskManager.java b/core/java/android/app/ActivityTaskManager.java
index 627017ce0893..28d6fbb36a47 100644
--- a/core/java/android/app/ActivityTaskManager.java
+++ b/core/java/android/app/ActivityTaskManager.java
@@ -469,7 +469,8 @@ public class ActivityTaskManager {
}
}
- /** @hide */
+ /** Removes task by a given taskId */
+ @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS)
public boolean removeTask(int taskId) {
try {
return getService().removeTask(taskId);
diff --git a/core/proto/android/server/windowmanagerservice.proto b/core/proto/android/server/windowmanagerservice.proto
index a7127ad79401..b157146e70a3 100644
--- a/core/proto/android/server/windowmanagerservice.proto
+++ b/core/proto/android/server/windowmanagerservice.proto
@@ -308,6 +308,7 @@ message TaskProto {
optional float minimize_amount = 27;
optional bool created_by_organizer = 28;
optional string affinity = 29;
+ optional bool has_child_pip_activity = 30;
}
/* represents ActivityRecordProto */
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index f5cfc9d86cf4..a3624e014e30 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -587,7 +587,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
AnimatingActivityRegistry mAnimatingActivityRegistry;
- private Task mLastParent;
+ // Set whenever the ActivityRecord gets reparented to a Task so we can know the last known
+ // parent was when the ActivityRecord is detached from the hierarchy
+ private Task mLastKnownParent;
+
+ // Set to the previous Task parent of the ActivityRecord when it is reparented to a new Task
+ // due to picture-in-picture. This gets cleared whenever this activity or the Task
+ // it references to gets removed. This should also be cleared when we move out of pip.
+ private Task mLastParentBeforePip;
boolean firstWindowDrawn;
/** Whether the visible window(s) of this activity is drawn. */
@@ -1096,6 +1103,9 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges));
}
}
+ if (mLastParentBeforePip != null) {
+ pw.println(prefix + "lastParentTaskIdBeforePip=" + mLastParentBeforePip.mTaskId);
+ }
dumpLetterboxInfo(pw, prefix);
}
@@ -1349,7 +1359,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
if (getDisplayContent() != null) {
getDisplayContent().mClosingApps.remove(this);
}
- } else if (mLastParent != null && mLastParent.getRootTask() != null) {
+ } else if (mLastKnownParent != null && mLastKnownParent.getRootTask() != null) {
task.getRootTask().mExitingActivities.remove(this);
}
final Task rootTask = getRootTask();
@@ -1362,7 +1372,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
? rootTask.getAnimatingActivityRegistry()
: null;
- mLastParent = task;
+ mLastKnownParent = task;
+ if (mLastKnownParent == mLastParentBeforePip) {
+ // Activity's reparented back from pip, clear the links once established
+ clearLastParentBeforePip();
+ }
updateColorTransform();
@@ -1381,6 +1395,26 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
}
}
+ /**
+ * Sets {@link #mLastParentBeforePip} to the current parent Task, it's caller's job to ensure
+ * {@link #getTask()} is set before this is called.
+ */
+ void setLastParentBeforePip() {
+ mLastParentBeforePip = getTask();
+ mLastParentBeforePip.mChildPipActivity = this;
+ }
+
+ private void clearLastParentBeforePip() {
+ if (mLastParentBeforePip != null) {
+ mLastParentBeforePip.mChildPipActivity = null;
+ mLastParentBeforePip = null;
+ }
+ }
+
+ @Nullable Task getLastParentBeforePip() {
+ return mLastParentBeforePip;
+ }
+
private void updateColorTransform() {
if (mSurfaceControl != null && mLastAppSaturationInfo != null) {
getPendingTransaction().setColorTransform(mSurfaceControl,
@@ -3434,6 +3468,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
*/
void cleanUp(boolean cleanServices, boolean setState) {
task.cleanUpActivityReferences(this);
+ clearLastParentBeforePip();
deferRelaunchUntilPaused = false;
frozenBeforeDestroy = false;
diff --git a/services/core/java/com/android/server/wm/RecentTasks.java b/services/core/java/com/android/server/wm/RecentTasks.java
index 6631a3e61e77..4bb48b0bdbe8 100644
--- a/services/core/java/com/android/server/wm/RecentTasks.java
+++ b/services/core/java/com/android/server/wm/RecentTasks.java
@@ -1415,6 +1415,9 @@ class RecentTasks {
return true;
}
+ // The given task if always treated as in visible range if it is the origin of pinned task.
+ if (task.mChildPipActivity != null) return true;
+
if (mMaxNumVisibleTasks >= 0) {
// Always keep up to the max number of recent tasks, but return false afterwards
return numVisibleTasks <= mMaxNumVisibleTasks;
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java
index 52551ec54b32..b9fc8b1222ee 100644
--- a/services/core/java/com/android/server/wm/RootWindowContainer.java
+++ b/services/core/java/com/android/server/wm/RootWindowContainer.java
@@ -2124,6 +2124,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
.setDeferTaskAppear(true)
.setHasBeenVisible(true)
.build();
+ // Establish bi-directional link between the original and pinned task.
+ r.setLastParentBeforePip();
// It's possible the task entering PIP is in freeform, so save the last
// non-fullscreen bounds. Then when this new PIP task exits PIP, it can restore
// to its previous freeform bounds.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 86904991616f..07f81c725d4d 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -131,6 +131,7 @@ import static com.android.server.wm.TaskProto.BOUNDS;
import static com.android.server.wm.TaskProto.CREATED_BY_ORGANIZER;
import static com.android.server.wm.TaskProto.DISPLAY_ID;
import static com.android.server.wm.TaskProto.FILLS_PARENT;
+import static com.android.server.wm.TaskProto.HAS_CHILD_PIP_ACTIVITY;
import static com.android.server.wm.TaskProto.LAST_NON_FULLSCREEN_BOUNDS;
import static com.android.server.wm.TaskProto.MIN_HEIGHT;
import static com.android.server.wm.TaskProto.MIN_WIDTH;
@@ -836,6 +837,14 @@ class Task extends WindowContainer<WindowContainer> {
// The task will be removed when TaskOrganizer, which is managing the task, is destroyed.
boolean mRemoveWithTaskOrganizer;
+ /**
+ * Reference to the pinned activity that is logically parented to this task, ie.
+ * the previous top activity within this task is put into pinned mode.
+ * This always gets cleared in pair with the ActivityRecord-to-Task link as seen in
+ * {@link ActivityRecord#clearLastParentBeforePip()}.
+ */
+ ActivityRecord mChildPipActivity;
+
private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
Intent _affinityIntent, String _affinity, String _rootAffinity,
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
@@ -1841,6 +1850,10 @@ class Task extends WindowContainer<WindowContainer> {
/** Completely remove all activities associated with an existing task. */
void performClearTask(String reason) {
+ // The original task is to be removed, try remove also the pinned task.
+ if (mChildPipActivity != null && mChildPipActivity.getTask() != null) {
+ mTaskSupervisor.removeRootTask(mChildPipActivity.getTask());
+ }
// Broken down into to cases to avoid object create due to capturing mStack.
if (getRootTask() == null) {
forAllActivities((r) -> {
@@ -4449,6 +4462,7 @@ class Task extends WindowContainer<WindowContainer> {
}
pw.print(prefix); pw.print("taskId=" + mTaskId);
pw.println(" rootTaskId=" + getRootTaskId());
+ pw.print(prefix); pw.println("hasChildPipActivity=" + (mChildPipActivity != null));
pw.print(prefix); pw.print("mHasBeenVisible="); pw.println(getHasBeenVisible());
pw.print(prefix); pw.print("mResizeMode=");
pw.print(ActivityInfo.resizeModeToString(mResizeMode));
@@ -5328,7 +5342,6 @@ class Task extends WindowContainer<WindowContainer> {
return;
}
final int currentMode = getWindowingMode();
- final int currentOverrideMode = getRequestedOverrideWindowingMode();
final Task topTask = getTopMostTask();
int windowingMode = preferredWindowingMode;
@@ -5397,9 +5410,26 @@ class Task extends WindowContainer<WindowContainer> {
mTaskSupervisor.mNoAnimActivities.add(topActivity);
}
super.setWindowingMode(windowingMode);
- // setWindowingMode triggers an onConfigurationChanged cascade which can result in a
- // different resolved windowing mode (usually when preferredWindowingMode is UNDEFINED).
- windowingMode = getWindowingMode();
+
+ // Try reparent pinned activity back to its original task after onConfigurationChanged
+ // cascade finishes. This is done on Task level instead of
+ // {@link ActivityRecord#onConfigurationChanged(Configuration)} since when we exit PiP,
+ // we set final windowing mode on the ActivityRecord first and then on its Task when
+ // the exit PiP transition finishes. Meanwhile, the exit transition is always
+ // performed on its original task, reparent immediately in ActivityRecord breaks it.
+ if (currentMode == WINDOWING_MODE_PINNED) {
+ if (topActivity != null && topActivity.getLastParentBeforePip() != null) {
+ // Do not reparent if the pinned task is in removal, indicated by the
+ // force hidden flag.
+ if (!isForceHidden()) {
+ final Task lastParentBeforePip = topActivity.getLastParentBeforePip();
+ topActivity.reparent(lastParentBeforePip,
+ lastParentBeforePip.getChildCount() /* top */,
+ "movePinnedActivityToOriginalTask");
+ lastParentBeforePip.moveToFront("movePinnedActivityToOriginalTask");
+ }
+ }
+ }
if (creating) {
// Nothing else to do if we don't have a window container yet. E.g. call from ctor.
@@ -7530,7 +7560,11 @@ class Task extends WindowContainer<WindowContainer> {
final Task task = getBottomMostTask();
setWindowingMode(WINDOWING_MODE_UNDEFINED);
- getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */);
+ // Task could have been removed from the hierarchy due to windowing mode change
+ // where its only child is reparented back to their original parent task.
+ if (isAttached()) {
+ getDisplayArea().positionChildAt(POSITION_TOP, this, false /* includingParents */);
+ }
mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this);
});
@@ -7831,6 +7865,7 @@ class Task extends WindowContainer<WindowContainer> {
proto.write(CREATED_BY_ORGANIZER, mCreatedByOrganizer);
proto.write(AFFINITY, affinity);
+ proto.write(HAS_CHILD_PIP_ACTIVITY, mChildPipActivity != null);
proto.end(token);
}