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

Commit 9c005632 authored by Orhan Uysal's avatar Orhan Uysal
Browse files

Restore all visible root tasks on user switch.

Instead of storing just the top focused task, store the visible tasks
for the user. When the user switch happens, restore these tasks from
bottom to top.

Test: atest RootWindowContainerTest
Flag: com.android.window.flags.enable_top_visible_root_task_per_user_tracking
Bug: 381038076

Change-Id: Ic1795d1492499484534edf43d2d07ec3eda8a8c8
parent 52685603
Loading
Loading
Loading
Loading
+67 −6
Original line number Diff line number Diff line
@@ -156,6 +156,7 @@ import com.android.server.policy.PermissionPolicyInternal;
import com.android.server.policy.WindowManagerPolicy;
import com.android.server.utils.Slogf;
import com.android.server.wm.utils.RegionUtils;
import com.android.window.flags.Flags;

import java.io.FileDescriptor;
import java.io.PrintWriter;
@@ -262,6 +263,7 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
    int mCurrentUser;
    /** Root task id of the front root task when user switched, indexed by userId. */
    SparseIntArray mUserRootTaskInFront = new SparseIntArray(2);
    SparseArray<IntArray> mUserVisibleRootTasks = new SparseArray<>();

    /**
     * A list of tokens that cause the top activity to be put to sleep.
@@ -1924,7 +1926,18 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
        // appropriate.
        removeRootTasksInWindowingModes(WINDOWING_MODE_PINNED);

        if (Flags.enableTopVisibleRootTaskPerUserTracking()) {
            final IntArray visibleRootTasks = new IntArray();
            forAllRootTasks(rootTask -> {
                if (mCurrentUser == rootTask.mUserId && rootTask.isVisibleRequested()) {
                    visibleRootTasks.add(rootTask.getRootTaskId());
                }
            }, /* traverseTopToBottom */ false);
            mUserVisibleRootTasks.put(mCurrentUser, visibleRootTasks);
        } else {
            mUserRootTaskInFront.put(mCurrentUser, focusRootTaskId);
        }

        mCurrentUser = userId;

        mTaskSupervisor.mStartingUsers.add(uss);
@@ -1937,22 +1950,60 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
            Slog.i(TAG, "Persisting top task because it belongs to an always-visible user");
            // For a normal user-switch, we will restore the new user's task. But if the pre-switch
            // top task is an always-visible (Communal) one, keep it even after the switch.
            if (Flags.enableTopVisibleRootTaskPerUserTracking()) {
                final IntArray rootTasks = mUserVisibleRootTasks.get(mCurrentUser);
                rootTasks.add(focusRootTaskId);
                mUserVisibleRootTasks.put(mCurrentUser, rootTasks);
            } else {
                mUserRootTaskInFront.put(mCurrentUser, focusRootTaskId);
            }

        }

        final int restoreRootTaskId = mUserRootTaskInFront.get(userId);
        final IntArray rootTaskIdsToRestore = mUserVisibleRootTasks.get(userId);
        boolean homeInFront = false;
        if (Flags.enableTopVisibleRootTaskPerUserTracking()) {
            if (rootTaskIdsToRestore == null) {
                // If there are no root tasks saved, try restore id 0 which should create and launch
                // the home task.
                handleRootTaskLaunchOnUserSwitch(/* restoreRootTaskId */INVALID_TASK_ID);
                homeInFront = true;
            } else {
                for (int i = 0; i < rootTaskIdsToRestore.size(); i++) {
                    handleRootTaskLaunchOnUserSwitch(rootTaskIdsToRestore.get(i));
                }
                // Check if the top task is type home
                if (rootTaskIdsToRestore.size() > 0) {
                    final int topRootTaskId = rootTaskIdsToRestore.get(
                            rootTaskIdsToRestore.size() - 1);
                    homeInFront = isHomeTask(topRootTaskId);
                }
            }
        } else {
            handleRootTaskLaunchOnUserSwitch(restoreRootTaskId);
            // Check if the top task is type home
            homeInFront = isHomeTask(restoreRootTaskId);
        }
        return homeInFront;
    }

    private boolean isHomeTask(int taskId) {
        final Task rootTask = getRootTask(taskId);
        return rootTask != null && rootTask.isActivityTypeHome();
    }

    private void handleRootTaskLaunchOnUserSwitch(int restoreRootTaskId) {
        Task rootTask = getRootTask(restoreRootTaskId);
        if (rootTask == null) {
            rootTask = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
        }
        final boolean homeInFront = rootTask.isActivityTypeHome();
        if (rootTask.isOnHomeDisplay()) {
            rootTask.moveToFront("switchUserOnHomeDisplay");
        } else {
            // Root task was moved to another display while user was swapped out.
            resumeHomeActivity(null, "switchUserOnOtherDisplay", getDefaultTaskDisplayArea());
        }
        return homeInFront;
    }

    /** Returns whether the given user is to be always-visible (e.g. a communal profile). */
