diff options
| author | 2022-12-05 22:44:42 +0000 | |
|---|---|---|
| committer | 2022-12-05 22:44:42 +0000 | |
| commit | 456e2fe90b39b38a367496f9a94fddfdd9c18bee (patch) | |
| tree | 688060df7c154bcf1d46023937e9e5f2c5d2dd68 | |
| parent | b250c79ea6bb8b168af5c7e1f4a609e4185c67c4 (diff) | |
| parent | fa5835246451e04dfbd5c32bc2a7c9126e58f1b6 (diff) | |
Merge changes Ib2cc8d90,I6f2751b3 into tm-qpr-dev
* changes:
Only bring desktop app to front when necessary
Sort tasks by Z-order instead of lastActiveTime
5 files changed, 185 insertions, 32 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java index abc4024bc290..17ba246910d5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeController.java @@ -64,6 +64,7 @@ import com.android.wm.shell.transition.Transitions; import java.util.ArrayList; import java.util.Comparator; +import java.util.List; import java.util.concurrent.Executor; /** @@ -258,18 +259,36 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll @NonNull private WindowContainerTransaction bringDesktopAppsToFront() { - ArraySet<Integer> activeTasks = mDesktopModeTaskRepository.getActiveTasks(); + final WindowContainerTransaction wct = new WindowContainerTransaction(); + final ArraySet<Integer> activeTasks = mDesktopModeTaskRepository.getActiveTasks(); ProtoLog.d(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront: tasks=%s", activeTasks.size()); - ArrayList<RunningTaskInfo> taskInfos = new ArrayList<>(); + + final List<RunningTaskInfo> taskInfos = new ArrayList<>(); for (Integer taskId : activeTasks) { RunningTaskInfo taskInfo = mShellTaskOrganizer.getRunningTaskInfo(taskId); if (taskInfo != null) { taskInfos.add(taskInfo); } } - // Order by lastActiveTime, descending - taskInfos.sort(Comparator.comparingLong(task -> -task.lastActiveTime)); - WindowContainerTransaction wct = new WindowContainerTransaction(); + + if (taskInfos.isEmpty()) { + return wct; + } + + final boolean allActiveTasksAreVisible = taskInfos.stream() + .allMatch(info -> mDesktopModeTaskRepository.isVisibleTask(info.taskId)); + if (allActiveTasksAreVisible) { + ProtoLog.d(WM_SHELL_DESKTOP_MODE, + "bringDesktopAppsToFront: active tasks are already in front, skipping."); + return wct; + } + ProtoLog.d(WM_SHELL_DESKTOP_MODE, + "bringDesktopAppsToFront: reordering all active tasks to the front"); + final List<Integer> allTasksInZOrder = + mDesktopModeTaskRepository.getFreeformTasksInZOrder(); + // Sort by z-order, bottom to top, so that the top-most task is reordered to the top last + // in the WCT. + taskInfos.sort(Comparator.comparingInt(task -> -allTasksInZOrder.indexOf(task.taskId))); for (RunningTaskInfo task : taskInfos) { wct.reorder(task.token, true); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt index b7749fc4c3d4..600ccc17ecaa 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt @@ -33,6 +33,8 @@ class DesktopModeTaskRepository { */ private val activeTasks = ArraySet<Int>() private val visibleTasks = ArraySet<Int>() + // Tasks currently in freeform mode, ordered from top to bottom (top is at index 0). + private val freeformTasksInZOrder = mutableListOf<Int>() private val activeTasksListeners = ArraySet<ActiveTasksListener>() // Track visible tasks separately because a task may be part of the desktop but not visible. private val visibleTasksListeners = ArrayMap<VisibleTasksListener, Executor>() @@ -101,6 +103,13 @@ class DesktopModeTaskRepository { } /** + * Whether a task is visible. + */ + fun isVisibleTask(taskId: Int): Boolean { + return visibleTasks.contains(taskId) + } + + /** * Get a set of the active tasks */ fun getActiveTasks(): ArraySet<Int> { @@ -108,6 +117,13 @@ class DesktopModeTaskRepository { } /** + * Get a list of freeform tasks, ordered from top-bottom (top at index 0). + */ + fun getFreeformTasksInZOrder(): List<Int> { + return freeformTasksInZOrder + } + + /** * Updates whether a freeform task with this id is visible or not and notifies listeners. */ fun updateVisibleFreeformTasks(taskId: Int, visible: Boolean) { @@ -127,6 +143,23 @@ class DesktopModeTaskRepository { } /** + * Add (or move if it already exists) the task to the top of the ordered list. + */ + fun addOrMoveFreeformTaskToTop(taskId: Int) { + if (freeformTasksInZOrder.contains(taskId)) { + freeformTasksInZOrder.remove(taskId) + } + freeformTasksInZOrder.add(0, taskId) + } + + /** + * Remove the task from the ordered list. + */ + fun removeFreeformTask(taskId: Int) { + freeformTasksInZOrder.remove(taskId) + } + + /** * Defines interface for classes that can listen to changes for active tasks in desktop mode. */ interface ActiveTasksListener { diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java index 44bcdb2d5de5..8a9b74fd72b1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java @@ -38,7 +38,8 @@ import java.util.Optional; * {@link ShellTaskOrganizer.TaskListener} for {@link * ShellTaskOrganizer#TASK_LISTENER_TYPE_FREEFORM}. */ -public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener { +public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, + ShellTaskOrganizer.FocusListener { private static final String TAG = "FreeformTaskListener"; private final ShellTaskOrganizer mShellTaskOrganizer; @@ -67,6 +68,9 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener { private void onInit() { mShellTaskOrganizer.addListenerForType(this, TASK_LISTENER_TYPE_FREEFORM); + if (DesktopModeStatus.IS_SUPPORTED) { + mShellTaskOrganizer.addFocusListener(this); + } } @Override @@ -86,13 +90,16 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener { t.apply(); } - if (DesktopModeStatus.IS_SUPPORTED && taskInfo.isVisible) { + if (DesktopModeStatus.IS_SUPPORTED) { mDesktopModeTaskRepository.ifPresent(repository -> { - if (repository.addActiveTask(taskInfo.taskId)) { - ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, - "Adding active freeform task: #%d", taskInfo.taskId); + repository.addOrMoveFreeformTaskToTop(taskInfo.taskId); + if (taskInfo.isVisible) { + if (repository.addActiveTask(taskInfo.taskId)) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, + "Adding active freeform task: #%d", taskInfo.taskId); + } + repository.updateVisibleFreeformTasks(taskInfo.taskId, true); } - repository.updateVisibleFreeformTasks(taskInfo.taskId, true); }); } } @@ -105,6 +112,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener { if (DesktopModeStatus.IS_SUPPORTED) { mDesktopModeTaskRepository.ifPresent(repository -> { + repository.removeFreeformTask(taskInfo.taskId); if (repository.removeActiveTask(taskInfo.taskId)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, "Removing active freeform task: #%d", taskInfo.taskId); @@ -140,6 +148,18 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener { } @Override + public void onFocusTaskChanged(RunningTaskInfo taskInfo) { + ProtoLog.v(ShellProtoLogGroup.WM_SHELL_TASK_ORG, + "Freeform Task Focus Changed: #%d focused=%b", + taskInfo.taskId, taskInfo.isFocused); + if (DesktopModeStatus.IS_SUPPORTED && taskInfo.isFocused) { + mDesktopModeTaskRepository.ifPresent(repository -> { + repository.addOrMoveFreeformTaskToTop(taskInfo.taskId); + }); + } + } + + @Override public void attachChildSurfaceToTask(int taskId, SurfaceControl.Builder b) { b.setParent(findTaskSurface(taskId)); } diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java index 89bafcb6b2f4..01584a067cc2 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeControllerTest.java @@ -50,6 +50,7 @@ import android.window.TransitionRequestInfo; import android.window.WindowContainerToken; import android.window.WindowContainerTransaction; import android.window.WindowContainerTransaction.Change; +import android.window.WindowContainerTransaction.HierarchyOp; import androidx.test.filters.SmallTest; @@ -222,25 +223,29 @@ public class DesktopModeControllerTest extends ShellTestCase { // Check that there are hierarchy changes for home task and visible task assertThat(wct.getHierarchyOps()).hasSize(2); // First show home task - WindowContainerTransaction.HierarchyOp op1 = wct.getHierarchyOps().get(0); + HierarchyOp op1 = wct.getHierarchyOps().get(0); assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER); assertThat(op1.getContainer()).isEqualTo(homeTask.token.asBinder()); // Then visible task on top of it - WindowContainerTransaction.HierarchyOp op2 = wct.getHierarchyOps().get(1); + HierarchyOp op2 = wct.getHierarchyOps().get(1); assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER); assertThat(op2.getContainer()).isEqualTo(fullscreenTask1.token.asBinder()); } @Test - public void testShowDesktopApps() { - // Set up two active tasks on desktop + public void testShowDesktopApps_allAppsInvisible_bringsToFront() { + // Set up two active tasks on desktop, task2 is on top of task1. RunningTaskInfo freeformTask1 = createFreeformTask(); - freeformTask1.lastActiveTime = 100; - RunningTaskInfo freeformTask2 = createFreeformTask(); - freeformTask2.lastActiveTime = 200; mDesktopModeTaskRepository.addActiveTask(freeformTask1.taskId); + mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(freeformTask1.taskId); + mDesktopModeTaskRepository.updateVisibleFreeformTasks( + freeformTask1.taskId, false /* visible */); + RunningTaskInfo freeformTask2 = createFreeformTask(); mDesktopModeTaskRepository.addActiveTask(freeformTask2.taskId); + mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(freeformTask2.taskId); + mDesktopModeTaskRepository.updateVisibleFreeformTasks( + freeformTask2.taskId, false /* visible */); when(mShellTaskOrganizer.getRunningTaskInfo(freeformTask1.taskId)).thenReturn( freeformTask1); when(mShellTaskOrganizer.getRunningTaskInfo(freeformTask2.taskId)).thenReturn( @@ -248,27 +253,66 @@ public class DesktopModeControllerTest extends ShellTestCase { // Run show desktop apps logic mController.showDesktopApps(); - ArgumentCaptor<WindowContainerTransaction> wctCaptor = ArgumentCaptor.forClass( - WindowContainerTransaction.class); - if (Transitions.ENABLE_SHELL_TRANSITIONS) { - verify(mTransitions).startTransition(eq(TRANSIT_TO_FRONT), wctCaptor.capture(), any()); - } else { - verify(mShellTaskOrganizer).applyTransaction(wctCaptor.capture()); - } - WindowContainerTransaction wct = wctCaptor.getValue(); + final WindowContainerTransaction wct = getBringAppsToFrontTransaction(); // Check wct has reorder calls assertThat(wct.getHierarchyOps()).hasSize(2); - // Task 2 has activity later, must be first - WindowContainerTransaction.HierarchyOp op1 = wct.getHierarchyOps().get(0); + // Task 1 appeared first, must be first reorder to top. + HierarchyOp op1 = wct.getHierarchyOps().get(0); assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER); - assertThat(op1.getContainer()).isEqualTo(freeformTask2.token.asBinder()); + assertThat(op1.getContainer()).isEqualTo(freeformTask1.token.asBinder()); + + // Task 2 appeared last, must be last reorder to top. + HierarchyOp op2 = wct.getHierarchyOps().get(1); + assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER); + assertThat(op2.getContainer()).isEqualTo(freeformTask2.token.asBinder()); + } + + @Test + public void testShowDesktopApps_appsAlreadyVisible_doesNothing() { + final RunningTaskInfo task1 = createFreeformTask(); + mDesktopModeTaskRepository.addActiveTask(task1.taskId); + mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId); + mDesktopModeTaskRepository.updateVisibleFreeformTasks(task1.taskId, true /* visible */); + when(mShellTaskOrganizer.getRunningTaskInfo(task1.taskId)).thenReturn(task1); + final RunningTaskInfo task2 = createFreeformTask(); + mDesktopModeTaskRepository.addActiveTask(task2.taskId); + mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId); + mDesktopModeTaskRepository.updateVisibleFreeformTasks(task2.taskId, true /* visible */); + when(mShellTaskOrganizer.getRunningTaskInfo(task2.taskId)).thenReturn(task2); + + mController.showDesktopApps(); + + final WindowContainerTransaction wct = getBringAppsToFrontTransaction(); + // No reordering needed. + assertThat(wct.getHierarchyOps()).isEmpty(); + } + + @Test + public void testShowDesktopApps_someAppsInvisible_reordersAll() { + final RunningTaskInfo task1 = createFreeformTask(); + mDesktopModeTaskRepository.addActiveTask(task1.taskId); + mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task1.taskId); + mDesktopModeTaskRepository.updateVisibleFreeformTasks(task1.taskId, false /* visible */); + when(mShellTaskOrganizer.getRunningTaskInfo(task1.taskId)).thenReturn(task1); + final RunningTaskInfo task2 = createFreeformTask(); + mDesktopModeTaskRepository.addActiveTask(task2.taskId); + mDesktopModeTaskRepository.addOrMoveFreeformTaskToTop(task2.taskId); + mDesktopModeTaskRepository.updateVisibleFreeformTasks(task2.taskId, true /* visible */); + when(mShellTaskOrganizer.getRunningTaskInfo(task2.taskId)).thenReturn(task2); - // Task 1 should be second - WindowContainerTransaction.HierarchyOp op2 = wct.getHierarchyOps().get(1); + mController.showDesktopApps(); + + final WindowContainerTransaction wct = getBringAppsToFrontTransaction(); + // Both tasks should be reordered to top, even if one was already visible. + assertThat(wct.getHierarchyOps()).hasSize(2); + final HierarchyOp op1 = wct.getHierarchyOps().get(0); + assertThat(op1.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER); + assertThat(op1.getContainer()).isEqualTo(task1.token.asBinder()); + final HierarchyOp op2 = wct.getHierarchyOps().get(1); assertThat(op2.getType()).isEqualTo(HIERARCHY_OP_TYPE_REORDER); - assertThat(op2.getContainer()).isEqualTo(freeformTask1.token.asBinder()); + assertThat(op2.getContainer()).isEqualTo(task2.token.asBinder()); } @Test @@ -355,6 +399,17 @@ public class DesktopModeControllerTest extends ShellTestCase { return arg.getValue(); } + private WindowContainerTransaction getBringAppsToFrontTransaction() { + final ArgumentCaptor<WindowContainerTransaction> arg = ArgumentCaptor.forClass( + WindowContainerTransaction.class); + if (Transitions.ENABLE_SHELL_TRANSITIONS) { + verify(mTransitions).startTransition(eq(TRANSIT_TO_FRONT), arg.capture(), any()); + } else { + verify(mShellTaskOrganizer).applyTransaction(arg.capture()); + } + return arg.getValue(); + } + private void assertThatBoundsCleared(Change change) { assertThat((change.getWindowSetMask() & WINDOW_CONFIG_BOUNDS) != 0).isTrue(); assertThat(change.getConfiguration().windowConfiguration.getBounds().isEmpty()).isTrue(); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt index aaa5c8a35acb..1e43a5983821 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt @@ -140,6 +140,32 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { assertThat(listener.visibleFreeformTaskChangedCalls).isEqualTo(3) } + @Test + fun addOrMoveFreeformTaskToTop_didNotExist_addsToTop() { + repo.addOrMoveFreeformTaskToTop(5) + repo.addOrMoveFreeformTaskToTop(6) + repo.addOrMoveFreeformTaskToTop(7) + + val tasks = repo.getFreeformTasksInZOrder() + assertThat(tasks.size).isEqualTo(3) + assertThat(tasks[0]).isEqualTo(7) + assertThat(tasks[1]).isEqualTo(6) + assertThat(tasks[2]).isEqualTo(5) + } + + @Test + fun addOrMoveFreeformTaskToTop_alreadyExists_movesToTop() { + repo.addOrMoveFreeformTaskToTop(5) + repo.addOrMoveFreeformTaskToTop(6) + repo.addOrMoveFreeformTaskToTop(7) + + repo.addOrMoveFreeformTaskToTop(6) + + val tasks = repo.getFreeformTasksInZOrder() + assertThat(tasks.size).isEqualTo(3) + assertThat(tasks.first()).isEqualTo(6) + } + class TestListener : DesktopModeTaskRepository.ActiveTasksListener { var activeTaskChangedCalls = 0 override fun onActiveTasksChanged() { |