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

Commit 48a461f3 authored by Chris Li's avatar Chris Li
Browse files

Return all visible activities for VIS

Before, we only return the top activities of each visible root Task
(with handle split screen specially), which doesn't cover:
1. Desktop Windowing, which can have multiple leaf Tasks in one root.
2. Activity Embedding, which can have multiple leaf TaskFragments in one
   leaf Task.
3. Paused activities behind another translucent activity.

Now, we return all visible activities.

Bug: 434114340
Flag: com.android.window.flags.return_all_visible_activities_for_vis
Test: atest WmTests:RootWindowContainerTests
Change-Id: Ib07febfc65ed800c7ecbcd7086a58dffdd771798
parent 8441f07f
Loading
Loading
Loading
Loading
+11 −0
Original line number Diff line number Diff line
@@ -178,6 +178,17 @@ flag {
    is_fixed_read_only: true
}

flag {
    namespace: "windowing_sdk"
    name: "return_all_visible_activities_for_vis"
    description: "Return all visible activities in multi-tasking feature to VIS"
    bug: "434114340"
    is_fixed_read_only: true
    metadata {
        purpose: PURPOSE_BUGFIX
    }
}

flag {
    namespace: "windowing_sdk"
    name: "dispose_task_fragment_synchronously"
+11 −8
Original line number Diff line number Diff line
@@ -143,20 +143,23 @@ public abstract class ActivityTaskManagerInternal implements ActiveUids.Observer
            IVoiceInteractor mInteractor);

    /**
     * Returns the top activity from each of the currently visible root tasks, and the related task
     * id. The first entry will be the focused activity.
     * @return a list of {@link ActivityAssistInfo} of the visible activities in the all displays.
     * Visible activities in the focused root Task are at the front of the list.
     *
     * <p>NOTE: If the top activity is in the split screen, the other activities in the same split
     * screen will also be returned.
     * <p>NOTE: This includes all visible activities, even if one is paused, which means it is
     * behind a translucent container.
     */
    public abstract List<ActivityAssistInfo> getTopVisibleActivities();

    /**
     * Returns the top activity from each of the currently visible root tasks of the given
     * display, and the related task id. The first entry will be the focused activity.
     * @return a list of {@link ActivityAssistInfo} of the visible activities in the given display.
     * Visible activities in the focused root Task are at the front of the list.
     *
     * <p>NOTE: If the top activity is in the split screen, the other activities in the same split
     * screen will also be returned.
     * <p>NOTE: This includes all visible activities, even if one is paused, which means it is
     * behind a translucent container.
     *
     * @param displayId if the displayId is not found, this will return visible activities in all
     *                  displays.
     */
    public abstract List<ActivityAssistInfo> getTopVisibleActivities(int displayId);

