Loading services/core/java/com/android/server/wm/RootWindowContainer.java +67 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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); Loading @@ -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). */ Loading @@ -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 Loading @@ -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. Loading services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +36 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -1332,6 +1336,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; Loading Loading
services/core/java/com/android/server/wm/RootWindowContainer.java +67 −6 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading Loading @@ -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); Loading @@ -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). */ Loading @@ -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 Loading @@ -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. Loading
services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +36 −0 Original line number Diff line number Diff line Loading @@ -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; Loading @@ -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; Loading @@ -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; Loading Loading @@ -1332,6 +1336,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; Loading