@@ -1963,8 +2014,12 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
    }

    void removeUser(int userId) {
        if (Flags.enableTopVisibleRootTaskPerUserTracking()) {
            mUserVisibleRootTasks.delete(userId);
        } else {
            mUserRootTaskInFront.delete(userId);
        }
    }

    /**
     * Update the last used root task id for non-current user (current user's last
@@ -1976,9 +2031,15 @@ class RootWindowContainer extends WindowContainer<DisplayContent>
                rootTask = getDefaultTaskDisplayArea().getOrCreateRootHomeTask();
            }

            if (Flags.enableTopVisibleRootTaskPerUserTracking()) {
                final IntArray rootTasks = mUserVisibleRootTasks.get(userId, new IntArray());
                rootTasks.add(rootTask.getRootTaskId());
                mUserVisibleRootTasks.put(userId, rootTasks);
            } else {
                mUserRootTaskInFront.put(userId, rootTask.getRootTaskId());
            }
        }
    }

    /**
     * Move root task with all its existing content to specified task display area.
+36 −0
Original line number Diff line number Diff line
@@ -41,6 +41,7 @@ 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.google.common.truth.Truth.assertThat;

import static org.junit.Assert.assertEquals;
@@ -63,6 +64,7 @@ import static org.mockito.Mockito.reset;
import static org.mockito.Mockito.spy;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.testng.internal.junit.ArrayAsserts.assertArrayEquals;

import android.app.ActivityOptions;
import android.app.WindowConfiguration;
@@ -77,12 +79,14 @@ import android.graphics.Rect;
import android.os.PowerManager;
import android.os.RemoteException;
import android.os.UserHandle;
import android.platform.test.annotations.EnableFlags;
import android.platform.test.annotations.Presubmit;
import android.util.Pair;

import androidx.test.filters.MediumTest;

import com.android.internal.app.ResolverActivity;
import com.android.window.flags.Flags;

import org.junit.Before;
import org.junit.Test;
@@ -1331,6 +1335,38 @@ public class RootWindowContainerTests extends WindowTestsBase {
        assertEquals(taskDisplayArea.getTopRootTask(), taskDisplayArea.getRootHomeTask());
    }

    @EnableFlags(Flags.FLAG_ENABLE_TOP_VISIBLE_ROOT_TASK_PER_USER_TRACKING)
    @Test
    public void testSwitchUser_withVisibleRootTasks_storesAllVisibleRootTasksForCurrentUser() {
        // Set up root tasks
        final Task rootTask1 = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
                WINDOWING_MODE_FULLSCREEN, ACTIVITY_TYPE_STANDARD, true /* onTop */);
        final Task rootTask2 = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
                WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
        final Task rootTask3 = mRootWindowContainer.getDefaultTaskDisplayArea().createRootTask(
                WINDOWING_MODE_FREEFORM, ACTIVITY_TYPE_STANDARD, true /* onTop */);
        doReturn(rootTask3).when(mRootWindowContainer).getTopDisplayFocusedRootTask();

        // Set up user ids and visibility
        rootTask1.mUserId = mRootWindowContainer.mCurrentUser;
        rootTask2.mUserId = mRootWindowContainer.mCurrentUser;
        rootTask3.mUserId = mRootWindowContainer.mCurrentUser;
        rootTask1.mVisibleRequested = false;
        rootTask2.mVisibleRequested = true;
        rootTask3.mVisibleRequested = true;

        // Switch to a different user
        int currentUser = mRootWindowContainer.mCurrentUser;
        int otherUser = currentUser + 1;
        mRootWindowContainer.switchUser(otherUser, null);

        // Verify that the previous user persists it's previous visible root tasks
        assertArrayEquals(
                new int[]{rootTask2.mTaskId, rootTask3.mTaskId},
                mRootWindowContainer.mUserVisibleRootTasks.get(currentUser).toArray()
        );
    }

    @Test
    public void testLockAllProfileTasks() {
        final int profileUid = UserHandle.PER_USER_RANGE + UserHandle.MIN_SECONDARY_USER_ID;