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

Commit 0b6f5f70 authored by Eric Lin's avatar Eric Lin
Browse files

Add ability to exclude individual tasks from Recents.

Adds an explicit exclusion control for tasks in the Recents list via a
new `mForceExcludedFromRecents` field in `Task.java`, with accompanying
getter/setter methods. This allows for precise control over task
visibility in Recents, independent of other visibility criteria.

This can replace the previous hidden bubble task approach that used
`isAlwaysOnTop` and `MULTI_WINDOW_MODE` to hide tasks with a more direct
exclusion mechanism.

Bug: 404726350
Flag: com.android.window.flags.exclude_task_from_recents
Test: atest WmTests:RecentTasksTest
Test: atest WmTests:TaskTests
Test: adb shell dumpsys activity recents
Change-Id: I0f8576ba2e9f0095957c440edcf8d5dd639ce657
parent d9a023d1
Loading
Loading
Loading
Loading
+9 −1
Original line number Original line Diff line number Diff line
@@ -49,6 +49,7 @@ import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_ATM;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskManagerDebugConfig.TAG_WITH_CLASS_NAME;
import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;
import static com.android.server.wm.ActivityTaskSupervisor.REMOVE_FROM_RECENTS;


import android.annotation.NonNull;
import android.annotation.Nullable;
import android.annotation.Nullable;
import android.app.ActivityManager;
import android.app.ActivityManager;
import android.app.ActivityTaskManager;
import android.app.ActivityTaskManager;
@@ -83,6 +84,7 @@ import com.android.internal.annotations.VisibleForTesting;
import com.android.internal.protolog.ProtoLog;
import com.android.internal.protolog.ProtoLog;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.internal.util.function.pooled.PooledLambda;
import com.android.server.am.ActivityManagerService;
import com.android.server.am.ActivityManagerService;
import com.android.window.flags.Flags;


import com.google.android.collect.Sets;
import com.google.android.collect.Sets;


