Loading core/java/android/window/flags/windowing_sdk.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -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" Loading services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +11 −8 Original line number Diff line number Diff line Loading @@ -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); Loading services/core/java/com/android/server/wm/RootWindowContainer.java +64 −31 Original line number Diff line number Diff line Loading @@ -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 */)) { Loading Loading @@ -1706,6 +1737,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Traverse all displays. forAllRootTasks(collectVisibleActivities); } } return topVisibleActivities; } Loading services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +111 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +3 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading Loading
core/java/android/window/flags/windowing_sdk.aconfig +11 −0 Original line number Diff line number Diff line Loading @@ -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" Loading
services/core/java/com/android/server/wm/ActivityTaskManagerInternal.java +11 −8 Original line number Diff line number Diff line Loading @@ -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); Loading
services/core/java/com/android/server/wm/RootWindowContainer.java +64 −31 Original line number Diff line number Diff line Loading @@ -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 */)) { Loading Loading @@ -1706,6 +1737,8 @@ class RootWindowContainer extends WindowContainer<DisplayContent> // Traverse all displays. forAllRootTasks(collectVisibleActivities); } } return topVisibleActivities; } Loading
services/tests/wmtests/src/com/android/server/wm/RootWindowContainerTests.java +111 −0 Original line number Diff line number Diff line Loading @@ -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; Loading Loading @@ -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. Loading
services/tests/wmtests/src/com/android/server/wm/WindowTestsBase.java +3 −0 Original line number Diff line number Diff line Loading @@ -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) { Loading