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);
|
||||
|
||||
final boolean isTaskSwitch = startedTask != prevTopTask && !startedTask.isEmbedded();
|
||||
mTargetRootTask.startActivityLocked(mStartActivity,
|
||||
topRootTask != null ? topRootTask.getTopNonFinishingActivity() : null, newTask,
|
||||
isTaskSwitch, mOptions, sourceRecord);
|
||||
mTargetRootTask.startActivityLocked(mStartActivity, topRootTask, newTask, isTaskSwitch,
|
||||
mOptions, sourceRecord);
|
||||
if (mDoResume) {
|
||||
final ActivityRecord topTaskActivity = startedTask.topRunningActivityLocked();
|
||||
if (!mTargetRootTask.isTopActivityFocusable()
|
||||
|
||||
@@ -5031,9 +5031,9 @@ class Task extends TaskFragment {
|
||||
return mRootWindowContainer.resumeHomeActivity(prev, reason, getDisplayArea());
|
||||
}
|
||||
|
||||
void startActivityLocked(ActivityRecord r, @Nullable ActivityRecord focusedTopActivity,
|
||||
boolean newTask, boolean isTaskSwitch, ActivityOptions options,
|
||||
@Nullable ActivityRecord sourceRecord) {
|
||||
void startActivityLocked(ActivityRecord r, @Nullable Task topTask, boolean newTask,
|
||||
boolean isTaskSwitch, ActivityOptions options, @Nullable ActivityRecord sourceRecord) {
|
||||
final ActivityRecord pipCandidate = findEnterPipOnTaskSwitchCandidate(topTask);
|
||||
Task rTask = r.getTask();
|
||||
final boolean allowMoveToFront = options == null || !options.getAvoidMoveToFront();
|
||||
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
|
||||
// would not be considered an overlay on top of the current activity
|
||||
// (eg. not fullscreen, or the assistant)
|
||||
if (canEnterPipOnTaskSwitch(focusedTopActivity,
|
||||
null /* toFrontTask */, r, options)) {
|
||||
focusedTopActivity.supportsEnterPipOnTaskSwitch = true;
|
||||
}
|
||||
enableEnterPipOnTaskSwitch(pipCandidate,
|
||||
null /* toFrontTask */, r, options);
|
||||
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
|
||||
* {@param toFrontActivity} should be set.
|
||||
*/
|
||||
private boolean canEnterPipOnTaskSwitch(ActivityRecord pipCandidate,
|
||||
Task toFrontTask, ActivityRecord toFrontActivity, ActivityOptions opts) {
|
||||
private static void enableEnterPipOnTaskSwitch(@Nullable ActivityRecord pipCandidate,
|
||||
@Nullable Task toFrontTask, @Nullable ActivityRecord toFrontActivity,
|
||||
@Nullable ActivityOptions opts) {
|
||||
if (pipCandidate == null) {
|
||||
return;
|
||||
}
|
||||
if (opts != null && opts.disallowEnterPictureInPictureWhileLaunching()) {
|
||||
// Ensure the caller has requested not to trigger auto-enter PiP
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
if (pipCandidate == null || pipCandidate.inPinnedWindowingMode()) {
|
||||
// Ensure that we do not trigger entering PiP an activity on the root pinned task
|
||||
return false;
|
||||
if (pipCandidate.inPinnedWindowingMode()) {
|
||||
// Ensure that we do not trigger entering PiP an activity on the root pinned task.
|
||||
return;
|
||||
}
|
||||
final boolean isTransient = opts != null && opts.getTransientLaunch();
|
||||
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
|
||||
// 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.
|
||||
return false;
|
||||
return;
|
||||
}
|
||||
return true;
|
||||
pipCandidate.supportsEnterPipOnTaskSwitch = true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -5492,9 +5515,8 @@ class Task extends TaskFragment {
|
||||
AppTimeTracker timeTracker, boolean deferResume, String reason) {
|
||||
if (DEBUG_SWITCH) Slog.v(TAG_SWITCH, "moveTaskToFront: " + tr);
|
||||
|
||||
final Task topRootTask = getDisplayArea().getTopRootTask();
|
||||
final ActivityRecord topActivity = topRootTask != null
|
||||
? topRootTask.getTopNonFinishingActivity() : null;
|
||||
final ActivityRecord pipCandidate = findEnterPipOnTaskSwitchCandidate(
|
||||
getDisplayArea().getTopRootTask());
|
||||
|
||||
if (tr != this && !tr.isDescendantOf(this)) {
|
||||
// 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
|
||||
// on top
|
||||
// of the current activity (eg. not fullscreen, or the assistant)
|
||||
if (canEnterPipOnTaskSwitch(topActivity, tr, null /* toFrontActivity */,
|
||||
options)) {
|
||||
topActivity.supportsEnterPipOnTaskSwitch = true;
|
||||
}
|
||||
enableEnterPipOnTaskSwitch(pipCandidate, tr, null /* toFrontActivity */, options);
|
||||
|
||||
if (!deferResume) {
|
||||
mRootWindowContainer.resumeFocusedTasksTopActivities();
|
||||
|
||||
@@ -2693,7 +2693,7 @@ public class ActivityRecordTests extends WindowTestsBase {
|
||||
.resumeFocusedTasksTopActivities();
|
||||
// Make mVisibleSetFromTransferredStartingWindow true.
|
||||
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 */,
|
||||
null /* sourceRecord */);
|
||||
middle.makeFinishingLocked();
|
||||
@@ -2706,7 +2706,7 @@ public class ActivityRecordTests extends WindowTestsBase {
|
||||
// a visible activity.
|
||||
top.setVisible(false);
|
||||
// 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 */,
|
||||
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.spyOn;
|
||||
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.assertFalse;
|
||||
import static org.junit.Assert.assertTrue;
|
||||
import static org.mockito.Mockito.clearInvocations;
|
||||
|
||||
import android.graphics.Rect;
|
||||
@@ -170,4 +172,34 @@ public class TaskFragmentTest extends WindowTestsBase {
|
||||
false /* preserveWindows */);
|
||||
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