Merge "Support enter PIP on Task switch for TaskFragment" into tm-dev

This commit is contained in:
Chris Li
2022-04-11 07:19:07 +00:00
committed by Android (Google) Code Review
4 changed files with 78 additions and 28 deletions

View File

@@ -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()

View File

@@ -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();

View File

@@ -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 */);

View File

@@ -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);
}
}