Loading libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +2 −1 Original line number Diff line number Diff line Loading @@ -925,7 +925,8 @@ public abstract class WMShellModule { DesktopState desktopState) { if (ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() && desktopState.canEnterDesktopMode()) { return Optional.of(new DesktopTaskChangeListener(desktopUserRepositories)); return Optional.of(new DesktopTaskChangeListener( desktopUserRepositories, desktopState)); } return Optional.empty(); } Loading libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt +37 −3 Original line number Diff line number Diff line Loading @@ -18,17 +18,27 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.window.DesktopExperienceFlags import android.window.DesktopModeFlags import com.android.internal.protolog.ProtoLog import com.android.wm.shell.freeform.TaskChangeListener import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.desktopmode.DesktopState /** Manages tasks handling specific to Android Desktop Mode. */ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUserRepositories) : TaskChangeListener { class DesktopTaskChangeListener( private val desktopUserRepositories: DesktopUserRepositories, private val desktopState: DesktopState, ) : TaskChangeListener { override fun onTaskOpening(taskInfo: RunningTaskInfo) { logD("onTaskOpening for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) if ( !desktopState.isDesktopModeSupportedOnDisplay(taskInfo.displayId) && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ) { return } val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (!isFreeformTask(taskInfo) && desktopRepository.isActiveTask(taskInfo.taskId)) { Loading @@ -42,6 +52,12 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser override fun onTaskChanging(taskInfo: RunningTaskInfo) { logD("onTaskChanging for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) if ( !desktopState.isDesktopModeSupportedOnDisplay(taskInfo.displayId) && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ) { return } val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) // TODO: b/394281403 - with multiple desks, it's possible to have a non-freeform task Loading Loading @@ -78,6 +94,12 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser override fun onTaskMovingToFront(taskInfo: RunningTaskInfo) { logD("onTaskMovingToFront for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) if ( !desktopState.isDesktopModeSupportedOnDisplay(taskInfo.displayId) && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ) { return } val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) // When the task change is from a task in the desktop repository which is now fullscreen, Loading @@ -93,15 +115,27 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser } override fun onTaskMovingToBack(taskInfo: RunningTaskInfo) { logD("onTaskMovingToBack for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) if ( !desktopState.isDesktopModeSupportedOnDisplay(taskInfo.displayId) && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ) { return } val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (!desktopRepository.isActiveTask(taskInfo.taskId)) return logD("onTaskMovingToBack for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) desktopRepository.updateTask(taskInfo.displayId, taskInfo.taskId, /* isVisible= */ false) } override fun onTaskClosing(taskInfo: RunningTaskInfo) { logD("onTaskClosing for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) if ( !desktopState.isDesktopModeSupportedOnDisplay(taskInfo.displayId) && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ) { return } val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (!desktopRepository.isActiveTask(taskInfo.taskId)) return Loading libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt +76 −1 Original line number Diff line number Diff line Loading @@ -21,13 +21,17 @@ import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner 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.wm.shell.ShellTestCase import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask import com.android.wm.shell.shared.desktopmode.FakeDesktopState import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.kotlin.any import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.verify Loading @@ -46,10 +50,15 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { private val desktopUserRepositories = mock<DesktopUserRepositories>() private val desktopRepository = mock<DesktopRepository>() private val desktopState = FakeDesktopState().apply { canEnterDesktopMode = true overrideDesktopModeSupportPerDisplay[UNSUPPORTED_DISPLAY_ID] = false } @Before fun setUp() { desktopTaskChangeListener = DesktopTaskChangeListener(desktopUserRepositories) desktopTaskChangeListener = DesktopTaskChangeListener(desktopUserRepositories, desktopState) whenever(desktopUserRepositories.current).thenReturn(desktopRepository) whenever(desktopUserRepositories.getProfile(anyInt())).thenReturn(desktopRepository) Loading Loading @@ -98,6 +107,18 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { verify(desktopUserRepositories.current).addTask(task.displayId, task.taskId, task.isVisible) } @Test @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun onTaskOpening_desktopModeNotSupportedInDisplay_noOp() { val task = createFreeformTask(UNSUPPORTED_DISPLAY_ID) whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(false) desktopTaskChangeListener.onTaskOpening(task) verify(desktopUserRepositories.current, never()) .addTask(displayId = eq(UNSUPPORTED_DISPLAY_ID), taskId = any(), isVisible = any()) } @Test fun onTaskChanging_fullscreenTask_activeInDesktopRepository_removesTaskFromRepo() { val task = createFullscreenTask().apply { isVisible = true } Loading Loading @@ -127,6 +148,17 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { verify(desktopUserRepositories.current).addTask(task.displayId, task.taskId, task.isVisible) } @Test @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun onTaskChanging_desktopModeNotSupportedInDisplay_noOp() { val task = createFreeformTask(UNSUPPORTED_DISPLAY_ID) desktopTaskChangeListener.onTaskChanging(task) verify(desktopUserRepositories.current, never()) .addTask(displayId = eq(UNSUPPORTED_DISPLAY_ID), taskId = any(), isVisible = any()) } @Test fun onTaskMovingToFront_fullscreenTask_activeTaskInDesktopRepo_removesTaskFromRepo() { val task = createFullscreenTask().apply { isVisible = true } Loading Loading @@ -156,6 +188,17 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { verify(desktopUserRepositories.current).addTask(task.displayId, task.taskId, task.isVisible) } @Test @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun onTaskMovingToFront_desktopModeNotSupportedInDisplay_noOp() { val task = createFreeformTask(UNSUPPORTED_DISPLAY_ID).apply { isVisible = true } desktopTaskChangeListener.onTaskMovingToFront(task) verify(desktopUserRepositories.current, never()) .addTask(displayId = eq(UNSUPPORTED_DISPLAY_ID), taskId = any(), isVisible = any()) } @Test fun onTaskMovingToBack_activeTaskInRepo_updatesTask() { val task = createFreeformTask().apply { isVisible = true } Loading @@ -178,6 +221,18 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { .updateTask(task.displayId, task.taskId, /* isVisible= */ false) } @Test @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun onTaskMovingToBack_desktopModeNotSupportedInDisplay_noOp() { val task = createFreeformTask(UNSUPPORTED_DISPLAY_ID) whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) desktopTaskChangeListener.onTaskMovingToBack(task) verify(desktopUserRepositories.current, never()) .updateTask(displayId = eq(UNSUPPORTED_DISPLAY_ID), taskId = any(), isVisible = any()) } @Test @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) fun onTaskClosing_backNavEnabled_nonClosingTask_minimizesTaskInRepo() { Loading Loading @@ -218,4 +273,24 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { verify(desktopUserRepositories.current).removeClosingTask(task.taskId) verify(desktopUserRepositories.current).removeTask(task.displayId, task.taskId) } @Test @EnableFlags( FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION, FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND, ) fun onTaskClosing_desktopModeNotSupportedInDisplay_noOp() { val task = createFreeformTask(UNSUPPORTED_DISPLAY_ID).apply { isVisible = true } whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) whenever(desktopUserRepositories.current.isClosingTask(task.taskId)).thenReturn(true) desktopTaskChangeListener.onTaskClosing(task) verify(desktopUserRepositories.current, never()).removeClosingTask(task.taskId) verify(desktopUserRepositories.current, never()).removeTask(task.displayId, task.taskId) } companion object { private const val UNSUPPORTED_DISPLAY_ID = 3 } } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +2 −1 Original line number Diff line number Diff line Loading @@ -925,7 +925,8 @@ public abstract class WMShellModule { DesktopState desktopState) { if (ENABLE_WINDOWING_TRANSITION_HANDLERS_OBSERVERS.isTrue() && desktopState.canEnterDesktopMode()) { return Optional.of(new DesktopTaskChangeListener(desktopUserRepositories)); return Optional.of(new DesktopTaskChangeListener( desktopUserRepositories, desktopState)); } return Optional.empty(); } Loading
libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListener.kt +37 −3 Original line number Diff line number Diff line Loading @@ -18,17 +18,27 @@ package com.android.wm.shell.desktopmode import android.app.ActivityManager.RunningTaskInfo import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM import android.window.DesktopExperienceFlags import android.window.DesktopModeFlags import com.android.internal.protolog.ProtoLog import com.android.wm.shell.freeform.TaskChangeListener import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE import com.android.wm.shell.shared.desktopmode.DesktopState /** Manages tasks handling specific to Android Desktop Mode. */ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUserRepositories) : TaskChangeListener { class DesktopTaskChangeListener( private val desktopUserRepositories: DesktopUserRepositories, private val desktopState: DesktopState, ) : TaskChangeListener { override fun onTaskOpening(taskInfo: RunningTaskInfo) { logD("onTaskOpening for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) if ( !desktopState.isDesktopModeSupportedOnDisplay(taskInfo.displayId) && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ) { return } val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (!isFreeformTask(taskInfo) && desktopRepository.isActiveTask(taskInfo.taskId)) { Loading @@ -42,6 +52,12 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser override fun onTaskChanging(taskInfo: RunningTaskInfo) { logD("onTaskChanging for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) if ( !desktopState.isDesktopModeSupportedOnDisplay(taskInfo.displayId) && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ) { return } val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) // TODO: b/394281403 - with multiple desks, it's possible to have a non-freeform task Loading Loading @@ -78,6 +94,12 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser override fun onTaskMovingToFront(taskInfo: RunningTaskInfo) { logD("onTaskMovingToFront for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) if ( !desktopState.isDesktopModeSupportedOnDisplay(taskInfo.displayId) && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ) { return } val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) // When the task change is from a task in the desktop repository which is now fullscreen, Loading @@ -93,15 +115,27 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser } override fun onTaskMovingToBack(taskInfo: RunningTaskInfo) { logD("onTaskMovingToBack for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) if ( !desktopState.isDesktopModeSupportedOnDisplay(taskInfo.displayId) && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ) { return } val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (!desktopRepository.isActiveTask(taskInfo.taskId)) return logD("onTaskMovingToBack for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) desktopRepository.updateTask(taskInfo.displayId, taskInfo.taskId, /* isVisible= */ false) } override fun onTaskClosing(taskInfo: RunningTaskInfo) { logD("onTaskClosing for taskId=%d, displayId=%d", taskInfo.taskId, taskInfo.displayId) if ( !desktopState.isDesktopModeSupportedOnDisplay(taskInfo.displayId) && DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue ) { return } val desktopRepository: DesktopRepository = desktopUserRepositories.getProfile(taskInfo.userId) if (!desktopRepository.isActiveTask(taskInfo.taskId)) return Loading
libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTaskChangeListenerTest.kt +76 −1 Original line number Diff line number Diff line Loading @@ -21,13 +21,17 @@ import android.platform.test.annotations.EnableFlags import android.testing.AndroidTestingRunner 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.wm.shell.ShellTestCase import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFreeformTask import com.android.wm.shell.desktopmode.DesktopTestHelpers.createFullscreenTask import com.android.wm.shell.shared.desktopmode.FakeDesktopState import org.junit.Before import org.junit.Test import org.junit.runner.RunWith import org.mockito.ArgumentMatchers.anyInt import org.mockito.kotlin.any import org.mockito.kotlin.eq import org.mockito.kotlin.mock import org.mockito.kotlin.never import org.mockito.kotlin.verify Loading @@ -46,10 +50,15 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { private val desktopUserRepositories = mock<DesktopUserRepositories>() private val desktopRepository = mock<DesktopRepository>() private val desktopState = FakeDesktopState().apply { canEnterDesktopMode = true overrideDesktopModeSupportPerDisplay[UNSUPPORTED_DISPLAY_ID] = false } @Before fun setUp() { desktopTaskChangeListener = DesktopTaskChangeListener(desktopUserRepositories) desktopTaskChangeListener = DesktopTaskChangeListener(desktopUserRepositories, desktopState) whenever(desktopUserRepositories.current).thenReturn(desktopRepository) whenever(desktopUserRepositories.getProfile(anyInt())).thenReturn(desktopRepository) Loading Loading @@ -98,6 +107,18 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { verify(desktopUserRepositories.current).addTask(task.displayId, task.taskId, task.isVisible) } @Test @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun onTaskOpening_desktopModeNotSupportedInDisplay_noOp() { val task = createFreeformTask(UNSUPPORTED_DISPLAY_ID) whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(false) desktopTaskChangeListener.onTaskOpening(task) verify(desktopUserRepositories.current, never()) .addTask(displayId = eq(UNSUPPORTED_DISPLAY_ID), taskId = any(), isVisible = any()) } @Test fun onTaskChanging_fullscreenTask_activeInDesktopRepository_removesTaskFromRepo() { val task = createFullscreenTask().apply { isVisible = true } Loading Loading @@ -127,6 +148,17 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { verify(desktopUserRepositories.current).addTask(task.displayId, task.taskId, task.isVisible) } @Test @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun onTaskChanging_desktopModeNotSupportedInDisplay_noOp() { val task = createFreeformTask(UNSUPPORTED_DISPLAY_ID) desktopTaskChangeListener.onTaskChanging(task) verify(desktopUserRepositories.current, never()) .addTask(displayId = eq(UNSUPPORTED_DISPLAY_ID), taskId = any(), isVisible = any()) } @Test fun onTaskMovingToFront_fullscreenTask_activeTaskInDesktopRepo_removesTaskFromRepo() { val task = createFullscreenTask().apply { isVisible = true } Loading Loading @@ -156,6 +188,17 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { verify(desktopUserRepositories.current).addTask(task.displayId, task.taskId, task.isVisible) } @Test @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun onTaskMovingToFront_desktopModeNotSupportedInDisplay_noOp() { val task = createFreeformTask(UNSUPPORTED_DISPLAY_ID).apply { isVisible = true } desktopTaskChangeListener.onTaskMovingToFront(task) verify(desktopUserRepositories.current, never()) .addTask(displayId = eq(UNSUPPORTED_DISPLAY_ID), taskId = any(), isVisible = any()) } @Test fun onTaskMovingToBack_activeTaskInRepo_updatesTask() { val task = createFreeformTask().apply { isVisible = true } Loading @@ -178,6 +221,18 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { .updateTask(task.displayId, task.taskId, /* isVisible= */ false) } @Test @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND) fun onTaskMovingToBack_desktopModeNotSupportedInDisplay_noOp() { val task = createFreeformTask(UNSUPPORTED_DISPLAY_ID) whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) desktopTaskChangeListener.onTaskMovingToBack(task) verify(desktopUserRepositories.current, never()) .updateTask(displayId = eq(UNSUPPORTED_DISPLAY_ID), taskId = any(), isVisible = any()) } @Test @EnableFlags(FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION) fun onTaskClosing_backNavEnabled_nonClosingTask_minimizesTaskInRepo() { Loading Loading @@ -218,4 +273,24 @@ class DesktopTaskChangeListenerTest : ShellTestCase() { verify(desktopUserRepositories.current).removeClosingTask(task.taskId) verify(desktopUserRepositories.current).removeTask(task.displayId, task.taskId) } @Test @EnableFlags( FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION, FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND, ) fun onTaskClosing_desktopModeNotSupportedInDisplay_noOp() { val task = createFreeformTask(UNSUPPORTED_DISPLAY_ID).apply { isVisible = true } whenever(desktopUserRepositories.current.isActiveTask(task.taskId)).thenReturn(true) whenever(desktopUserRepositories.current.isClosingTask(task.taskId)).thenReturn(true) desktopTaskChangeListener.onTaskClosing(task) verify(desktopUserRepositories.current, never()).removeClosingTask(task.taskId) verify(desktopUserRepositories.current, never()).removeTask(task.displayId, task.taskId) } companion object { private const val UNSUPPORTED_DISPLAY_ID = 3 } }