summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Treehugger Robot <android-test-infra-autosubmit@system.gserviceaccount.com> 2025-01-31 16:38:03 -0800
committer Android (Google) Code Review <android-gerrit@google.com> 2025-01-31 16:38:03 -0800
commit72dbc2acfe41ce4c2f5c42760912b4dba66e51f4 (patch)
tree699def9dd2c778e253d07da6589aef261182d18b
parent43e6543d566f53dcc4e78bda20dc37aa172b57b1 (diff)
parentb6d9507d8acd7c713bf6e00051ff4b71c3571ca5 (diff)
Merge "[7/N] Desks: Implement desk activation" into main
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java5
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt6
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt116
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DeskTransition.kt4
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt3
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt17
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt6
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt244
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt26
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt21
11 files changed, 373 insertions, 79 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index 6f16e047a968..89eff5ea618c 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -1157,9 +1157,10 @@ public abstract class WMShellModule {
@WMSingleton
@Provides
static DesksTransitionObserver provideDesksTransitionObserver(
- @NonNull @DynamicOverride DesktopUserRepositories desktopUserRepositories
+ @NonNull @DynamicOverride DesktopUserRepositories desktopUserRepositories,
+ @NonNull DesksOrganizer desksOrganizer
) {
- return new DesksTransitionObserver(desktopUserRepositories);
+ return new DesksTransitionObserver(desktopUserRepositories, desksOrganizer);
}
@WMSingleton
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
index b93d2e396402..b0a38a85e0b2 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopModeShellCommandHandler.kt
@@ -131,8 +131,8 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
pw.println("Error: desk id should be an integer")
return false
}
- pw.println("Not implemented.")
- return false
+ controller.activateDesk(deskId)
+ return true
}
private fun runRemoveDesk(args: Array<String>, pw: PrintWriter): Boolean {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
index 043b353ba380..9583f3da2ee3 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopRepository.kt
@@ -226,6 +226,10 @@ class DesktopRepository(
desktopData.setActiveDesk(displayId = displayId, deskId = deskId)
}
+ /** Returns the id of the active desk in the given display, if any. */
+ @VisibleForTesting
+ fun getActiveDeskId(displayId: Int): Int? = desktopData.getActiveDesk(displayId)?.deskId
+
/**
* Adds task with [taskId] to the list of freeform tasks on [displayId]'s active desk.
*
@@ -435,7 +439,7 @@ class DesktopRepository(
?: error("Expected non-null desk in display $displayId")
unminimizeTask(displayId, taskId)
} else {
- desktopData.getActiveDesk(displayId)?.visibleTasks?.remove(taskId)
+ desktopData.getDefaultDesk(displayId)?.visibleTasks?.remove(taskId)
}
val newCount = getVisibleTaskCount(displayId)
if (prevCount != newCount) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
index 53f37659cf49..645367780390 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksController.kt
@@ -315,24 +315,10 @@ class DesktopTasksController(
}
/** Show all tasks, that are part of the desktop, on top of launcher */
+ @Deprecated("Use activateDesk() instead.", ReplaceWith("activateDesk()"))
fun showDesktopApps(displayId: Int, remoteTransition: RemoteTransition? = null) {
logV("showDesktopApps")
- val wct = WindowContainerTransaction()
- bringDesktopAppsToFront(displayId, wct)
-
- val transitionType = transitionType(remoteTransition)
- val handler =
- remoteTransition?.let {
- OneShotRemoteHandler(transitions.mainExecutor, remoteTransition)
- }
- transitions.startTransition(transitionType, wct, handler).also { t ->
- handler?.setTransition(t)
- }
-
- // launch from recent DesktopTaskView
- desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(
- FREEFORM_ANIMATION_DURATION
- )
+ activateDefaultDeskInDisplay(displayId, remoteTransition)
}
/** Gets number of visible freeform tasks in [displayId]. */
@@ -606,9 +592,9 @@ class DesktopTasksController(
val wct = WindowContainerTransaction()
exitSplitIfApplicable(wct, taskInfo)
if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
- moveHomeTask(wct, toTop = true, taskInfo.displayId)
+ moveHomeTask(taskInfo.displayId, wct)
} else {
- moveHomeTask(wct, toTop = true)
+ moveHomeTask(context.displayId, wct)
}
val taskIdToMinimize =
bringDesktopAppsToFrontBeforeShowingNewTask(taskInfo.displayId, wct, taskInfo.taskId)
@@ -780,7 +766,7 @@ class DesktopTasksController(
// We are moving a freeform task to fullscreen, put the home task under the fullscreen task.
if (!forceEnterDesktop(task.displayId)) {
- moveHomeTask(wct, toTop = true, task.displayId)
+ moveHomeTask(task.displayId, wct)
wct.reorder(task.token, /* onTop= */ true)
}
@@ -1433,33 +1419,36 @@ class DesktopTasksController(
?: WINDOWING_MODE_UNDEFINED
}
+ private fun prepareForDeskActivation(displayId: Int, wct: WindowContainerTransaction) {
+ // Move home to front, ensures that we go back home when all desktop windows are closed
+ val useParamDisplayId =
+ Flags.enableMultipleDesktopsBackend() ||
+ Flags.enablePerDisplayDesktopWallpaperActivity()
+ moveHomeTask(displayId = if (useParamDisplayId) displayId else context.displayId, wct = wct)
+ // Currently, we only handle the desktop on the default display really.
+ if (
+ (displayId == DEFAULT_DISPLAY || Flags.enablePerDisplayDesktopWallpaperActivity()) &&
+ ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ ) {
+ // Add translucent wallpaper activity to show the wallpaper underneath.
+ addWallpaperActivity(displayId, wct)
+ }
+ }
+
private fun bringDesktopAppsToFrontBeforeShowingNewTask(
displayId: Int,
wct: WindowContainerTransaction,
newTaskIdInFront: Int,
): Int? = bringDesktopAppsToFront(displayId, wct, newTaskIdInFront)
+ @Deprecated("Use activeDesk() instead.", ReplaceWith("activateDesk()"))
private fun bringDesktopAppsToFront(
displayId: Int,
wct: WindowContainerTransaction,
newTaskIdInFront: Int? = null,
): Int? {
logV("bringDesktopAppsToFront, newTaskId=%d", newTaskIdInFront)
- // Move home to front, ensures that we go back home when all desktop windows are closed
- if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
- moveHomeTask(wct, toTop = true, displayId)
- } else {
- moveHomeTask(wct, toTop = true)
- }
-
- // Currently, we only handle the desktop on the default display really.
- if (
- (displayId == DEFAULT_DISPLAY || Flags.enablePerDisplayDesktopWallpaperActivity()) &&
- ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
- ) {
- // Add translucent wallpaper activity to show the wallpaper underneath
- addWallpaperActivity(displayId, wct)
- }
+ prepareForDeskActivation(displayId, wct)
val expandedTasksOrderedFrontToBack = taskRepository.getExpandedTasksOrdered(displayId)
// If we're adding a new Task we might need to minimize an old one
@@ -1503,15 +1492,11 @@ class DesktopTasksController(
return taskIdToMinimize
}
- private fun moveHomeTask(
- wct: WindowContainerTransaction,
- toTop: Boolean,
- displayId: Int = DEFAULT_DISPLAY,
- ) {
+ private fun moveHomeTask(displayId: Int, wct: WindowContainerTransaction) {
shellTaskOrganizer
.getRunningTasks(displayId)
.firstOrNull { task -> task.activityType == ACTIVITY_TYPE_HOME }
- ?.let { homeTask -> wct.reorder(homeTask.getToken(), /* onTop= */ toTop) }
+ ?.let { homeTask -> wct.reorder(homeTask.getToken(), /* onTop= */ true) }
}
private fun addLaunchHomePendingIntent(wct: WindowContainerTransaction, displayId: Int) {
@@ -2389,6 +2374,57 @@ class DesktopTasksController(
)
}
+ private fun activateDefaultDeskInDisplay(
+ displayId: Int,
+ remoteTransition: RemoteTransition? = null,
+ ) {
+ val deskId =
+ checkNotNull(taskRepository.getDefaultDeskId(displayId)) {
+ "Expected a default desk to exist"
+ }
+ activateDesk(deskId, remoteTransition)
+ }
+
+ /** Activates the given desk. */
+ fun activateDesk(deskId: Int, remoteTransition: RemoteTransition? = null) {
+ val displayId = taskRepository.getDisplayForDesk(deskId)
+ val wct = WindowContainerTransaction()
+ if (Flags.enableMultipleDesktopsBackend()) {
+ prepareForDeskActivation(displayId, wct)
+ desksOrganizer.activateDesk(wct, deskId)
+ if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
+ // TODO: 362720497 - do non-running tasks need to be restarted with |wct#startTask|?
+ }
+ taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
+ doesAnyTaskRequireTaskbarRounding(displayId)
+ )
+ } else {
+ bringDesktopAppsToFront(displayId, wct)
+ }
+
+ val transitionType = transitionType(remoteTransition)
+ val handler =
+ remoteTransition?.let {
+ OneShotRemoteHandler(transitions.mainExecutor, remoteTransition)
+ }
+
+ val transition = transitions.startTransition(transitionType, wct, handler)
+ handler?.setTransition(transition)
+ if (Flags.enableMultipleDesktopsBackend()) {
+ desksTransitionObserver.addPendingTransition(
+ DeskTransition.ActivateDesk(
+ token = transition,
+ displayId = displayId,
+ deskId = deskId,
+ )
+ )
+ }
+
+ desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(
+ FREEFORM_ANIMATION_DURATION
+ )
+ }
+
/** Removes the default desk in the given display. */
@Deprecated("Deprecated with multi-desks.", ReplaceWith("removeDesk()"))
fun removeDefaultDeskInDisplay(displayId: Int) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DeskTransition.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DeskTransition.kt
index 47088c0b545a..4b658caf34ed 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DeskTransition.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DeskTransition.kt
@@ -30,4 +30,8 @@ sealed class DeskTransition {
val tasks: Set<Int>,
val onDeskRemovedListener: OnDeskRemovedListener?,
) : DeskTransition()
+
+ /** A transition to activate a desk in its display. */
+ data class ActivateDesk(override val token: IBinder, val displayId: Int, val deskId: Int) :
+ DeskTransition()
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt
index 5cbb59fbf323..547890a6200a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksOrganizer.kt
@@ -43,6 +43,9 @@ interface DesksOrganizer {
*/
fun getDeskAtEnd(change: TransitionInfo.Change): Int?
+ /** Whether the desk is activate according to the given change at the end of a transition. */
+ fun isDeskActiveAtEnd(change: TransitionInfo.Change, deskId: Int): Boolean
+
/** A callback that is invoked when the desk container is created. */
fun interface OnCreateCallback {
/** Calls back when the [deskId] has been created. */
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt
index 3e49b8a4538b..c235f204ece4 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserver.kt
@@ -25,7 +25,10 @@ import com.android.wm.shell.desktopmode.DesktopUserRepositories
* Observer of desk-related transitions, such as adding, removing or activating a whole desk. It
* tracks pending transitions and updates repository state once they finish.
*/
-class DesksTransitionObserver(private val desktopUserRepositories: DesktopUserRepositories) {
+class DesksTransitionObserver(
+ private val desktopUserRepositories: DesktopUserRepositories,
+ private val desksOrganizer: DesksOrganizer,
+) {
private val deskTransitions = mutableMapOf<IBinder, DeskTransition>()
/** Adds a pending desk transition to be tracked. */
@@ -53,6 +56,18 @@ class DesksTransitionObserver(private val desktopUserRepositories: DesktopUserRe
desktopRepository.removeDesk(deskTransition.deskId)
deskTransition.onDeskRemovedListener?.onDeskRemoved(displayId, deskId)
}
+ is DeskTransition.ActivateDesk -> {
+ val activeDeskChange =
+ info.changes.find { change ->
+ desksOrganizer.isDeskActiveAtEnd(change, deskTransition.deskId)
+ }
+ activeDeskChange?.let {
+ desktopRepository.setActiveDesk(
+ displayId = deskTransition.displayId,
+ deskId = deskTransition.deskId,
+ )
+ }
+ }
}
}
}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt
index 79c48c5e9594..65c0793aab51 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizer.kt
@@ -22,6 +22,7 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM
import android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED
import android.util.SparseArray
import android.view.SurfaceControl
+import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.TransitionInfo
import android.window.WindowContainerTransaction
import androidx.core.util.forEach
@@ -94,6 +95,11 @@ class RootTaskDesksOrganizer(
override fun getDeskAtEnd(change: TransitionInfo.Change): Int? =
change.taskInfo?.parentTaskId?.takeIf { it in roots }
+ override fun isDeskActiveAtEnd(change: TransitionInfo.Change, deskId: Int): Boolean =
+ change.taskInfo?.taskId == deskId &&
+ change.taskInfo?.isVisibleRequested == true &&
+ change.mode == TRANSIT_TO_FRONT
+
override fun onTaskAppeared(taskInfo: RunningTaskInfo, leash: SurfaceControl) {
if (taskInfo.parentTaskId in roots) {
val deskId = taskInfo.parentTaskId
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
index c10d2afbdc99..f5e45be96fc7 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksControllerTest.kt
@@ -66,6 +66,7 @@ import android.widget.Toast
import android.window.DisplayAreaInfo
import android.window.IWindowContainerToken
import android.window.RemoteTransition
+import android.window.TransitionInfo
import android.window.TransitionRequestInfo
import android.window.WindowContainerToken
import android.window.WindowContainerTransaction
@@ -519,7 +520,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @DisableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
fun showDesktopApps_allAppsInvisible_bringsToFront_desktopWallpaperDisabled() {
val homeTask = setUpHomeTask()
val task1 = setUpFreeformTask()
@@ -540,6 +544,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
fun showDesktopApps_allAppsInvisible_bringsToFront_desktopWallpaperEnabled() {
val task1 = setUpFreeformTask()
val task2 = setUpFreeformTask()
@@ -558,6 +563,29 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
+ fun showDesktopApps_deskInactive_bringsToFront_multipleDesksEnabled() {
+ whenever(transitions.startTransition(eq(TRANSIT_TO_FRONT), any(), anyOrNull()))
+ .thenReturn(Binder())
+ val deskId = 0
+ // Make desk inactive by activating another desk.
+ taskRepository.addDesk(DEFAULT_DISPLAY, deskId = 1)
+ taskRepository.setActiveDesk(DEFAULT_DISPLAY, deskId = 1)
+
+ controller.activateDesk(deskId, RemoteTransition(TestRemoteTransition()))
+
+ val wct =
+ getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
+ // Wallpaper is moved to front.
+ wct.assertPendingIntentAt(index = 0, desktopWallpaperIntent)
+ // Desk is activated.
+ verify(desksOrganizer).activateDesk(wct, deskId)
+ }
+
+ @Test
fun isDesktopModeShowing_noTasks_returnsFalse() {
assertThat(controller.isDesktopModeShowing(displayId = 0)).isFalse()
}
@@ -631,58 +659,83 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY,
)
- @DisableFlags(
- /** TODO: b/362720497 - re-enable when activation is implemented. */
- Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND
- )
- fun showDesktopApps_onSecondaryDisplay_desktopWallpaperEnabled_perDisplayWallpaperEnabled_shouldShowWallpaper() {
+ @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun showDesktopApps_onSecondaryDisplay_desktopWallpaperEnabled_perDisplayWallpaperEnabled_bringsTasksToFront() {
taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY)
- val homeTask = setUpHomeTask(SECOND_DISPLAY)
+ setUpHomeTask(SECOND_DISPLAY)
val task1 = setUpFreeformTask(SECOND_DISPLAY)
val task2 = setUpFreeformTask(SECOND_DISPLAY)
markTaskHidden(task1)
markTaskHidden(task2)
+ assertThat(taskRepository.getExpandedTasksOrdered(SECOND_DISPLAY)).contains(task1.taskId)
+ assertThat(taskRepository.getExpandedTasksOrdered(SECOND_DISPLAY)).contains(task2.taskId)
controller.showDesktopApps(SECOND_DISPLAY, RemoteTransition(TestRemoteTransition()))
val wct =
getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
- assertThat(wct.hierarchyOps).hasSize(4)
- // Expect order to be from bottom: home, wallpaperIntent, task1, task2
- wct.assertReorderAt(index = 0, homeTask)
- wct.assertPendingIntentAt(index = 1, desktopWallpaperIntent)
- wct.assertReorderAt(index = 2, task1)
- wct.assertReorderAt(index = 3, task2)
+ wct.assertReorder(task1)
+ wct.assertReorder(task2)
}
@Test
- @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
- @DisableFlags(
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY,
- /** TODO: b/362720497 - re-enable when activation is implemented. */
Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
)
+ fun showDesktopApps_onSecondaryDisplay_desktopWallpaperEnabled_perDisplayWallpaperEnabled_multipleDesksEnabled_bringsDeskToFront() {
+ whenever(transitions.startTransition(eq(TRANSIT_TO_FRONT), any(), anyOrNull()))
+ .thenReturn(Binder())
+ taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = 2)
+ setUpHomeTask(SECOND_DISPLAY)
+
+ controller.showDesktopApps(SECOND_DISPLAY, RemoteTransition(TestRemoteTransition()))
+
+ val wct =
+ getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
+ verify(desksOrganizer).activateDesk(wct, deskId = 2)
+ }
+
+ @Test
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY,
+ )
+ fun showDesktopApps_onSecondaryDisplay_desktopWallpaperEnabled_perDisplayWallpaperEnabled_shouldShowWallpaper() {
+ whenever(transitions.startTransition(eq(TRANSIT_TO_FRONT), any(), anyOrNull()))
+ .thenReturn(Binder())
+ taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY)
+ setUpHomeTask(SECOND_DISPLAY)
+
+ controller.showDesktopApps(SECOND_DISPLAY, RemoteTransition(TestRemoteTransition()))
+
+ val wct =
+ getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
+ wct.assertPendingIntent(desktopWallpaperIntent)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @DisableFlags(Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY)
fun showDesktopApps_onSecondaryDisplay_desktopWallpaperEnabled_shouldNotShowWallpaper() {
+ whenever(transitions.startTransition(eq(TRANSIT_TO_FRONT), any(), anyOrNull()))
+ .thenReturn(Binder())
taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY)
val homeTask = setUpHomeTask(SECOND_DISPLAY)
- val task1 = setUpFreeformTask(SECOND_DISPLAY)
- val task2 = setUpFreeformTask(SECOND_DISPLAY)
- markTaskHidden(task1)
- markTaskHidden(task2)
controller.showDesktopApps(SECOND_DISPLAY, RemoteTransition(TestRemoteTransition()))
val wct =
getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
- assertThat(wct.hierarchyOps).hasSize(3)
- // Expect order to be from bottom: home, task1, task2 (no wallpaper intent)
- wct.assertReorderAt(index = 0, homeTask)
- wct.assertReorderAt(index = 1, task1)
- wct.assertReorderAt(index = 2, task2)
+ wct.assertWithoutPendingIntent(desktopWallpaperIntent)
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @DisableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
fun showDesktopApps_appsAlreadyVisible_bringsToFront_desktopWallpaperDisabled() {
val homeTask = setUpHomeTask()
val task1 = setUpFreeformTask()
@@ -704,7 +757,6 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@DisableFlags(
Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
- /** TODO: b/362720497 - re-enable when activation is implemented. */
Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
)
fun showDesktopApps_onSecondaryDisplay_desktopWallpaperDisabled_shouldNotMoveLauncher() {
@@ -728,6 +780,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
fun showDesktopApps_appsAlreadyVisible_bringsToFront_desktopWallpaperEnabled() {
val task1 = setUpFreeformTask()
val task2 = setUpFreeformTask()
@@ -746,7 +799,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @DisableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
fun showDesktopApps_someAppsInvisible_reordersAll_desktopWallpaperDisabled() {
val homeTask = setUpHomeTask()
val task1 = setUpFreeformTask()
@@ -767,6 +823,7 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
fun showDesktopApps_someAppsInvisible_reordersAll_desktopWallpaperEnabled() {
val task1 = setUpFreeformTask()
val task2 = setUpFreeformTask()
@@ -785,7 +842,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @DisableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
fun showDesktopApps_noActiveTasks_reorderHomeToTop_desktopWallpaperDisabled() {
val homeTask = setUpHomeTask()
@@ -800,6 +860,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
fun showDesktopApps_noActiveTasks_addDesktopWallpaper_desktopWallpaperEnabled() {
+ whenever(transitions.startTransition(eq(TRANSIT_TO_FRONT), any(), anyOrNull()))
+ .thenReturn(Binder())
controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))
val wct =
@@ -808,7 +870,10 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @DisableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay_desktopWallpaperDisabled() {
taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY)
val homeTaskDefaultDisplay = setUpHomeTask(DEFAULT_DISPLAY)
@@ -831,6 +896,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplay_desktopWallpaperEnabled() {
+ whenever(transitions.startTransition(eq(TRANSIT_TO_FRONT), any(), anyOrNull()))
+ .thenReturn(Binder())
taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY)
val homeTaskDefaultDisplay = setUpHomeTask(DEFAULT_DISPLAY)
val taskDefaultDisplay = setUpFreeformTask(DEFAULT_DISPLAY)
@@ -843,17 +910,63 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
val wct =
getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
- assertThat(wct.hierarchyOps).hasSize(3)
// Move home to front
wct.assertReorderAt(index = 0, homeTaskDefaultDisplay)
// Add desktop wallpaper activity
wct.assertPendingIntentAt(index = 1, desktopWallpaperIntent)
+ }
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplayTasks_desktopWallpaperEnabled_multiDesksDisabled() {
+ whenever(transitions.startTransition(eq(TRANSIT_TO_FRONT), any(), anyOrNull()))
+ .thenReturn(Binder())
+ taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY)
+ val homeTaskDefaultDisplay = setUpHomeTask(DEFAULT_DISPLAY)
+ val taskDefaultDisplay = setUpFreeformTask(DEFAULT_DISPLAY)
+ setUpHomeTask(SECOND_DISPLAY)
+ val taskSecondDisplay = setUpFreeformTask(SECOND_DISPLAY)
+ markTaskHidden(taskDefaultDisplay)
+ markTaskHidden(taskSecondDisplay)
+
+ controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))
+
+ val wct =
+ getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
// Move freeform task to front
wct.assertReorderAt(index = 2, taskDefaultDisplay)
}
@Test
- @DisableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
+ fun showDesktopApps_twoDisplays_bringsToFrontOnlyOneDisplayTasks_desktopWallpaperEnabled_multiDesksEnabled() {
+ whenever(transitions.startTransition(eq(TRANSIT_TO_FRONT), any(), anyOrNull()))
+ .thenReturn(Binder())
+ taskRepository.addDesk(displayId = SECOND_DISPLAY, deskId = SECOND_DISPLAY)
+ val homeTaskDefaultDisplay = setUpHomeTask(DEFAULT_DISPLAY)
+ val taskDefaultDisplay = setUpFreeformTask(DEFAULT_DISPLAY)
+ setUpHomeTask(SECOND_DISPLAY)
+ val taskSecondDisplay = setUpFreeformTask(SECOND_DISPLAY)
+ markTaskHidden(taskDefaultDisplay)
+ markTaskHidden(taskSecondDisplay)
+
+ controller.showDesktopApps(DEFAULT_DISPLAY, RemoteTransition(TestRemoteTransition()))
+
+ val wct =
+ getLatestWct(type = TRANSIT_TO_FRONT, handlerClass = OneShotRemoteHandler::class.java)
+ // Move desktop tasks to front
+ verify(desksOrganizer).activateDesk(wct, deskId = DEFAULT_DISPLAY)
+ }
+
+ @Test
+ @DisableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
fun showDesktopApps_desktopWallpaperDisabled_dontReorderMinimizedTask() {
val homeTask = setUpHomeTask()
val freeformTask = setUpFreeformTask()
@@ -874,6 +987,8 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
@Test
@EnableFlags(Flags.FLAG_ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY)
+ /** TODO: b/362720497 - add multi-desk version when minimization is implemented. */
+ @DisableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
fun showDesktopApps_desktopWallpaperEnabled_dontReorderMinimizedTask() {
val homeTask = setUpHomeTask()
val freeformTask = setUpFreeformTask()
@@ -3641,6 +3756,34 @@ class DesktopTasksControllerTest(flags: FlagsParameterization) : ShellTestCase()
}
@Test
+ @EnableFlags(
+ Flags.FLAG_ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION,
+ Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND,
+ )
+ fun activateDesk_multipleDesks_addsPendingTransition() {
+ val deskId = 0
+ val transition = Binder()
+ val deskChange = mock(TransitionInfo.Change::class.java)
+ whenever(transitions.startTransition(eq(TRANSIT_TO_FRONT), any(), anyOrNull()))
+ .thenReturn(transition)
+ whenever(desksOrganizer.isDeskActiveAtEnd(deskChange, deskId)).thenReturn(true)
+ // Make desk inactive by activating another desk.
+ taskRepository.addDesk(DEFAULT_DISPLAY, deskId = 1)
+ taskRepository.setActiveDesk(DEFAULT_DISPLAY, deskId = 1)
+
+ controller.activateDesk(deskId, RemoteTransition(TestRemoteTransition()))
+
+ verify(desksTransitionsObserver)
+ .addPendingTransition(
+ argThat {
+ this is DeskTransition.ActivateDesk &&
+ this.token == transition &&
+ this.deskId == 0
+ }
+ )
+ }
+
+ @Test
@EnableFlags(Flags.FLAG_ENABLE_WINDOWING_DYNAMIC_INITIAL_BOUNDS)
fun dragToDesktop_landscapeDevice_resizable_undefinedOrientation_defaultLandscapeBounds() {
val spyController = spy(controller)
@@ -5617,6 +5760,29 @@ private fun WindowContainerTransaction.assertIndexInBounds(index: Int) {
.isGreaterThan(index)
}
+private fun WindowContainerTransaction.assertHop(
+ predicate: (WindowContainerTransaction.HierarchyOp) -> Boolean
+) {
+ assertThat(hierarchyOps.any(predicate)).isTrue()
+}
+
+private fun WindowContainerTransaction.assertWithoutHop(
+ predicate: (WindowContainerTransaction.HierarchyOp) -> Boolean
+) {
+ assertThat(hierarchyOps.none(predicate)).isTrue()
+}
+
+private fun WindowContainerTransaction.assertReorder(
+ task: RunningTaskInfo,
+ toTop: Boolean? = null,
+) {
+ assertHop { hop ->
+ hop.type == HIERARCHY_OP_TYPE_REORDER &&
+ (toTop == null || hop.toTop == toTop) &&
+ hop.container == task.token.asBinder()
+ }
+}
+
private fun WindowContainerTransaction.assertReorderAt(
index: Int,
task: RunningTaskInfo,
@@ -5678,6 +5844,20 @@ private fun WindowContainerTransaction.hasRemoveAt(index: Int, token: WindowCont
assertThat(op.container).isEqualTo(token.asBinder())
}
+private fun WindowContainerTransaction.assertPendingIntent(intent: Intent) {
+ assertHop { hop ->
+ hop.type == HIERARCHY_OP_TYPE_PENDING_INTENT &&
+ hop.pendingIntent?.intent?.component == intent.component
+ }
+}
+
+private fun WindowContainerTransaction.assertWithoutPendingIntent(intent: Intent) {
+ assertWithoutHop { hop ->
+ hop.type == HIERARCHY_OP_TYPE_PENDING_INTENT &&
+ hop.pendingIntent?.intent?.component == intent.component
+ }
+}
+
private fun WindowContainerTransaction.assertPendingIntentAt(index: Int, intent: Intent) {
assertIndexInBounds(index)
val op = hierarchyOps[index]
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt
index bfbaa84e9312..00c54c2ecc18 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/DesksTransitionObserverTest.kt
@@ -21,7 +21,9 @@ import android.platform.test.flag.junit.SetFlagsRule
import android.testing.AndroidTestingRunner
import android.view.Display.DEFAULT_DISPLAY
import android.view.WindowManager.TRANSIT_CLOSE
+import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.TransitionInfo
+import android.window.TransitionInfo.Change
import androidx.test.filters.SmallTest
import com.android.window.flags.Flags
import com.android.wm.shell.ShellTestCase
@@ -35,6 +37,7 @@ import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.kotlin.mock
+import org.mockito.kotlin.whenever
/**
* Tests for [DesksTransitionObserver].
@@ -47,6 +50,8 @@ class DesksTransitionObserverTest : ShellTestCase() {
@JvmField @Rule val setFlagsRule = SetFlagsRule()
+ private val mockDesksOrganizer = mock<DesksOrganizer>()
+
private lateinit var desktopUserRepositories: DesktopUserRepositories
private lateinit var observer: DesksTransitionObserver
@@ -65,7 +70,7 @@ class DesksTransitionObserverTest : ShellTestCase() {
/* mainCoroutineScope= */ mock(),
/* userManager= */ mock(),
)
- observer = DesksTransitionObserver(desktopUserRepositories)
+ observer = DesksTransitionObserver(desktopUserRepositories, mockDesksOrganizer)
}
@Test
@@ -121,4 +126,23 @@ class DesksTransitionObserverTest : ShellTestCase() {
assertThat(removeListener.lastDeskRemoved).isEqualTo(5)
}
+
+ @Test
+ @EnableFlags(Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
+ fun onTransitionReady_activateDesk_updatesRepository() {
+ val transition = Binder()
+ val change = Change(mock(), mock())
+ whenever(mockDesksOrganizer.isDeskActiveAtEnd(change, deskId = 5)).thenReturn(true)
+ val activateTransition =
+ DeskTransition.ActivateDesk(transition, displayId = DEFAULT_DISPLAY, deskId = 5)
+ repository.addDesk(DEFAULT_DISPLAY, deskId = 5)
+
+ observer.addPendingTransition(activateTransition)
+ observer.onTransitionReady(
+ transition = transition,
+ info = TransitionInfo(TRANSIT_TO_FRONT, /* flags= */ 0).apply { addChange(change) },
+ )
+
+ assertThat(repository.getActiveDeskId(DEFAULT_DISPLAY)).isEqualTo(5)
+ }
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt
index a07203d86b75..fbc78b21353e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/multidesks/RootTaskDesksOrganizerTest.kt
@@ -18,6 +18,7 @@ package com.android.wm.shell.desktopmode.multidesks
import android.testing.AndroidTestingRunner
import android.view.Display
import android.view.SurfaceControl
+import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.TransitionInfo
import android.window.WindowContainerTransaction
import android.window.WindowContainerTransaction.HierarchyOp
@@ -244,6 +245,26 @@ class RootTaskDesksOrganizerTest : ShellTestCase() {
assertThat(endDesk).isEqualTo(freeformRoot.taskId)
}
+ @Test
+ fun testIsDeskActiveAtEnd() {
+ organizer.createDesk(Display.DEFAULT_DISPLAY, FakeOnCreateCallback())
+ val freeformRoot = createFreeformTask().apply { parentTaskId = -1 }
+ freeformRoot.isVisibleRequested = true
+ organizer.onTaskAppeared(freeformRoot, SurfaceControl())
+
+ val isActive =
+ organizer.isDeskActiveAtEnd(
+ change =
+ TransitionInfo.Change(freeformRoot.token, SurfaceControl()).apply {
+ taskInfo = freeformRoot
+ mode = TRANSIT_TO_FRONT
+ },
+ deskId = freeformRoot.taskId,
+ )
+
+ assertThat(isActive).isTrue()
+ }
+
private class FakeOnCreateCallback : DesksOrganizer.OnCreateCallback {
var deskId: Int? = null
val created: Boolean