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

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

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

parents bb61650b 96f7464d
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);
    }
}