+64 −31
Original line number Diff line number Diff line
@@ -1661,20 +1661,51 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
    }

    /**
     * @return a list of pairs, containing activities and their task id which are the top ones in
     * each visible root task. The first entry will be the focused activity.
     * @return a list of {@link ActivityAssistInfo} of the visible activities in the given display.
     * Visible activities in the focused root Task are at the front of the list.
     *
     * <p>NOTE: If the top activity is in the split screen, the other activities in the same split
     * screen will also be returned.
     * <p>NOTE: This includes all visible activities, even if one is paused, which means it is
     * behind a translucent container.
     */
    List<ActivityAssistInfo> getTopVisibleActivities(int displayId) {
        final ArrayList<ActivityAssistInfo> topVisibleActivities = new ArrayList<>();
        final ArrayList<ActivityAssistInfo> activityAssistInfos = new ArrayList<>();
        final DisplayContent dc =
                displayId != INVALID_DISPLAY ? getDisplayContent(displayId) : null;
        final Task topFocusedRootTask =
                dc != null ? dc.getFocusedRootTask() : getTopDisplayFocusedRootTask();

        if (Flags.returnAllVisibleActivitiesForVis()) {
            final ArrayList<ActivityAssistInfo> visibleActivitiesInFocusedRoot = new ArrayList<>();
            final Consumer<ActivityRecord> collectFromFocusedRoot = activity -> {
                if (activity.isVisibleRequested()) {
                    visibleActivitiesInFocusedRoot.add(new ActivityAssistInfo(activity));
                }
            };
            final Consumer<ActivityRecord> collectFromNonFocusedRoot = activity -> {
                if (activity.isVisibleRequested()) {
                    topVisibleActivities.add(new ActivityAssistInfo(activity));
                }
            };
            final Consumer<Task> collectFromDisplay = leafTaskFragment -> {
                if (!leafTaskFragment.isVisibleRequested()) {
                    return;
                }
                if (leafTaskFragment.getRootTask() == topFocusedRootTask) {
                    leafTaskFragment.forAllActivities(collectFromFocusedRoot);
                } else {
                    leafTaskFragment.forAllActivities(collectFromNonFocusedRoot);
                }
            };

            if (dc != null) {
                dc.forAllRootTasks(collectFromDisplay);
            } else {
                // Traverse all displays.
                forAllRootTasks(collectFromDisplay);
            }
            topVisibleActivities.addAll(0, visibleActivitiesInFocusedRoot);
        } else {
            final ArrayList<ActivityAssistInfo> activityAssistInfos = new ArrayList<>();
            final Consumer<Task> collectVisibleActivities = rootTask -> {
                // Get top activity from a visible root task and add it to the list.
                if (rootTask.shouldBeVisible(null /* starting */)) {
@@ -1706,6 +1737,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
                // Traverse all displays.
                forAllRootTasks(collectVisibleActivities);
            }
        }

        return topVisibleActivities;
    }

+111 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ import static com.android.server.wm.ActivityRecord.State.STOPPING;
import static com.android.server.wm.ActivityTaskSupervisor.ON_TOP;
import static com.android.server.wm.RootWindowContainer.MATCH_ATTACHED_TASK_OR_RECENT_TASKS_AND_RESTORE;
import static com.android.server.wm.WindowContainer.POSITION_BOTTOM;
import static com.android.window.flags.Flags.FLAG_RETURN_ALL_VISIBLE_ACTIVITIES_FOR_VIS;

import static com.google.common.truth.Truth.assertThat;

@@ -1395,6 +1396,116 @@ public class RootWindowContainerTests extends WindowTestsBase {
                anyBoolean());
    }

    @Test
    public void testGetTopVisibleActivities_fullscreen() {
        // Make every Task opaque.
        final ActivityTaskSupervisor.OpaqueContainerHelper opaqueContainerHelper =
                mAtm.mTaskSupervisor.mOpaqueContainerHelper;
        spyOn(opaqueContainerHelper);
        doReturn(true).when(opaqueContainerHelper).isOpaque(
                any(), any(), anyBoolean(), anyBoolean());

        final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
        final ActivityRecord bottomR = createActivityRecord(display);
        final ActivityRecord topR = createActivityRecord(display);
        // The Task behind another should be invisible.
        bottomR.setVisibleRequested(false);

        final List<ActivityAssistInfo> result = mRootWindowContainer.getTopVisibleActivities(
                display.mDisplayId);

        assertEquals(1, result.size());
        assertEquals(topR.token, result.get(0).getActivityToken());
    }

    @Test
    public void testGetTopVisibleActivities_splitScreen() {
        // Make every Task opaque.
        final ActivityTaskSupervisor.OpaqueContainerHelper opaqueContainerHelper =
                mAtm.mTaskSupervisor.mOpaqueContainerHelper;
        spyOn(opaqueContainerHelper);
        doReturn(true).when(opaqueContainerHelper).isOpaque(
                any(), any(), anyBoolean(), anyBoolean());

        final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
        final ActivityRecord splitActivity0 = createActivityRecordWithParentTask(display,
                WINDOWING_MODE_MULTI_WINDOW, ACTIVITY_TYPE_STANDARD);
        final ActivityRecord splitActivity1 = createActivityRecordWithParentTask(
                splitActivity0.getRootTask());
        final Task splitTask0 = splitActivity0.getTask();
        final Task splitTask1 = splitActivity1.getTask();
        splitTask0.setAdjacentTaskFragments(new TaskFragment.AdjacentSet(splitTask0, splitTask1));
        splitTask0.setBounds(0, 0, 500, 500);
        splitTask1.setBounds(500, 0, 1000, 500);

        final List<ActivityAssistInfo> result = mRootWindowContainer.getTopVisibleActivities(
                display.mDisplayId);

        assertEquals(2, result.size());
        assertEquals(splitActivity1.token, result.get(0).getActivityToken());
        assertEquals(splitActivity0.token, result.get(1).getActivityToken());
    }

    @EnableFlags(FLAG_RETURN_ALL_VISIBLE_ACTIVITIES_FOR_VIS)
    @Test
    public void testGetTopVisibleActivities_rootTaskWithMultiLeafTasks() {
        final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
        final Task deskRoot = createTask(display, WINDOWING_MODE_MULTI_WINDOW,
                ACTIVITY_TYPE_STANDARD);
        final ActivityRecord activity0 = createActivityRecordWithParentTask(deskRoot);
        final ActivityRecord activity1 = createActivityRecordWithParentTask(deskRoot);
        final ActivityRecord activity2 = createActivityRecordWithParentTask(deskRoot);

        final List<ActivityAssistInfo> result = mRootWindowContainer.getTopVisibleActivities(
                display.mDisplayId);

        assertEquals(3, result.size());
        assertEquals(activity2.token, result.get(0).getActivityToken());
        assertEquals(activity1.token, result.get(1).getActivityToken());
        assertEquals(activity0.token, result.get(2).getActivityToken());
    }

    @EnableFlags(FLAG_RETURN_ALL_VISIBLE_ACTIVITIES_FOR_VIS)
    @Test
    public void testGetTopVisibleActivities_activityEmbedding() {
        final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
        final Task task = createTask(display, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
        final TaskFragment tf0 = createTaskFragmentWithActivity(task);
        final TaskFragment tf1 = createTaskFragmentWithActivity(task);
        tf0.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        tf1.setWindowingMode(WINDOWING_MODE_MULTI_WINDOW);
        tf0.setBounds(0, 0, 500, 500);
        tf1.setBounds(500, 0, 1000, 500);
        tf0.setAdjacentTaskFragments(new TaskFragment.AdjacentSet(tf0, tf1));
        final ActivityRecord activity0 = tf0.getTopMostActivity();
        final ActivityRecord activity1 = tf1.getTopMostActivity();

        final List<ActivityAssistInfo> result = mRootWindowContainer.getTopVisibleActivities(
                display.mDisplayId);

        assertEquals(2, result.size());
        assertEquals(activity1.token, result.get(0).getActivityToken());
        assertEquals(activity0.token, result.get(1).getActivityToken());
    }

    @EnableFlags(FLAG_RETURN_ALL_VISIBLE_ACTIVITIES_FOR_VIS)
    @Test
    public void testGetTopVisibleActivities_behindTranslucent() {
        final DisplayContent display = mRootWindowContainer.getDefaultDisplay();
        // Create two visible requested activities in one Task to simulate one behind another
        // translucent.
        final Task task = createTask(display, WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD);
        final ActivityRecord activity0 = createActivityRecord(task);
        final ActivityRecord activity1 = createActivityRecord(task);

        final List<ActivityAssistInfo> result = mRootWindowContainer.getTopVisibleActivities(
                display.mDisplayId);

        assertEquals(2, result.size());
        assertEquals(activity1.token, result.get(0).getActivityToken());
        assertEquals(activity0.token, result.get(1).getActivityToken());
    }

    /**
     * Mock {@link RootWindowContainer#resolveHomeActivity} for returning consistent activity
     * info for test cases.
+3 −0
Original line number Diff line number Diff line
@@ -1491,6 +1491,9 @@ public class WindowTestsBase extends SystemServiceTestsBase {
            while (mCreateActivityCount > 0) {
                final ActivityRecord activity = new ActivityBuilder(mAtm).build();
                taskFragment.addChild(activity);
                if (mParentTask != null) {
                    postCreateActivitySetup(activity, mParentTask.getDisplayContent());
                }
                mCreateActivityCount--;
            }
            if (mOrganizer != null) {