Fix back stack for PiP from multi-activity Task
Details in design doc go/pip-and-back Video: http://recall/-/aaaaaabFQoRHlzixHdtY/g8lbXnC8ln0t54ARxfPELo Bug: 184758170 Test: ensure back stack works for Netflix, see video Test: atest PinnedStackTests Test: atest RootWindowContainerTests Change-Id: I9e2f8d0d50dd107ff30fd7afe6273d8347aac803
This commit is contained in:
@@ -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 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 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 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 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 startSystemLockTaskMode(int);
|
||||||
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void stopSystemLockTaskMode();
|
method @RequiresPermission(android.Manifest.permission.MANAGE_ACTIVITY_TASKS) public void stopSystemLockTaskMode();
|
||||||
|
|||||||
@@ -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) {
|
public boolean removeTask(int taskId) {
|
||||||
try {
|
try {
|
||||||
return getService().removeTask(taskId);
|
return getService().removeTask(taskId);
|
||||||
|
|||||||
@@ -308,6 +308,7 @@ message TaskProto {
|
|||||||
optional float minimize_amount = 27;
|
optional float minimize_amount = 27;
|
||||||
optional bool created_by_organizer = 28;
|
optional bool created_by_organizer = 28;
|
||||||
optional string affinity = 29;
|
optional string affinity = 29;
|
||||||
|
optional bool has_child_pip_activity = 30;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* represents ActivityRecordProto */
|
/* represents ActivityRecordProto */
|
||||||
|
|||||||
@@ -587,7 +587,14 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
|
|
||||||
AnimatingActivityRegistry mAnimatingActivityRegistry;
|
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;
|
boolean firstWindowDrawn;
|
||||||
/** Whether the visible window(s) of this activity is drawn. */
|
/** 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));
|
pw.println(prefix + "configChanges=0x" + Integer.toHexString(info.configChanges));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (mLastParentBeforePip != null) {
|
||||||
|
pw.println(prefix + "lastParentTaskIdBeforePip=" + mLastParentBeforePip.mTaskId);
|
||||||
|
}
|
||||||
|
|
||||||
dumpLetterboxInfo(pw, prefix);
|
dumpLetterboxInfo(pw, prefix);
|
||||||
}
|
}
|
||||||
@@ -1349,7 +1359,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
if (getDisplayContent() != null) {
|
if (getDisplayContent() != null) {
|
||||||
getDisplayContent().mClosingApps.remove(this);
|
getDisplayContent().mClosingApps.remove(this);
|
||||||
}
|
}
|
||||||
} else if (mLastParent != null && mLastParent.getRootTask() != null) {
|
} else if (mLastKnownParent != null && mLastKnownParent.getRootTask() != null) {
|
||||||
task.getRootTask().mExitingActivities.remove(this);
|
task.getRootTask().mExitingActivities.remove(this);
|
||||||
}
|
}
|
||||||
final Task rootTask = getRootTask();
|
final Task rootTask = getRootTask();
|
||||||
@@ -1362,7 +1372,11 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
? rootTask.getAnimatingActivityRegistry()
|
? rootTask.getAnimatingActivityRegistry()
|
||||||
: null;
|
: null;
|
||||||
|
|
||||||
mLastParent = task;
|
mLastKnownParent = task;
|
||||||
|
if (mLastKnownParent == mLastParentBeforePip) {
|
||||||
|
// Activity's reparented back from pip, clear the links once established
|
||||||
|
clearLastParentBeforePip();
|
||||||
|
}
|
||||||
|
|
||||||
updateColorTransform();
|
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() {
|
private void updateColorTransform() {
|
||||||
if (mSurfaceControl != null && mLastAppSaturationInfo != null) {
|
if (mSurfaceControl != null && mLastAppSaturationInfo != null) {
|
||||||
getPendingTransaction().setColorTransform(mSurfaceControl,
|
getPendingTransaction().setColorTransform(mSurfaceControl,
|
||||||
@@ -3434,6 +3468,7 @@ final class ActivityRecord extends WindowToken implements WindowManagerService.A
|
|||||||
*/
|
*/
|
||||||
void cleanUp(boolean cleanServices, boolean setState) {
|
void cleanUp(boolean cleanServices, boolean setState) {
|
||||||
task.cleanUpActivityReferences(this);
|
task.cleanUpActivityReferences(this);
|
||||||
|
clearLastParentBeforePip();
|
||||||
|
|
||||||
deferRelaunchUntilPaused = false;
|
deferRelaunchUntilPaused = false;
|
||||||
frozenBeforeDestroy = false;
|
frozenBeforeDestroy = false;
|
||||||
|
|||||||
@@ -1415,6 +1415,9 @@ class RecentTasks {
|
|||||||
return true;
|
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) {
|
if (mMaxNumVisibleTasks >= 0) {
|
||||||
// Always keep up to the max number of recent tasks, but return false afterwards
|
// Always keep up to the max number of recent tasks, but return false afterwards
|
||||||
return numVisibleTasks <= mMaxNumVisibleTasks;
|
return numVisibleTasks <= mMaxNumVisibleTasks;
|
||||||
|
|||||||
@@ -2124,6 +2124,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
|
|||||||
.setDeferTaskAppear(true)
|
.setDeferTaskAppear(true)
|
||||||
.setHasBeenVisible(true)
|
.setHasBeenVisible(true)
|
||||||
.build();
|
.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
|
// 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
|
// non-fullscreen bounds. Then when this new PIP task exits PIP, it can restore
|
||||||
// to its previous freeform bounds.
|
// to its previous freeform bounds.
|
||||||
|
|||||||
@@ -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.CREATED_BY_ORGANIZER;
|
||||||
import static com.android.server.wm.TaskProto.DISPLAY_ID;
|
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.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.LAST_NON_FULLSCREEN_BOUNDS;
|
||||||
import static com.android.server.wm.TaskProto.MIN_HEIGHT;
|
import static com.android.server.wm.TaskProto.MIN_HEIGHT;
|
||||||
import static com.android.server.wm.TaskProto.MIN_WIDTH;
|
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.
|
// The task will be removed when TaskOrganizer, which is managing the task, is destroyed.
|
||||||
boolean mRemoveWithTaskOrganizer;
|
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,
|
private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
|
||||||
Intent _affinityIntent, String _affinity, String _rootAffinity,
|
Intent _affinityIntent, String _affinity, String _rootAffinity,
|
||||||
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
|
ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
|
||||||
@@ -1841,6 +1850,10 @@ class Task extends WindowContainer<WindowContainer> {
|
|||||||
|
|
||||||
/** Completely remove all activities associated with an existing task. */
|
/** Completely remove all activities associated with an existing task. */
|
||||||
void performClearTask(String reason) {
|
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.
|
// Broken down into to cases to avoid object create due to capturing mStack.
|
||||||
if (getRootTask() == null) {
|
if (getRootTask() == null) {
|
||||||
forAllActivities((r) -> {
|
forAllActivities((r) -> {
|
||||||
@@ -4449,6 +4462,7 @@ class Task extends WindowContainer<WindowContainer> {
|
|||||||
}
|
}
|
||||||
pw.print(prefix); pw.print("taskId=" + mTaskId);
|
pw.print(prefix); pw.print("taskId=" + mTaskId);
|
||||||
pw.println(" rootTaskId=" + getRootTaskId());
|
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("mHasBeenVisible="); pw.println(getHasBeenVisible());
|
||||||
pw.print(prefix); pw.print("mResizeMode=");
|
pw.print(prefix); pw.print("mResizeMode=");
|
||||||
pw.print(ActivityInfo.resizeModeToString(mResizeMode));
|
pw.print(ActivityInfo.resizeModeToString(mResizeMode));
|
||||||
@@ -5328,7 +5342,6 @@ class Task extends WindowContainer<WindowContainer> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
final int currentMode = getWindowingMode();
|
final int currentMode = getWindowingMode();
|
||||||
final int currentOverrideMode = getRequestedOverrideWindowingMode();
|
|
||||||
final Task topTask = getTopMostTask();
|
final Task topTask = getTopMostTask();
|
||||||
int windowingMode = preferredWindowingMode;
|
int windowingMode = preferredWindowingMode;
|
||||||
|
|
||||||
@@ -5397,9 +5410,26 @@ class Task extends WindowContainer<WindowContainer> {
|
|||||||
mTaskSupervisor.mNoAnimActivities.add(topActivity);
|
mTaskSupervisor.mNoAnimActivities.add(topActivity);
|
||||||
}
|
}
|
||||||
super.setWindowingMode(windowingMode);
|
super.setWindowingMode(windowingMode);
|
||||||
// setWindowingMode triggers an onConfigurationChanged cascade which can result in a
|
|
||||||
// different resolved windowing mode (usually when preferredWindowingMode is UNDEFINED).
|
// Try reparent pinned activity back to its original task after onConfigurationChanged
|
||||||
windowingMode = getWindowingMode();
|
// 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) {
|
if (creating) {
|
||||||
// Nothing else to do if we don't have a window container yet. E.g. call from ctor.
|
// 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();
|
final Task task = getBottomMostTask();
|
||||||
setWindowingMode(WINDOWING_MODE_UNDEFINED);
|
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);
|
mTaskSupervisor.scheduleUpdatePictureInPictureModeIfNeeded(task, this);
|
||||||
});
|
});
|
||||||
@@ -7831,6 +7865,7 @@ class Task extends WindowContainer<WindowContainer> {
|
|||||||
|
|
||||||
proto.write(CREATED_BY_ORGANIZER, mCreatedByOrganizer);
|
proto.write(CREATED_BY_ORGANIZER, mCreatedByOrganizer);
|
||||||
proto.write(AFFINITY, affinity);
|
proto.write(AFFINITY, affinity);
|
||||||
|
proto.write(HAS_CHILD_PIP_ACTIVITY, mChildPipActivity != null);
|
||||||
|
|
||||||
proto.end(token);
|
proto.end(token);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user