diff options
| author | 2022-03-25 23:31:09 +0800 | |
|---|---|---|
| committer | 2022-04-11 11:02:29 +0800 | |
| commit | 96f7464dbd540c56e95ed6973b0617f2aa0b22d0 (patch) | |
| tree | bc8c3078b6f609347269edfb511ca774da2067f4 | |
| parent | 94bba02785c0f845bbb8c1236458c32659f07555 (diff) | |
Support enter PIP on Task switch for TaskFragment
Before, when the Task contains more than one visible TaskFragments,
only the activity on the top would support enter pip on task swtich.
Now, activities on any visible TaskFragments can have the chance to
enter pip on task switch.
Bug: 225371112
Test: atest WmTests:TaskFragmentTest
Change-Id: I1721b3e0476927dffe6d8367c8ede433b10af837
4 files changed, 78 insertions, 28 deletions
diff --git a/services/core/java/com/android/server/wm/ActivityStarter.java b/services/core/java/com/android/server/wm/ActivityStarter.java index 003268b33cdc..1f78f6f6e129 100644 --- a/services/core/java/com/android/server/wm/ActivityStarter.java +++ b/services/core/java/com/android/server/wm/ActivityStarter.java @@ -1874,9 +1874,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() diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java index 6ab3916425f9..a46544d6c902 100644 --- a/services/core/java/com/android/server/wm/Task.java +++ b/services/core/java/com/android/server/wm/Task.java @@ -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(); diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java index 3be70114172b..31bc2818978d 100644 --- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java @@ -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 */); diff --git a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java index 189a1dacb891..971826dd09b6 100644 --- a/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java @@ -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); + } } |