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

Commit fa5f4c8a authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Remove invisible replaced recent task when going to home"

parents db62abfc 4e361e9f
Loading
Loading
Loading
Loading
+42 −0
Original line number Diff line number Diff line
@@ -173,6 +173,9 @@ class RecentTasks {
    private final ArrayList<Task> mTasks = new ArrayList<>();
    private final ArrayList<Callbacks> mCallbacks = new ArrayList<>();

    /** The non-empty tasks that are removed from recent tasks (see {@link #removeForAddTask}). */
    private final ArrayList<Task> mHiddenTasks = new ArrayList<>();

    // These values are generally loaded from resources, but can be set dynamically in the tests
    private boolean mHasVisibleRecentTasks;
    private int mGlobalMaxNumTasks;
@@ -1024,6 +1027,12 @@ class RecentTasks {
    void add(Task task) {
        if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "add: task=" + task);

        // Clean up the hidden tasks when going to home because the user may not be unable to return
        // to the task from recents.
        if (!mHiddenTasks.isEmpty() && task.isActivityTypeHome()) {
            removeUnreachableHiddenTasks(task.getWindowingMode());
        }

        final boolean isAffiliated = task.mAffiliatedTaskId != task.mTaskId
                || task.mNextAffiliateTaskId != INVALID_TASK_ID
                || task.mPrevAffiliateTaskId != INVALID_TASK_ID;
@@ -1390,6 +1399,28 @@ class RecentTasks {
        return display.getIndexOf(stack) < display.getIndexOf(display.getRootHomeTask());
    }

    /** Remove the tasks that user may not be able to return. */
    private void removeUnreachableHiddenTasks(int windowingMode) {
        for (int i = mHiddenTasks.size() - 1; i >= 0; i--) {
            final Task hiddenTask = mHiddenTasks.get(i);
            if (!hiddenTask.hasChild()) {
                // The task was removed by other path.
                mHiddenTasks.remove(i);
                continue;
            }
            if (hiddenTask.getWindowingMode() != windowingMode
                    || hiddenTask.getTopVisibleActivity() != null) {
                // The task may be reachable from the back stack of other windowing mode or it is
                // currently in use. Keep the task in the hidden list to avoid losing track, e.g.
                // after dismissing primary split screen.
                continue;
            }
            mHiddenTasks.remove(i);
            mSupervisor.removeTask(hiddenTask, false /* killProcess */,
                    !REMOVE_FROM_RECENTS, "remove-hidden-task");
        }
    }

    /**
     * If needed, remove oldest existing entries in recents that are for the same kind
     * of task as the given one.
@@ -1406,6 +1437,14 @@ class RecentTasks {
        // callbacks here.
        final Task removedTask = mTasks.remove(removeIndex);
        if (removedTask != task) {
            // The added task is in recents so it is not hidden.
            mHiddenTasks.remove(task);
            if (removedTask.hasChild()) {
                // A non-empty task is replaced by a new task. Because the removed task is no longer
                // managed by the recent tasks list, add it to the hidden list to prevent the task
                // from becoming dangling.
                mHiddenTasks.add(removedTask);
            }
            notifyTaskRemoved(removedTask, false /* wasTrimmed */, false /* killProcess */);
            if (DEBUG_RECENTS_TRIM_TASKS) Slog.d(TAG, "Trimming task=" + removedTask
                    + " for addition of task=" + task);
@@ -1662,6 +1701,9 @@ class RecentTasks {
        pw.println("mFreezeTaskListReordering=" + mFreezeTaskListReordering);
        pw.println("mFreezeTaskListReorderingPendingTimeout="
                + mService.mH.hasCallbacks(mResetFreezeTaskListOnTimeoutRunnable));
        if (!mHiddenTasks.isEmpty()) {
            pw.println("mHiddenTasks=" + mHiddenTasks);
        }
        if (mTasks.isEmpty()) {
            return;
        }
+33 −0
Original line number Diff line number Diff line
@@ -39,6 +39,8 @@ import static com.google.common.truth.Truth.assertWithMessage;

import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import static org.mockito.ArgumentMatchers.anyBoolean;
@@ -83,6 +85,7 @@ import java.util.HashSet;
import java.util.List;
import java.util.Random;
import java.util.Set;
import java.util.function.Function;

/**
 * Build/Install/Run:
@@ -418,6 +421,36 @@ public class RecentTasksTest extends ActivityTestsBase {
        assertThat(mCallbacksRecorder.mRemoved).isEmpty();
    }

    @Test
    public void testAddTasksHomeClearUntrackedTasks_expectFinish() {
        // There may be multiple tasks with the same base intent by flags (FLAG_ACTIVITY_NEW_TASK |
        // FLAG_ACTIVITY_MULTIPLE_TASK). If the previous task is still active, it should be removed
        // because user may not be able to return to the task.
        final String className = ".PermissionsReview";
        final Function<Boolean, Task> taskBuilder = visible -> {
            final Task task = createTaskBuilder(className).build();
            // Make the task non-empty.
            final ActivityRecord r = new ActivityBuilder(mService).setTask(task).build();
            r.setVisibility(visible);
            return task;
        };

        final Task task1 = taskBuilder.apply(false /* visible */);
        mRecentTasks.add(task1);
        final Task task2 = taskBuilder.apply(true /* visible */);
        mRecentTasks.add(task2);
        // Only the last task is kept in recents and the previous 2 tasks will becomes untracked
        // tasks because their intents are identical.
        mRecentTasks.add(createTaskBuilder(className).build());
        // Go home to trigger the removal of untracked tasks.
        mRecentTasks.add(createTaskBuilder(".Home").setStack(mDisplay.getRootHomeTask()).build());

        // All activities in the invisible task should be finishing or removed.
        assertNull(task1.getTopNonFinishingActivity());
        // The visible task should not be affected.
        assertNotNull(task2.getTopNonFinishingActivity());
    }

    @Test
    public void testUsersTasks() {
        mRecentTasks.setOnlyTestVisibleRange();