Merge "Support enter PIP on Task switch for TaskFragment" into tm-dev
This commit is contained in:
@@ -1884,9 +1884,8 @@ class ActivityStarter {
|
|||||||
false /* forceSend */, mStartActivity);
|
false /* forceSend */, mStartActivity);
|
||||||
|
|
||||||
final boolean isTaskSwitch = startedTask != prevTopTask && !startedTask.isEmbedded();
|
final boolean isTaskSwitch = startedTask != prevTopTask && !startedTask.isEmbedded();
|
||||||
mTargetRootTask.startActivityLocked(mStartActivity,
|
mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,
|
||||||
topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
|
mOptions, sourceRecord);
|
||||||
isTaskSwitch, mOptions, sourceRecord);
|
|
||||||
if (mDoResume) {
|
if (mDoResume) {
|
||||||
final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
|
final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
|
||||||
if (!mTargetRootTask.isTopActivityFocusable()
|
if (!mTargetRootTask.isTopActivityFocusable()
|
||||||
|
|||||||
@@ -5031,9 +5031,9 @@ class Task extends TaskFragment {
|
|||||||
return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea());
|
return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea());
|
||||||
}
|
}
|
||||||
|
|
||||||
void startActivityLocked(ActivityRecord r, @Nullable ActivityRecord focusedTopActivity,
|
void startActivityLocked(ActivityRecord r, @Nullable Task topTask, boolean newTask,
|
||||||
boolean newTask, boolean isTaskSwitch, ActivityOptions options,
|
boolean isTaskSwitch, ActivityOptions options, @Nullable ActivityRecord sourceRecord) {
|
||||||
@Nullable ActivityRecord sourceRecord) {
|
final ActivityRecord pipCandidate = findEnterPipOnTaskSwitchCandidate(topTask);
|
||||||
Task rTask = r.getTask();
|
Task rTask = r.getTask();
|
||||||
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
|
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
|
||||||
final boolean isOrhasTask = rTask == this || hasChild(rTask);
|
final boolean isOrhasTask = rTask == this || hasChild(rTask);
|
||||||
@@ -5099,10 +5099,8 @@ class Task extends TaskFragment {
|
|||||||
// supporting picture-in-picture while pausing only if the starting activity
|
// supporting picture-in-picture while pausing only if the starting activity
|
||||||
// would not be considered an overlay on top of the current activity
|
// would not be considered an overlay on top of the current activity
|
||||||
// (eg. not fullscreen, or the assistant)
|
// (eg. not fullscreen, or the assistant)
|
||||||
if (canEnterPipOnTaskSwitch(focusedTopActivity,
|
enableEnterPipOnTaskSwitch(pipCandidate,
|
||||||
null /* toFrontTask */, r, options)) {
|
null /* toFrontTask */, r, options);
|
||||||
focusedTopActivity.supportsEnterPipOnTaskSwitch = true;
|
|
||||||
}
|
|
||||||
transit = TRANSIT_OLD_TASK_OPEN;
|
transit = TRANSIT_OLD_TASK_OPEN;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -5159,20 +5157,44 @@ class Task extends TaskFragment {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** On Task switch, finds the top activity that supports PiP. */
|
||||||
|
@Nullable
|
||||||
|
static ActivityRecord findEnterPipOnTaskSwitchCandidate(@Nullable Task topTask) {
|
||||||
|
if (topTask == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
final ActivityRecord[] candidate = new ActivityRecord[1];
|
||||||
|
topTask.forAllLeafTaskFragments(tf -> {
|
||||||
|
// Find the top activity that may enter Pip while pausing.
|
||||||
|
final ActivityRecord topActivity = tf.getTopNonFinishingActivity();
|
||||||
|
if (topActivity != null && topActivity.isState(RESUMED, PAUSING)
|
||||||
|
&& topActivity.supportsPictureInPicture()) {
|
||||||
|
candidate[0] = topActivity;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
});
|
||||||
|
return candidate[0];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @return Whether the switch to another task can trigger the currently running activity to
|
* When switching to another Task, marks the currently PiP candidate activity as supporting to
|
||||||
* enter PiP while it is pausing (if supported). Only one of {@param toFrontTask} or
|
* enter PiP while it is pausing (if supported). Only one of {@param toFrontTask} or
|
||||||
* {@param toFrontActivity} should be set.
|
* {@param toFrontActivity} should be set.
|
||||||
*/
|
*/
|
||||||
private boolean canEnterPipOnTaskSwitch(ActivityRecord pipCandidate,
|
private static void enableEnterPipOnTaskSwitch(@Nullable ActivityRecord pipCandidate,
|
||||||
Task toFrontTask, ActivityRecord toFrontActivity, ActivityOptions opts) {
|
@Nullable Task toFrontTask, @Nullable ActivityRecord toFrontActivity,
|
||||||
|
@Nullable ActivityOptions opts) {
|
||||||
|
if (pipCandidate == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (opts != null && opts.disallowEnterPictureInPictureWhileLaunching()) {
|
if (opts != null && opts.disallowEnterPictureInPictureWhileLaunching()) {
|
||||||
// Ensure the caller has requested not to trigger auto-enter PiP
|
// Ensure the caller has requested not to trigger auto-enter PiP
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
if (pipCandidate == null || pipCandidate.inPinnedWindowingMode()) {
|
if (pipCandidate.inPinnedWindowingMode()) {
|
||||||
// Ensure that we do not trigger entering PiP an activity on the root pinned task
|
// Ensure that we do not trigger entering PiP an activity on the root pinned task.
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
final boolean isTransient = opts != null && opts.getTransientLaunch();
|
final boolean isTransient = opts != null && opts.getTransientLaunch();
|
||||||
final Task targetRootTask = toFrontTask != null
|
final Task targetRootTask = toFrontTask != null
|
||||||
@@ -5181,9 +5203,10 @@ class Task extends TaskFragment {
|
|||||||
// Ensure the task/activity being brought forward is not the assistant and is not
|
// Ensure the task/activity being brought forward is not the assistant and is not
|
||||||
// transient. In the case of transient-launch, we want to wait until the end of the
|
// transient. In the case of transient-launch, we want to wait until the end of the
|
||||||
// transition and only allow switch if the transient launch was committed.
|
// transition and only allow switch if the transient launch was committed.
|
||||||
return false;
|
return;
|
||||||
}
|
}
|
||||||
return true;
|
pipCandidate.supportsEnterPipOnTaskSwitch = true;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -5492,9 +5515,8 @@ class Task extends TaskFragment {
|
|||||||
AppTimeTracker timeTracker, boolean deferResume, String reason) {
|
AppTimeTracker timeTracker, boolean deferResume, String reason) {
|
||||||
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
|
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
|
||||||
|
|
||||||
final Task topRootTask = getDisplayArea().getTopRootTask();
|
final ActivityRecord pipCandidate = findEnterPipOnTaskSwitchCandidate(
|
||||||
final ActivityRecord topActivity = topRootTask != null
|
getDisplayArea().getTopRootTask());
|
||||||
? topRootTask.getTopNonFinishingActivity() : null;
|
|
||||||
|
|
||||||
if (tr != this && !tr.isDescendantOf(this)) {
|
if (tr != this && !tr.isDescendantOf(this)) {
|
||||||
// nothing to do!
|
// nothing to do!
|
||||||
@@ -5549,10 +5571,7 @@ class Task extends TaskFragment {
|
|||||||
// picture-in-picture while paused only if the task would not be considered an oerlay
|
// picture-in-picture while paused only if the task would not be considered an oerlay
|
||||||
// on top
|
// on top
|
||||||
// of the current activity (eg. not fullscreen, or the assistant)
|
// of the current activity (eg. not fullscreen, or the assistant)
|
||||||
if (canEnterPipOnTaskSwitch(topActivity, tr, null /* toFrontActivity */,
|
enableEnterPipOnTaskSwitch(pipCandidate, tr, null /* toFrontActivity */, options);
|
||||||
options)) {
|
|
||||||
topActivity.supportsEnterPipOnTaskSwitch = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!deferResume) {
|
if (!deferResume) {
|
||||||
mRootWindowContainer.resumeFocusedTasksTopActivities();
|
mRootWindowContainer.resumeFocusedTasksTopActivities();
|
||||||
|
|||||||
@@ -2693,7 +2693,7 @@ public class ActivityRecordTests extends WindowTestsBase {
|
|||||||
.resumeFocusedTasksTopActivities();
|
.resumeFocusedTasksTopActivities();
|
||||||
// Make mVisibleSetFromTransferredStartingWindow true.
|
// Make mVisibleSetFromTransferredStartingWindow true.
|
||||||
final ActivityRecord middle = new ActivityBuilder(mAtm).setTask(task).build();
|
final ActivityRecord middle = new ActivityBuilder(mAtm).setTask(task).build();
|
||||||
task.startActivityLocked(middle, null /* focusedTopActivity */,
|
task.startActivityLocked(middle, null /* topTask */,
|
||||||
false /* newTask */, false /* isTaskSwitch */, null /* options */,
|
false /* newTask */, false /* isTaskSwitch */, null /* options */,
|
||||||
null /* sourceRecord */);
|
null /* sourceRecord */);
|
||||||
middle.makeFinishingLocked();
|
middle.makeFinishingLocked();
|
||||||
@@ -2706,7 +2706,7 @@ public class ActivityRecordTests extends WindowTestsBase {
|
|||||||
// a visible activity.
|
// a visible activity.
|
||||||
top.setVisible(false);
|
top.setVisible(false);
|
||||||
// The finishing middle should be able to transfer starting window to top.
|
// The finishing middle should be able to transfer starting window to top.
|
||||||
task.startActivityLocked(top, null /* focusedTopActivity */,
|
task.startActivityLocked(top, null /* topTask */,
|
||||||
false /* newTask */, false /* isTaskSwitch */, null /* options */,
|
false /* newTask */, false /* isTaskSwitch */, null /* options */,
|
||||||
null /* sourceRecord */);
|
null /* sourceRecord */);
|
||||||
|
|
||||||
|
|||||||
@@ -21,9 +21,11 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.doReturn;
|
|||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.never;
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
|
||||||
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
|
||||||
|
import static com.android.server.wm.ActivityRecord.State.RESUMED;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
import static org.junit.Assert.assertFalse;
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
import static org.mockito.Mockito.clearInvocations;
|
import static org.mockito.Mockito.clearInvocations;
|
||||||
|
|
||||||
import android.graphics.Rect;
|
import android.graphics.Rect;
|
||||||
@@ -170,4 +172,34 @@ public class TaskFragmentTest extends WindowTestsBase {
|
|||||||
false /* preserveWindows */);
|
false /* preserveWindows */);
|
||||||
assertEquals(true, activityBelow.isVisibleRequested());
|
assertEquals(true, activityBelow.isVisibleRequested());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testMoveTaskToFront_supportsEnterPipOnTaskSwitchForAdjacentTaskFragment() {
|
||||||
|
final Task bottomTask = createTask(mDisplayContent);
|
||||||
|
final ActivityRecord bottomActivity = createActivityRecord(bottomTask);
|
||||||
|
final Task topTask = createTask(mDisplayContent);
|
||||||
|
// First create primary TF, and then secondary TF, so that the secondary will be on the top.
|
||||||
|
final TaskFragment primaryTf = createTaskFragmentWithParentTask(
|
||||||
|
topTask, false /* createEmbeddedTask */);
|
||||||
|
final TaskFragment secondaryTf = createTaskFragmentWithParentTask(
|
||||||
|
topTask, false /* createEmbeddedTask */);
|
||||||
|
final ActivityRecord primaryActivity = primaryTf.getTopMostActivity();
|
||||||
|
final ActivityRecord secondaryActivity = secondaryTf.getTopMostActivity();
|
||||||
|
doReturn(true).when(primaryActivity).supportsPictureInPicture();
|
||||||
|
doReturn(false).when(secondaryActivity).supportsPictureInPicture();
|
||||||
|
|
||||||
|
primaryTf.setAdjacentTaskFragment(secondaryTf, false /* moveAdjacentTogether */);
|
||||||
|
primaryActivity.setState(RESUMED, "test");
|
||||||
|
secondaryActivity.setState(RESUMED, "test");
|
||||||
|
|
||||||
|
assertEquals(topTask, bottomTask.getDisplayArea().getTopRootTask());
|
||||||
|
|
||||||
|
// When moving Task to front, the resumed activity that supports PIP should support enter
|
||||||
|
// PIP on Task switch even if it is not the topmost in the Task.
|
||||||
|
bottomTask.moveTaskToFront(bottomTask, false /* noAnimation */, null /* options */,
|
||||||
|
null /* timeTracker */, "test");
|
||||||
|
|
||||||
|
assertTrue(primaryActivity.supportsEnterPipOnTaskSwitch);
|
||||||
|
assertFalse(secondaryActivity.supportsEnterPipOnTaskSwitch);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user