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

Commit 81441aa5 authored by Eric Lin's avatar Eric Lin
Browse files

Mark pinned activity task as auto-removeable from recents.

Tasks resumed from Picture-in-Picture (PIP) mode originating from a
non-single activity task were unintentionally added to the recents.
We initially observed this issue on the 24D1-dev branch when exiting
PIP (b/323315206), which was fixed by ag/26565884 on the main branch.

However, we encountered another scenario when exiting PIP that
originated from a non-single activity task with split pair. It
involves reorder operations (`mHierarchyOps`) to split paired in
recents. The pinned activity task was being added to the recents
while resuming the top PIP activity.

This change takes a different approach compared to previous attempt.
Instead of checking if the task is a pinned activity task from a
non-single activity task for each `RecentTasks.add`, this change only
marks the pinned activity task as auto-removable and then lets
`reparent` in `Task.setWindowingMode` cleanup resources for destory.
This approach prevents empty pinned task from appearing in recents.

Test: atest WmTests:TaskTests WmTests:RootWindowContainerTests
Fix: 348085976
Flag: EXEMPT bugfix
Change-Id: I8ed5938f122988383b11fe0820723de980313540
parent c5002e47
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -2158,6 +2158,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
                // Use Task#setBoundsUnchecked to skip checking windowing mode as the windowing mode
                // will be updated later after this is collected in transition.
                rootTask.setBoundsUnchecked(taskFragment.getBounds());
                // The exit-PIP activity resumes early for seamless transition. In certain
                // scenarios, this introduces unintended addition to recents. To address this,
                // we mark the root task for automatic removal from recents. This ensures that
                // after the pinned activity reparents to its original task, the root task is
                // automatically removed from the recents list.
                rootTask.autoRemoveRecents = true;

                // Move the last recents animation transaction from original task to the new one.
                if (task.mLastRecentsAnimationTransaction != null) {
+6 −0
Original line number Diff line number Diff line
@@ -392,6 +392,8 @@ public class RootWindowContainerTests extends WindowTestsBase {
        assertEquals(newPipTask, mDisplayContent.getDefaultTaskDisplayArea().getRootPinnedTask());
        assertNotEquals(newPipTask, activity1.getTask());
        assertFalse("Created PiP task must not be in recents", newPipTask.inRecents);
        assertThat(newPipTask.autoRemoveRecents).isTrue();
        assertThat(activity1.getTask().autoRemoveRecents).isFalse();
    }

    /**
@@ -427,6 +429,7 @@ public class RootWindowContainerTests extends WindowTestsBase {
        bounds.scale(0.5f);
        task.setBounds(bounds);
        assertFalse(activity.isLetterboxedForFixedOrientationAndAspectRatio());
        assertThat(task.autoRemoveRecents).isFalse();
    }

    /**
@@ -451,6 +454,7 @@ public class RootWindowContainerTests extends WindowTestsBase {
        // Ensure a task has moved over.
        ensureTaskPlacement(task, activity);
        assertTrue(task.inPinnedWindowingMode());
        assertThat(task.autoRemoveRecents).isFalse();
    }

    /**
@@ -480,6 +484,8 @@ public class RootWindowContainerTests extends WindowTestsBase {
        ensureTaskPlacement(fullscreenTask, secondActivity);
        assertTrue(pinnedRootTask.inPinnedWindowingMode());
        assertEquals(WINDOWING_MODE_FULLSCREEN, fullscreenTask.getWindowingMode());
        assertThat(pinnedRootTask.autoRemoveRecents).isTrue();
        assertThat(secondActivity.getTask().autoRemoveRecents).isFalse();
    }

    @Test
+22 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ import static com.android.dx.mockito.inline.extended.ExtendedMockito.spyOn;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.times;
import static com.android.dx.mockito.inline.extended.ExtendedMockito.verify;
import static com.android.server.policy.WindowManagerPolicy.USER_ROTATION_FREE;
import static com.android.server.wm.ActivityRecord.State.RESUMED;
import static com.android.server.wm.Task.FLAG_FORCE_HIDDEN_FOR_TASK_ORG;
import static com.android.server.wm.TaskFragment.EMBEDDED_DIM_AREA_PARENT_TASK;
import static com.android.server.wm.TaskFragment.TASK_FRAGMENT_VISIBILITY_VISIBLE_BEHIND_TRANSLUCENT;
@@ -221,6 +222,27 @@ public class TaskTests extends WindowTestsBase {
        assertEquals(1, task2.getParent().mChildren.indexOf(task2));
    }

    @Test
    public void testReparentPinnedActivityBackToOriginalTask() {
        final ActivityRecord activityMain = new ActivityBuilder(mAtm).setCreateTask(true).build();
        final Task originalTask = activityMain.getTask();
        final ActivityRecord activityPip = new ActivityBuilder(mAtm).setTask(originalTask).build();
        activityPip.setState(RESUMED, "test");
        mAtm.mRootWindowContainer.moveActivityToPinnedRootTask(activityPip,
                null /* launchIntoPipHostActivity */, "test");
        final Task pinnedActivityTask = activityPip.getTask();

        // Simulate pinnedActivityTask unintentionally added to recent during top activity resume.
        mAtm.getRecentTasks().getRawTasks().add(pinnedActivityTask);

        // Reparent the activity back to its original task when exiting PIP mode.
        pinnedActivityTask.setWindowingMode(WINDOWING_MODE_FULLSCREEN);

        assertThat(activityPip.getTask()).isEqualTo(originalTask);
        assertThat(originalTask.autoRemoveRecents).isFalse();
        assertThat(mAtm.getRecentTasks().getRawTasks()).containsExactly(originalTask);
    }

    @Test
    public void testReparent_BetweenDisplays() {
        // Create first task on primary display.