summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--services/core/java/com/android/server/wm/ActivityStarter.java5
-rw-r--r--services/core/java/com/android/server/wm/Task.java65
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java4
-rw-r--r--services/tests/wmtests/src/com/android/server/wm/TaskFragmentTest.java32
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);
+ }
}