@@ -1452,9 +1454,10 @@ class RecentTasks {
     * @return whether the given active task should be presented to the user through SystemUI.
     * @return whether the given active task should be presented to the user through SystemUI.
     */
     */
    @VisibleForTesting
    @VisibleForTesting
    boolean isVisibleRecentTask(Task task) {
    boolean isVisibleRecentTask(@NonNull Task task) {
        if (DEBUG_RECENTS_TRIM_TASKS) {
        if (DEBUG_RECENTS_TRIM_TASKS) {
            Slog.d(TAG, "isVisibleRecentTask: task=" + task
            Slog.d(TAG, "isVisibleRecentTask: task=" + task
                    + " isForceExcludedFromRecents=" + task.isForceExcludedFromRecents()
                    + " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks
                    + " minVis=" + mMinNumVisibleTasks + " maxVis=" + mMaxNumVisibleTasks
                    + " sessionDuration=" + mActiveTasksSessionDurationMs
                    + " sessionDuration=" + mActiveTasksSessionDurationMs
                    + " inactiveDuration=" + task.getInactiveDuration()
                    + " inactiveDuration=" + task.getInactiveDuration()
@@ -1464,6 +1467,11 @@ class RecentTasks {
                    + " intentFlags=" + task.getBaseIntent().getFlags());
                    + " intentFlags=" + task.getBaseIntent().getFlags());
        }
        }


        // Ignore the task if it is force excluded from recents.
        if (Flags.excludeTaskFromRecents() && task.isForceExcludedFromRecents()) {
            return false;
        }

        switch (task.getActivityType()) {
        switch (task.getActivityType()) {
            case ACTIVITY_TYPE_HOME:
            case ACTIVITY_TYPE_HOME:
            case ACTIVITY_TYPE_RECENTS:
            case ACTIVITY_TYPE_RECENTS:
+40 −2
Original line number Original line Diff line number Diff line
@@ -625,6 +625,9 @@ class Task extends TaskFragment {


    boolean mAlignActivityLocaleWithTask = false;
    boolean mAlignActivityLocaleWithTask = false;


    /** @see #isForceExcludedFromRecents() */
    private boolean mForceExcludedFromRecents;

    private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
    private Task(ActivityTaskManagerService atmService, int _taskId, Intent _intent,
            Intent _affinityIntent, String _affinity, String _rootAffinity,
            Intent _affinityIntent, String _affinity, String _rootAffinity,
            ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
            ComponentName _realActivity, ComponentName _origActivity, boolean _rootWasReset,
@@ -3842,7 +3845,8 @@ class Task extends TaskFragment {
        pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
        pw.print(prefix); pw.print("lastActiveTime="); pw.print(lastActiveTime);
        pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
        pw.println(" (inactive for " + (getInactiveDuration() / 1000) + "s)");
        pw.print(prefix); pw.print("isTrimmable=" + mIsTrimmableFromRecents);
        pw.print(prefix); pw.print("isTrimmable=" + mIsTrimmableFromRecents);
        pw.print(" isForceHidden="); pw.println(isForceHidden());
        pw.print(" isForceHidden="); pw.print(isForceHidden());
        pw.print(" isForceExcludedFromRecents="); pw.println(isForceExcludedFromRecents());
        if (mLaunchAdjacentDisabled) {
        if (mLaunchAdjacentDisabled) {
            pw.println(prefix + "mLaunchAdjacentDisabled=true");
            pw.println(prefix + "mLaunchAdjacentDisabled=true");
        }
        }
@@ -4555,11 +4559,45 @@ class Task extends TaskFragment {


    /**
    /**
     * @return whether this task is always on top without taking visibility into account.
     * @return whether this task is always on top without taking visibility into account.
     * @deprecated b/388630258 replace hidden bubble tasks with reordering.
     * {@link RecentTasks#isVisibleRecentTask} now checks {@link #isForceExcludedFromRecents}.
     */
     */
    public boolean isAlwaysOnTopWhenVisible() {
    @Deprecated
    boolean isAlwaysOnTopWhenVisible() {
        return super.isAlwaysOnTop();
        return super.isAlwaysOnTop();
    }
    }


    /**
     * Returns whether this task is forcibly excluded from the Recents list.
     *
     * <p>This flag is used by {@link RecentTasks#isVisibleRecentTask} to determine
     * if the task should be presented to the user through SystemUI. If this method
     * returns {@code true}, the task will not be shown in Recents, regardless of other
     * visibility criteria.
     *
     * @return {@code true} if the task is excluded, {@code false} otherwise.
     */
    boolean isForceExcludedFromRecents() {
        return mForceExcludedFromRecents;
    }

    /**
     * Sets whether this task should be forcibly excluded from the Recents list.
     *
     * <p>This method is intended to be used in conjunction with
     * {@link android.window.WindowContainerTransaction#setTaskForceExcludedFromRecents} to modify the
     * task's exclusion state.
     *
     * @param excluded {@code true} to exclude the task, {@code false} otherwise.
     */
    void setForceExcludedFromRecents(boolean excluded) {
        if (!Flags.excludeTaskFromRecents()) {
            Slog.w(TAG, "Flag " + Flags.FLAG_EXCLUDE_TASK_FROM_RECENTS + " is not enabled");
            return;
        }
        mForceExcludedFromRecents = excluded;
    }

    boolean isForceHiddenForPinnedTask() {
    boolean isForceHiddenForPinnedTask() {
        return (mForceHiddenFlags & FLAG_FORCE_HIDDEN_FOR_PINNED_TASK) != 0;
        return (mForceHiddenFlags & FLAG_FORCE_HIDDEN_FOR_PINNED_TASK) != 0;
    }
    }
+15 −0
Original line number Original line Diff line number Diff line
@@ -81,6 +81,7 @@ import android.window.TaskSnapshot;
import androidx.test.filters.MediumTest;
import androidx.test.filters.MediumTest;


import com.android.server.wm.RecentTasks.Callbacks;
import com.android.server.wm.RecentTasks.Callbacks;
import com.android.window.flags.Flags;


import org.junit.Before;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Rule;
@@ -930,6 +931,20 @@ public class RecentTasksTest extends WindowTestsBase {
        assertFalse(mRecentTasks.isVisibleRecentTask(task));
        assertFalse(mRecentTasks.isVisibleRecentTask(task));
    }
    }


    @Test
    public void testVisibleTask_forceExcludedFromRecents() {
        final Task forceExcludedFromRecentsTask = mTasks.getFirst();
        forceExcludedFromRecentsTask.setForceExcludedFromRecents(true);

        final boolean visible = mRecentTasks.isVisibleRecentTask(forceExcludedFromRecentsTask);

        if (Flags.excludeTaskFromRecents()) {
            assertFalse(visible);
        } else {
            assertTrue(visible);
        }
    }

    @Test
    @Test
    public void testFreezeTaskListOrder_reorderExistingTask() {
    public void testFreezeTaskListOrder_reorderExistingTask() {
        // Add some tasks
        // Add some tasks
+32 −0
Original line number Original line Diff line number Diff line
@@ -86,6 +86,7 @@ import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Rect;
import android.os.IBinder;
import android.os.IBinder;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.platform.test.annotations.Presubmit;
import android.util.DisplayMetrics;
import android.util.DisplayMetrics;
import android.util.Xml;
import android.util.Xml;
@@ -99,6 +100,7 @@ import androidx.test.filters.MediumTest;


import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlPullParser;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.modules.utils.TypedXmlSerializer;
import com.android.window.flags.Flags;


import org.junit.Assert;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Before;
@@ -2161,6 +2163,36 @@ public class TaskTests extends WindowTestsBase {


    }
    }


    @Test
    public void testIsForceExcludedFromRecents_defaultFalse() {
        final Task task = createTask(mDisplayContent);
        assertFalse(task.isForceExcludedFromRecents());
    }

    @Test
    public void testSetForceExcludedFromRecents() {
        final Task task = createTask(mDisplayContent);

        task.setForceExcludedFromRecents(true);

        if (Flags.excludeTaskFromRecents()) {
            assertTrue(task.isForceExcludedFromRecents());
        } else {
            assertFalse(task.isForceExcludedFromRecents());
        }
    }

    @Test
    @EnableFlags(Flags.FLAG_EXCLUDE_TASK_FROM_RECENTS)
    public void testSetForceExcludedFromRecents_resetsTaskForceExcludedFromRecents() {
        final Task task = createTask(mDisplayContent);
        task.setForceExcludedFromRecents(true);

        task.setForceExcludedFromRecents(false);

        assertFalse(task.isForceExcludedFromRecents());
    }

    private Task getTestTask() {
    private Task getTestTask() {
        return new TaskBuilder(mSupervisor).setCreateActivity(true).build();
        return new TaskBuilder(mSupervisor).setCreateActivity(true).build();
    }
    }