Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit db07082b authored by Chris Li's avatar Chris Li Committed by Android (Google) Code Review
Browse files

Merge changes from topic "presubmit-am-d8f5066444f243d0a0e8921fe51486e6" into tm-mainline-prod

* changes:
  [automerge] Support enter PIP on Task switch for TaskFragment 2p: 96f7464d
  Support enter PIP on Task switch for TaskFragment
parents 2e29466b d711b211
Loading
Loading
Loading
Loading
+2 −3
Original line number Diff line number Diff line
@@ -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()
+42 −23
Original line number Diff line number Diff line
@@ -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();
+2 −2
Original line number Diff line number Diff line
@@ -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 */);

+32 −0
Original line number Diff line number Diff line
@@ -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);
    }
}