diff options
| author | 2024-12-03 15:38:39 +0000 | |
|---|---|---|
| committer | 2024-12-10 11:26:39 +0000 | |
| commit | 9c005632ab566dfdf03439f27789037a8085ae8d (patch) | |
| tree | e26faefb3754e4470d00af0641b4748e4749fc56 | |
| parent | 5268560308d05c729ccede36112003346756ee73 (diff) | |
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
| -rw-r--r-- | services/core/java/com/android/server/wm/RootWindowContainer.java | 73 | ||||
| -rw-r--r-- | services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java | 36 |
2 files changed, 103 insertions, 6 deletions
diff --git a/services/core/java/com/android/server/wm/RootWindowContainer.java b/services/core/java/com/android/server/wm/RootWindowContainer.java index 46312aff1fb6..c284222a7c1d 100644 --- a/services/core/java/com/android/server/wm/RootWindowContainer.java +++ b/services/core/java/com/android/server/wm/RootWindowContainer.java @@ -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); - mUserRootTaskInFront.put(mCurrentUser, focusRootTaskId); + 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. - mUserRootTaskInFront.put(mCurrentUser, focusRootTaskId); + 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,7 +2014,11 @@ class RootWindowContainer extends WindowContainer<DisplayContent> } void removeUser(int userId) { - mUserRootTaskInFront.delete(userId); + if (Flags.enableTopVisibleRootTaskPerUserTracking()) { + mUserVisibleRootTasks.delete(userId); + } else { + mUserRootTaskInFront.delete(userId); + } } /** @@ -1976,7 +2031,13 @@ class RootWindowContainer extends WindowContainer<DisplayContent> rootTask = getDefaultTaskDisplayArea().getOrCreateRootHomeTask(); } - mUserRootTaskInFront.put(userId, rootTask.getRootTaskId()); + 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()); + } } } diff --git a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java index 7e8bd38fb6a9..d53825ffefa7 100644 --- a/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +++ b/services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java @@ -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; |