Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt +52 −3 Original line number Diff line number Diff line Loading @@ -46,6 +46,9 @@ class DesktopModeTaskRepository { val activeTasks: ArraySet<Int> = ArraySet(), val visibleTasks: ArraySet<Int> = ArraySet(), val minimizedTasks: ArraySet<Int> = ArraySet(), // Tasks that are closing, but are still visible // TODO(b/332682201): Remove when the repository state is updated via TransitionObserver val closingTasks: ArraySet<Int> = ArraySet(), // Tasks currently in freeform mode, ordered from top to bottom (top is at index 0). val freeformTasksInZOrder: ArrayList<Int> = ArrayList(), ) Loading Loading @@ -169,6 +172,42 @@ class DesktopModeTaskRepository { return result } /** * Mark a task with given [taskId] as closing on given [displayId] * * @return `true` if the task was not closing on given [displayId] */ fun addClosingTask(displayId: Int, taskId: Int): Boolean { val added = displayData.getOrCreate(displayId).closingTasks.add(taskId) if (added) { KtProtoLog.d( WM_SHELL_DESKTOP_MODE, "DesktopTaskRepo: added closing task=%d displayId=%d", taskId, displayId ) } return added } /** * Remove task with given [taskId] from closing tasks. * * @return `true` if the task was closing */ fun removeClosingTask(taskId: Int): Boolean { var removed = false displayData.forEach { _, data -> if (data.closingTasks.remove(taskId)) { removed = true } } if (removed) { KtProtoLog.d(WM_SHELL_DESKTOP_MODE, "DesktopTaskRepo: remove closing task=%d", taskId) } return removed } /** Check if a task with the given [taskId] was marked as an active task */ fun isActiveTask(taskId: Int): Boolean { return displayData.valueIterator().asSequence().any { data -> Loading @@ -176,6 +215,10 @@ class DesktopModeTaskRepository { } } /** Check if a task with the given [taskId] was marked as a closing task */ fun isClosingTask(taskId: Int): Boolean = displayData.valueIterator().asSequence().any { data -> taskId in data.closingTasks } /** Whether a task is visible. */ fun isVisibleTask(taskId: Int): Boolean { return displayData.valueIterator().asSequence().any { data -> Loading @@ -190,10 +233,16 @@ class DesktopModeTaskRepository { } } /** Check if a task with the given [taskId] is the only active task on its display */ fun isOnlyActiveTask(taskId: Int): Boolean { /** * Check if a task with the given [taskId] is the only active, non-closing, not-minimized task * on its display */ fun isOnlyActiveNonClosingTask(taskId: Int): Boolean { return displayData.valueIterator().asSequence().any { data -> data.activeTasks.singleOrNull() == taskId data.activeTasks .subtract(data.closingTasks) .subtract(data.minimizedTasks) .singleOrNull() == taskId } } Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +27 −13 Original line number Diff line number Diff line Loading @@ -442,12 +442,21 @@ class DesktopTasksController( * active task. * * @param wct transaction to modify if the last active task is closed * @param displayId display id of the window that's being closed * @param taskId task id of the window that's being closed */ fun onDesktopWindowClose(wct: WindowContainerTransaction, taskId: Int) { if (desktopModeTaskRepository.isOnlyActiveTask(taskId)) { fun onDesktopWindowClose(wct: WindowContainerTransaction, displayId: Int, taskId: Int) { if (desktopModeTaskRepository.isOnlyActiveNonClosingTask(taskId)) { removeWallpaperActivity(wct) } if (!desktopModeTaskRepository.addClosingTask(displayId, taskId)) { // Could happen if the task hasn't been removed from closing list after it disappeared KtProtoLog.w( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: the task with taskId=%d is already closing!", taskId ) } } /** Move a task with given `taskId` to fullscreen */ Loading Loading @@ -871,7 +880,7 @@ class DesktopTasksController( false } // Handle back navigation for the last window if wallpaper available shouldRemoveWallpaper(request) -> true shouldHandleBackNavigation(request) -> true // Only handle open or to front transitions request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> { reason = "transition type not handled (${request.type})" Loading Loading @@ -951,13 +960,9 @@ class DesktopTasksController( private fun shouldLaunchAsModal(task: TaskInfo) = Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task) private fun shouldRemoveWallpaper(request: TransitionRequestInfo): Boolean { private fun shouldHandleBackNavigation(request: TransitionRequestInfo): Boolean { return Flags.enableDesktopWindowingWallpaperActivity() && request.type == TRANSIT_TO_BACK && request.triggerTask?.let { task -> desktopModeTaskRepository.isOnlyActiveTask(task.taskId) } ?: false request.type == TRANSIT_TO_BACK } private fun handleFreeformTaskLaunch( Loading Loading @@ -1026,15 +1031,24 @@ class DesktopTasksController( /** Handle back navigation by removing wallpaper activity if it's the last active task */ private fun handleBackNavigation(task: RunningTaskInfo): WindowContainerTransaction? { if ( desktopModeTaskRepository.isOnlyActiveTask(task.taskId) && val wct = if ( desktopModeTaskRepository.isOnlyActiveNonClosingTask(task.taskId) && desktopModeTaskRepository.wallpaperActivityToken != null ) { // Remove wallpaper activity when the last active task is removed return WindowContainerTransaction().also { wct -> removeWallpaperActivity(wct) } WindowContainerTransaction().also { wct -> removeWallpaperActivity(wct) } } else { return null null } if (!desktopModeTaskRepository.addClosingTask(task.displayId, task.taskId)) { // Could happen if the task hasn't been removed from closing list after it disappeared KtProtoLog.w( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: the task with taskId=%d is already closing!", task.taskId ) } return wct } private fun addMoveToDesktopChanges( Loading libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +8 −0 Original line number Diff line number Diff line Loading @@ -122,6 +122,10 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, mDesktopModeTaskRepository.ifPresent(repository -> { repository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId); repository.unminimizeTask(taskInfo.displayId, taskInfo.taskId); if (repository.removeClosingTask(taskInfo.taskId)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, "Removing closing freeform task: #%d", taskInfo.taskId); } if (repository.removeActiveTask(taskInfo.taskId)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, "Removing active freeform task: #%d", taskInfo.taskId); Loading Loading @@ -150,6 +154,10 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, "Adding active freeform task: #%d", taskInfo.taskId); } } else if (repository.isClosingTask(taskInfo.taskId) && repository.removeClosingTask(taskInfo.taskId)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, "Removing closing freeform task: #%d", taskInfo.taskId); } repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible); Loading libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +1 −1 Original line number Diff line number Diff line Loading @@ -435,7 +435,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { SplitScreenController.EXIT_REASON_DESKTOP_MODE); } else { WindowContainerTransaction wct = new WindowContainerTransaction(); mDesktopTasksController.onDesktopWindowClose(wct, mTaskId); mDesktopTasksController.onDesktopWindowClose(wct, mDisplayId, mTaskId); mTaskOperations.closeTask(mTaskToken, wct); } } else if (id == R.id.back_button) { Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt +46 −14 Original line number Diff line number Diff line Loading @@ -119,54 +119,86 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test fun isOnlyActiveTask_noActiveTasks() { fun isOnlyActiveNonClosingTask_noActiveNonClosingTasks() { // Not an active task assertThat(repo.isOnlyActiveTask(1)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse() assertThat(repo.isClosingTask(1)).isFalse() } @Test fun isOnlyActiveTask_singleActiveTask() { fun isOnlyActiveNonClosingTask_singleActiveNonClosingTask() { repo.addActiveTask(DEFAULT_DISPLAY, 1) // The only active task assertThat(repo.isActiveTask(1)).isTrue() assertThat(repo.isOnlyActiveTask(1)).isTrue() assertThat(repo.isClosingTask(1)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(1)).isTrue() // Not an active task assertThat(repo.isActiveTask(99)).isFalse() assertThat(repo.isOnlyActiveTask(99)).isFalse() assertThat(repo.isClosingTask(99)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse() } @Test fun isOnlyActiveTask_multipleActiveTasks() { fun isOnlyActiveNonClosingTask_singleActiveClosingTask() { repo.addActiveTask(DEFAULT_DISPLAY, 1) repo.addClosingTask(DEFAULT_DISPLAY, 1) // The active task that's closing assertThat(repo.isActiveTask(1)).isTrue() assertThat(repo.isClosingTask(1)).isTrue() assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse() // Not an active task assertThat(repo.isActiveTask(99)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse() } @Test fun isOnlyActiveNonClosingTask_singleActiveMinimizedTask() { repo.addActiveTask(DEFAULT_DISPLAY, 1) repo.minimizeTask(DEFAULT_DISPLAY, 1) // The active task that's closing assertThat(repo.isActiveTask(1)).isTrue() assertThat(repo.isMinimizedTask(1)).isTrue() assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse() // Not an active task assertThat(repo.isActiveTask(99)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse() } @Test fun isOnlyActiveNonClosingTask_multipleActiveNonClosingTasks() { repo.addActiveTask(DEFAULT_DISPLAY, 1) repo.addActiveTask(DEFAULT_DISPLAY, 2) // Not the only task assertThat(repo.isActiveTask(1)).isTrue() assertThat(repo.isOnlyActiveTask(1)).isFalse() assertThat(repo.isClosingTask(1)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse() // Not the only task assertThat(repo.isActiveTask(2)).isTrue() assertThat(repo.isOnlyActiveTask(2)).isFalse() assertThat(repo.isClosingTask(2)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(2)).isFalse() // Not an active task assertThat(repo.isActiveTask(99)).isFalse() assertThat(repo.isOnlyActiveTask(99)).isFalse() assertThat(repo.isClosingTask(99)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse() } @Test fun isOnlyActiveTask_multipleDisplays() { fun isOnlyActiveNonClosingTask_multipleDisplays() { repo.addActiveTask(DEFAULT_DISPLAY, 1) repo.addActiveTask(DEFAULT_DISPLAY, 2) repo.addActiveTask(SECOND_DISPLAY, 3) // Not the only task on DEFAULT_DISPLAY assertThat(repo.isActiveTask(1)).isTrue() assertThat(repo.isOnlyActiveTask(1)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse() // Not the only task on DEFAULT_DISPLAY assertThat(repo.isActiveTask(2)).isTrue() assertThat(repo.isOnlyActiveTask(2)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(2)).isFalse() // The only active task on SECOND_DISPLAY assertThat(repo.isActiveTask(3)).isTrue() assertThat(repo.isOnlyActiveTask(3)).isTrue() assertThat(repo.isOnlyActiveNonClosingTask(3)).isTrue() // Not an active task assertThat(repo.isActiveTask(99)).isFalse() assertThat(repo.isOnlyActiveTask(99)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse() } @Test Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepository.kt +52 −3 Original line number Diff line number Diff line Loading @@ -46,6 +46,9 @@ class DesktopModeTaskRepository { val activeTasks: ArraySet<Int> = ArraySet(), val visibleTasks: ArraySet<Int> = ArraySet(), val minimizedTasks: ArraySet<Int> = ArraySet(), // Tasks that are closing, but are still visible // TODO(b/332682201): Remove when the repository state is updated via TransitionObserver val closingTasks: ArraySet<Int> = ArraySet(), // Tasks currently in freeform mode, ordered from top to bottom (top is at index 0). val freeformTasksInZOrder: ArrayList<Int> = ArrayList(), ) Loading Loading @@ -169,6 +172,42 @@ class DesktopModeTaskRepository { return result } /** * Mark a task with given [taskId] as closing on given [displayId] * * @return `true` if the task was not closing on given [displayId] */ fun addClosingTask(displayId: Int, taskId: Int): Boolean { val added = displayData.getOrCreate(displayId).closingTasks.add(taskId) if (added) { KtProtoLog.d( WM_SHELL_DESKTOP_MODE, "DesktopTaskRepo: added closing task=%d displayId=%d", taskId, displayId ) } return added } /** * Remove task with given [taskId] from closing tasks. * * @return `true` if the task was closing */ fun removeClosingTask(taskId: Int): Boolean { var removed = false displayData.forEach { _, data -> if (data.closingTasks.remove(taskId)) { removed = true } } if (removed) { KtProtoLog.d(WM_SHELL_DESKTOP_MODE, "DesktopTaskRepo: remove closing task=%d", taskId) } return removed } /** Check if a task with the given [taskId] was marked as an active task */ fun isActiveTask(taskId: Int): Boolean { return displayData.valueIterator().asSequence().any { data -> Loading @@ -176,6 +215,10 @@ class DesktopModeTaskRepository { } } /** Check if a task with the given [taskId] was marked as a closing task */ fun isClosingTask(taskId: Int): Boolean = displayData.valueIterator().asSequence().any { data -> taskId in data.closingTasks } /** Whether a task is visible. */ fun isVisibleTask(taskId: Int): Boolean { return displayData.valueIterator().asSequence().any { data -> Loading @@ -190,10 +233,16 @@ class DesktopModeTaskRepository { } } /** Check if a task with the given [taskId] is the only active task on its display */ fun isOnlyActiveTask(taskId: Int): Boolean { /** * Check if a task with the given [taskId] is the only active, non-closing, not-minimized task * on its display */ fun isOnlyActiveNonClosingTask(taskId: Int): Boolean { return displayData.valueIterator().asSequence().any { data -> data.activeTasks.singleOrNull() == taskId data.activeTasks .subtract(data.closingTasks) .subtract(data.minimizedTasks) .singleOrNull() == taskId } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt +27 −13 Original line number Diff line number Diff line Loading @@ -442,12 +442,21 @@ class DesktopTasksController( * active task. * * @param wct transaction to modify if the last active task is closed * @param displayId display id of the window that's being closed * @param taskId task id of the window that's being closed */ fun onDesktopWindowClose(wct: WindowContainerTransaction, taskId: Int) { if (desktopModeTaskRepository.isOnlyActiveTask(taskId)) { fun onDesktopWindowClose(wct: WindowContainerTransaction, displayId: Int, taskId: Int) { if (desktopModeTaskRepository.isOnlyActiveNonClosingTask(taskId)) { removeWallpaperActivity(wct) } if (!desktopModeTaskRepository.addClosingTask(displayId, taskId)) { // Could happen if the task hasn't been removed from closing list after it disappeared KtProtoLog.w( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: the task with taskId=%d is already closing!", taskId ) } } /** Move a task with given `taskId` to fullscreen */ Loading Loading @@ -871,7 +880,7 @@ class DesktopTasksController( false } // Handle back navigation for the last window if wallpaper available shouldRemoveWallpaper(request) -> true shouldHandleBackNavigation(request) -> true // Only handle open or to front transitions request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> { reason = "transition type not handled (${request.type})" Loading Loading @@ -951,13 +960,9 @@ class DesktopTasksController( private fun shouldLaunchAsModal(task: TaskInfo) = Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task) private fun shouldRemoveWallpaper(request: TransitionRequestInfo): Boolean { private fun shouldHandleBackNavigation(request: TransitionRequestInfo): Boolean { return Flags.enableDesktopWindowingWallpaperActivity() && request.type == TRANSIT_TO_BACK && request.triggerTask?.let { task -> desktopModeTaskRepository.isOnlyActiveTask(task.taskId) } ?: false request.type == TRANSIT_TO_BACK } private fun handleFreeformTaskLaunch( Loading Loading @@ -1026,15 +1031,24 @@ class DesktopTasksController( /** Handle back navigation by removing wallpaper activity if it's the last active task */ private fun handleBackNavigation(task: RunningTaskInfo): WindowContainerTransaction? { if ( desktopModeTaskRepository.isOnlyActiveTask(task.taskId) && val wct = if ( desktopModeTaskRepository.isOnlyActiveNonClosingTask(task.taskId) && desktopModeTaskRepository.wallpaperActivityToken != null ) { // Remove wallpaper activity when the last active task is removed return WindowContainerTransaction().also { wct -> removeWallpaperActivity(wct) } WindowContainerTransaction().also { wct -> removeWallpaperActivity(wct) } } else { return null null } if (!desktopModeTaskRepository.addClosingTask(task.displayId, task.taskId)) { // Could happen if the task hasn't been removed from closing list after it disappeared KtProtoLog.w( WM_SHELL_DESKTOP_MODE, "DesktopTasksController: the task with taskId=%d is already closing!", task.taskId ) } return wct } private fun addMoveToDesktopChanges( Loading
libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java +8 −0 Original line number Diff line number Diff line Loading @@ -122,6 +122,10 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, mDesktopModeTaskRepository.ifPresent(repository -> { repository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId); repository.unminimizeTask(taskInfo.displayId, taskInfo.taskId); if (repository.removeClosingTask(taskInfo.taskId)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, "Removing closing freeform task: #%d", taskInfo.taskId); } if (repository.removeActiveTask(taskInfo.taskId)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, "Removing active freeform task: #%d", taskInfo.taskId); Loading Loading @@ -150,6 +154,10 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener, ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, "Adding active freeform task: #%d", taskInfo.taskId); } } else if (repository.isClosingTask(taskInfo.taskId) && repository.removeClosingTask(taskInfo.taskId)) { ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE, "Removing closing freeform task: #%d", taskInfo.taskId); } repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId, taskInfo.isVisible); Loading
libs/WindowManager/Shell/src/com/android/wm/shell/windowdecor/DesktopModeWindowDecorViewModel.java +1 −1 Original line number Diff line number Diff line Loading @@ -435,7 +435,7 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel { SplitScreenController.EXIT_REASON_DESKTOP_MODE); } else { WindowContainerTransaction wct = new WindowContainerTransaction(); mDesktopTasksController.onDesktopWindowClose(wct, mTaskId); mDesktopTasksController.onDesktopWindowClose(wct, mDisplayId, mTaskId); mTaskOperations.closeTask(mTaskToken, wct); } } else if (id == R.id.back_button) { Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopModeTaskRepositoryTest.kt +46 −14 Original line number Diff line number Diff line Loading @@ -119,54 +119,86 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() { } @Test fun isOnlyActiveTask_noActiveTasks() { fun isOnlyActiveNonClosingTask_noActiveNonClosingTasks() { // Not an active task assertThat(repo.isOnlyActiveTask(1)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse() assertThat(repo.isClosingTask(1)).isFalse() } @Test fun isOnlyActiveTask_singleActiveTask() { fun isOnlyActiveNonClosingTask_singleActiveNonClosingTask() { repo.addActiveTask(DEFAULT_DISPLAY, 1) // The only active task assertThat(repo.isActiveTask(1)).isTrue() assertThat(repo.isOnlyActiveTask(1)).isTrue() assertThat(repo.isClosingTask(1)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(1)).isTrue() // Not an active task assertThat(repo.isActiveTask(99)).isFalse() assertThat(repo.isOnlyActiveTask(99)).isFalse() assertThat(repo.isClosingTask(99)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse() } @Test fun isOnlyActiveTask_multipleActiveTasks() { fun isOnlyActiveNonClosingTask_singleActiveClosingTask() { repo.addActiveTask(DEFAULT_DISPLAY, 1) repo.addClosingTask(DEFAULT_DISPLAY, 1) // The active task that's closing assertThat(repo.isActiveTask(1)).isTrue() assertThat(repo.isClosingTask(1)).isTrue() assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse() // Not an active task assertThat(repo.isActiveTask(99)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse() } @Test fun isOnlyActiveNonClosingTask_singleActiveMinimizedTask() { repo.addActiveTask(DEFAULT_DISPLAY, 1) repo.minimizeTask(DEFAULT_DISPLAY, 1) // The active task that's closing assertThat(repo.isActiveTask(1)).isTrue() assertThat(repo.isMinimizedTask(1)).isTrue() assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse() // Not an active task assertThat(repo.isActiveTask(99)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse() } @Test fun isOnlyActiveNonClosingTask_multipleActiveNonClosingTasks() { repo.addActiveTask(DEFAULT_DISPLAY, 1) repo.addActiveTask(DEFAULT_DISPLAY, 2) // Not the only task assertThat(repo.isActiveTask(1)).isTrue() assertThat(repo.isOnlyActiveTask(1)).isFalse() assertThat(repo.isClosingTask(1)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse() // Not the only task assertThat(repo.isActiveTask(2)).isTrue() assertThat(repo.isOnlyActiveTask(2)).isFalse() assertThat(repo.isClosingTask(2)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(2)).isFalse() // Not an active task assertThat(repo.isActiveTask(99)).isFalse() assertThat(repo.isOnlyActiveTask(99)).isFalse() assertThat(repo.isClosingTask(99)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse() } @Test fun isOnlyActiveTask_multipleDisplays() { fun isOnlyActiveNonClosingTask_multipleDisplays() { repo.addActiveTask(DEFAULT_DISPLAY, 1) repo.addActiveTask(DEFAULT_DISPLAY, 2) repo.addActiveTask(SECOND_DISPLAY, 3) // Not the only task on DEFAULT_DISPLAY assertThat(repo.isActiveTask(1)).isTrue() assertThat(repo.isOnlyActiveTask(1)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse() // Not the only task on DEFAULT_DISPLAY assertThat(repo.isActiveTask(2)).isTrue() assertThat(repo.isOnlyActiveTask(2)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(2)).isFalse() // The only active task on SECOND_DISPLAY assertThat(repo.isActiveTask(3)).isTrue() assertThat(repo.isOnlyActiveTask(3)).isTrue() assertThat(repo.isOnlyActiveNonClosingTask(3)).isTrue() // Not an active task assertThat(repo.isActiveTask(99)).isFalse() assertThat(repo.isOnlyActiveTask(99)).isFalse() assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse() } @Test Loading