Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt +30 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.app.ActivityManager import android.content.Context import android.os.IBinder import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CLOSE import android.view.WindowManager.TRANSIT_TO_BACK import android.window.DesktopExperienceFlags import android.window.DesktopModeFlags Loading Loading @@ -154,10 +155,13 @@ class DesktopTasksLimiter( ) { val launchDetails = pendingTaskLimitTransitionTokens.remove(transition) ?: return logV("handleTaskLimitTransitionReady, transition=$transition, info=$info") markClosingTasks(taskRepository, info, launchDetails) transitions.runOnIdle { val expandedTaskIds = taskRepository.getExpandedTasksIdsInDeskOrdered(launchDetails.deskId) logV("runOnIdle, expandedTasks=$expandedTaskIds") taskRepository.getExpandedTasksIdsInDeskOrdered(launchDetails.deskId).filter { !taskRepository.isClosingTask(it) } logV("runOnIdle, expandedTasks=$expandedTaskIds, after transition=$transition") val taskIdToMinimize = getTaskIdToMinimize(expandedTaskIds, /* launchingNewIntent= */ false) if (taskIdToMinimize != null) { Loading @@ -166,6 +170,30 @@ class DesktopTasksLimiter( } } private fun markClosingTasks( taskRepository: DesktopRepository, info: TransitionInfo, launchDetails: LaunchDetails, ) { // markClosingTasks() is a workaround while // ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS is ramping up, so don't run this // logic when that flag has been enabled. if (DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue) { return } info.changes.forEach { change -> val taskInfo = change.taskInfo ?: return@forEach if (change.mode != TRANSIT_CLOSE || !taskInfo.isFreeform) { return@forEach } taskRepository.addClosingTask( taskInfo.displayId, launchDetails.deskId, taskInfo.taskId, ) } } private fun triggerMinimizeTransition(deskId: Int, taskIdToMinimize: Int) { val task = shellTaskOrganizer.getRunningTaskInfo(taskIdToMinimize) ?: return logV("triggerMinimizeTransition, found running task -> start transition, %s", task) Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt +83 −3 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CLOSE import android.view.WindowManager.TRANSIT_OPEN import android.view.WindowManager.TRANSIT_TO_BACK import android.window.TransitionInfo Loading @@ -35,6 +36,7 @@ import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_R import androidx.test.filters.SmallTest import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION import com.android.window.flags.Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND import com.android.window.flags.Flags.FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.ShellExecutor Loading Loading @@ -75,6 +77,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.eq import org.mockito.kotlin.never import org.mockito.kotlin.times import org.mockito.kotlin.whenever /** Loading Loading @@ -707,7 +710,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { taskId = launchTask.taskId, ) val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, launchTask).build() TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_OPEN, launchTask).build() whenever(desktopMixedTransitionHandler.startTaskLimitMinimizeTransition(any(), anyInt())) .thenReturn(minimizeTransition) Loading @@ -729,7 +732,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { (1..MAX_TASK_LIMIT).map { setUpFreeformTask() } val launchTask = setUpFreeformTask() val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, launchTask).build() TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_OPEN, launchTask).build() whenever(desktopMixedTransitionHandler.startTaskLimitMinimizeTransition(any(), anyInt())) .thenReturn(Binder()) Loading @@ -752,7 +755,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { taskId = task.taskId, ) val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build() TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_OPEN, task).build() whenever(desktopMixedTransitionHandler.startTaskLimitMinimizeTransition(any(), anyInt())) .thenReturn(Binder()) Loading @@ -765,6 +768,83 @@ class DesktopTasksLimiterTest : ShellTestCase() { .startTaskLimitMinimizeTransition(any(), any()) } @Test @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) fun onTransitionReady_taskLimitTransition_taskTrampoline_doesntStartMinimizeTransition() { desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val transition1 = Binder() val transition2 = Binder() (2..MAX_TASK_LIMIT).map { setUpFreeformTask() } val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() desktopTasksLimiter.addPendingTaskLimitTransition( transition1, deskId = 0, taskId = task1.taskId, ) desktopTasksLimiter.addPendingTaskLimitTransition( transition2, deskId = 0, taskId = task2.taskId, ) val transitionInfo1 = TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_OPEN, task1).build() val transitionInfo2 = TransitionInfoBuilder(TRANSIT_OPEN) .addChange(TRANSIT_OPEN, task2) .addChange(TRANSIT_CLOSE, task1) .build() // Start the initial task launch transition - launching a trampoline task callOnTransitionReady(transition1, transitionInfo1) // Start the second task launch transition - launching the final task and closing the // trampoline task callOnTransitionReady(transition2, transitionInfo2) val onIdleArgumentCaptor = argumentCaptor<Runnable>() verify(transitions, times(2)).runOnIdle(onIdleArgumentCaptor.capture()) onIdleArgumentCaptor.allValues.forEach { runnable -> runnable.run() } verify(desktopMixedTransitionHandler, never()) .startTaskLimitMinimizeTransition(any(), any()) } @Test @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) fun onTransitionReady_taskLimitTransition_taskTrampoline_marksTramplineAsClosed() { desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val transition1 = Binder() val transition2 = Binder() val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() desktopTasksLimiter.addPendingTaskLimitTransition( transition1, deskId = 0, taskId = task1.taskId, ) desktopTasksLimiter.addPendingTaskLimitTransition( transition2, deskId = 0, taskId = task2.taskId, ) val transitionInfo1 = TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_OPEN, task1).build() val transitionInfo2 = TransitionInfoBuilder(TRANSIT_OPEN) .addChange(TRANSIT_OPEN, task2) .addChange(TRANSIT_CLOSE, task1) .build() // Start the initial task launch transition - launching a trampoline task callOnTransitionReady(transition1, transitionInfo1) // Start the second task launch transition - launching the final task and closing the // trampoline task callOnTransitionReady(transition2, transitionInfo2) assertThat(desktopTaskRepo.isClosingTask(task1.taskId)).isTrue() } private fun setUpFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo { val task = createFreeformTask(displayId) `when`(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) Loading Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksLimiter.kt +30 −2 Original line number Diff line number Diff line Loading @@ -20,6 +20,7 @@ import android.app.ActivityManager import android.content.Context import android.os.IBinder import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CLOSE import android.view.WindowManager.TRANSIT_TO_BACK import android.window.DesktopExperienceFlags import android.window.DesktopModeFlags Loading Loading @@ -154,10 +155,13 @@ class DesktopTasksLimiter( ) { val launchDetails = pendingTaskLimitTransitionTokens.remove(transition) ?: return logV("handleTaskLimitTransitionReady, transition=$transition, info=$info") markClosingTasks(taskRepository, info, launchDetails) transitions.runOnIdle { val expandedTaskIds = taskRepository.getExpandedTasksIdsInDeskOrdered(launchDetails.deskId) logV("runOnIdle, expandedTasks=$expandedTaskIds") taskRepository.getExpandedTasksIdsInDeskOrdered(launchDetails.deskId).filter { !taskRepository.isClosingTask(it) } logV("runOnIdle, expandedTasks=$expandedTaskIds, after transition=$transition") val taskIdToMinimize = getTaskIdToMinimize(expandedTaskIds, /* launchingNewIntent= */ false) if (taskIdToMinimize != null) { Loading @@ -166,6 +170,30 @@ class DesktopTasksLimiter( } } private fun markClosingTasks( taskRepository: DesktopRepository, info: TransitionInfo, launchDetails: LaunchDetails, ) { // markClosingTasks() is a workaround while // ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS is ramping up, so don't run this // logic when that flag has been enabled. if (DesktopModeFlags.ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue) { return } info.changes.forEach { change -> val taskInfo = change.taskInfo ?: return@forEach if (change.mode != TRANSIT_CLOSE || !taskInfo.isFreeform) { return@forEach } taskRepository.addClosingTask( taskInfo.displayId, launchDetails.deskId, taskInfo.taskId, ) } } private fun triggerMinimizeTransition(deskId: Int, taskIdToMinimize: Int) { val task = shellTaskOrganizer.getRunningTaskInfo(taskIdToMinimize) ?: return logV("triggerMinimizeTransition, found running task -> start transition, %s", task) Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksLimiterTest.kt +83 −3 Original line number Diff line number Diff line Loading @@ -26,6 +26,7 @@ import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner import android.view.Display.DEFAULT_DISPLAY import android.view.SurfaceControl import android.view.WindowManager.TRANSIT_CLOSE import android.view.WindowManager.TRANSIT_OPEN import android.view.WindowManager.TRANSIT_TO_BACK import android.window.TransitionInfo Loading @@ -35,6 +36,7 @@ import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_R import androidx.test.filters.SmallTest import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION import com.android.window.flags.Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND import com.android.window.flags.Flags.FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS import com.android.wm.shell.ShellTaskOrganizer import com.android.wm.shell.ShellTestCase import com.android.wm.shell.common.ShellExecutor Loading Loading @@ -75,6 +77,7 @@ import org.mockito.kotlin.any import org.mockito.kotlin.argumentCaptor import org.mockito.kotlin.eq import org.mockito.kotlin.never import org.mockito.kotlin.times import org.mockito.kotlin.whenever /** Loading Loading @@ -707,7 +710,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { taskId = launchTask.taskId, ) val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, launchTask).build() TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_OPEN, launchTask).build() whenever(desktopMixedTransitionHandler.startTaskLimitMinimizeTransition(any(), anyInt())) .thenReturn(minimizeTransition) Loading @@ -729,7 +732,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { (1..MAX_TASK_LIMIT).map { setUpFreeformTask() } val launchTask = setUpFreeformTask() val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, launchTask).build() TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_OPEN, launchTask).build() whenever(desktopMixedTransitionHandler.startTaskLimitMinimizeTransition(any(), anyInt())) .thenReturn(Binder()) Loading @@ -752,7 +755,7 @@ class DesktopTasksLimiterTest : ShellTestCase() { taskId = task.taskId, ) val transitionInfo = TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_TO_BACK, task).build() TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_OPEN, task).build() whenever(desktopMixedTransitionHandler.startTaskLimitMinimizeTransition(any(), anyInt())) .thenReturn(Binder()) Loading @@ -765,6 +768,83 @@ class DesktopTasksLimiterTest : ShellTestCase() { .startTaskLimitMinimizeTransition(any(), any()) } @Test @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) fun onTransitionReady_taskLimitTransition_taskTrampoline_doesntStartMinimizeTransition() { desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val transition1 = Binder() val transition2 = Binder() (2..MAX_TASK_LIMIT).map { setUpFreeformTask() } val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() desktopTasksLimiter.addPendingTaskLimitTransition( transition1, deskId = 0, taskId = task1.taskId, ) desktopTasksLimiter.addPendingTaskLimitTransition( transition2, deskId = 0, taskId = task2.taskId, ) val transitionInfo1 = TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_OPEN, task1).build() val transitionInfo2 = TransitionInfoBuilder(TRANSIT_OPEN) .addChange(TRANSIT_OPEN, task2) .addChange(TRANSIT_CLOSE, task1) .build() // Start the initial task launch transition - launching a trampoline task callOnTransitionReady(transition1, transitionInfo1) // Start the second task launch transition - launching the final task and closing the // trampoline task callOnTransitionReady(transition2, transitionInfo2) val onIdleArgumentCaptor = argumentCaptor<Runnable>() verify(transitions, times(2)).runOnIdle(onIdleArgumentCaptor.capture()) onIdleArgumentCaptor.allValues.forEach { runnable -> runnable.run() } verify(desktopMixedTransitionHandler, never()) .startTaskLimitMinimizeTransition(any(), any()) } @Test @DisableFlags(FLAG_ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS) fun onTransitionReady_taskLimitTransition_taskTrampoline_marksTramplineAsClosed() { desktopTaskRepo.addDesk(displayId = DEFAULT_DISPLAY, deskId = 0) desktopTaskRepo.setActiveDesk(displayId = DEFAULT_DISPLAY, deskId = 0) val transition1 = Binder() val transition2 = Binder() val task1 = setUpFreeformTask() val task2 = setUpFreeformTask() desktopTasksLimiter.addPendingTaskLimitTransition( transition1, deskId = 0, taskId = task1.taskId, ) desktopTasksLimiter.addPendingTaskLimitTransition( transition2, deskId = 0, taskId = task2.taskId, ) val transitionInfo1 = TransitionInfoBuilder(TRANSIT_OPEN).addChange(TRANSIT_OPEN, task1).build() val transitionInfo2 = TransitionInfoBuilder(TRANSIT_OPEN) .addChange(TRANSIT_OPEN, task2) .addChange(TRANSIT_CLOSE, task1) .build() // Start the initial task launch transition - launching a trampoline task callOnTransitionReady(transition1, transitionInfo1) // Start the second task launch transition - launching the final task and closing the // trampoline task callOnTransitionReady(transition2, transitionInfo2) assertThat(desktopTaskRepo.isClosingTask(task1.taskId)).isTrue() } private fun setUpFreeformTask(displayId: Int = DEFAULT_DISPLAY): RunningTaskInfo { val task = createFreeformTask(displayId) `when`(shellTaskOrganizer.getRunningTaskInfo(task.taskId)).thenReturn(task) Loading