summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt55
-rw-r--r--libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt75
2 files changed, 116 insertions, 14 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
index e086e40fb21c..da9c8a2bdf21 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserver.kt
@@ -21,6 +21,7 @@ import android.content.Context
import android.os.IBinder
import android.view.SurfaceControl
import android.view.WindowManager
+import android.view.WindowManager.TRANSIT_CLOSE
import android.view.WindowManager.TRANSIT_TO_BACK
import android.window.TransitionInfo
import android.window.WindowContainerTransaction
@@ -36,8 +37,8 @@ import com.android.wm.shell.transition.Transitions
/**
* A [Transitions.TransitionObserver] that observes shell transitions and updates the
- * [DesktopRepository] state TODO: b/332682201 This observes transitions related to desktop
- * mode and other transitions that originate both within and outside shell.
+ * [DesktopRepository] state TODO: b/332682201 This observes transitions related to desktop mode and
+ * other transitions that originate both within and outside shell.
*/
class DesktopTasksTransitionObserver(
private val context: Context,
@@ -47,6 +48,8 @@ class DesktopTasksTransitionObserver(
shellInit: ShellInit
) : Transitions.TransitionObserver {
+ private var transitionToCloseWallpaper: IBinder? = null
+
init {
if (
Transitions.ENABLE_SHELL_TRANSITIONS && DesktopModeStatus.canEnterDesktopMode(context)
@@ -72,6 +75,7 @@ class DesktopTasksTransitionObserver(
handleBackNavigation(info)
removeTaskIfNeeded(info)
}
+ removeWallpaperOnLastTaskClosingIfNeeded(transition, info)
}
private fun removeTaskIfNeeded(info: TransitionInfo) {
@@ -83,13 +87,9 @@ class DesktopTasksTransitionObserver(
val taskInfo = change.taskInfo
if (taskInfo == null || taskInfo.taskId == -1) continue
- if (desktopRepository.isActiveTask(taskInfo.taskId)
- && taskInfo.windowingMode != WINDOWING_MODE_FREEFORM
- ) {
- desktopRepository.removeFreeformTask(
- taskInfo.displayId,
- taskInfo.taskId
- )
+ if (desktopRepository.isActiveTask(taskInfo.taskId) &&
+ taskInfo.windowingMode != WINDOWING_MODE_FREEFORM) {
+ desktopRepository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId)
}
}
}
@@ -106,14 +106,32 @@ class DesktopTasksTransitionObserver(
if (desktopRepository.getVisibleTaskCount(taskInfo.displayId) > 0 &&
change.mode == TRANSIT_TO_BACK &&
- taskInfo.windowingMode == WINDOWING_MODE_FREEFORM
- ) {
+ taskInfo.windowingMode == WINDOWING_MODE_FREEFORM) {
desktopRepository.minimizeTask(taskInfo.displayId, taskInfo.taskId)
}
}
}
}
+ private fun removeWallpaperOnLastTaskClosingIfNeeded(
+ transition: IBinder,
+ info: TransitionInfo
+ ) {
+ for (change in info.changes) {
+ val taskInfo = change.taskInfo
+ if (taskInfo == null || taskInfo.taskId == -1) {
+ continue
+ }
+
+ if (desktopRepository.getVisibleTaskCount(taskInfo.displayId) == 1 &&
+ change.mode == TRANSIT_CLOSE &&
+ taskInfo.windowingMode == WINDOWING_MODE_FREEFORM &&
+ desktopRepository.wallpaperActivityToken != null) {
+ transitionToCloseWallpaper = transition
+ }
+ }
+ }
+
override fun onTransitionStarting(transition: IBinder) {
// TODO: b/332682201 Update repository state
}
@@ -124,6 +142,16 @@ class DesktopTasksTransitionObserver(
override fun onTransitionFinished(transition: IBinder, aborted: Boolean) {
// TODO: b/332682201 Update repository state
+ if (transitionToCloseWallpaper == transition) {
+ // TODO: b/362469671 - Handle merging the animation when desktop is also closing.
+ desktopRepository.wallpaperActivityToken?.let { wallpaperActivityToken ->
+ transitions.startTransition(
+ TRANSIT_CLOSE,
+ WindowContainerTransaction().removeTask(wallpaperActivityToken),
+ null)
+ }
+ transitionToCloseWallpaper = null
+ }
}
private fun updateWallpaperToken(info: TransitionInfo) {
@@ -141,10 +169,9 @@ class DesktopTasksTransitionObserver(
// task.
shellTaskOrganizer.applyTransaction(
WindowContainerTransaction()
- .setTaskTrimmableFromRecents(taskInfo.token, false)
- )
+ .setTaskTrimmableFromRecents(taskInfo.token, false))
}
- WindowManager.TRANSIT_CLOSE ->
+ TRANSIT_CLOSE ->
desktopRepository.wallpaperActivityToken = null
else -> {}
}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
index 598df34a310d..fe87aa88a8db 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/desktopmode/DesktopTasksTransitionObserverTest.kt
@@ -22,26 +22,38 @@ import android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN
import android.content.ComponentName
import android.content.Context
import android.content.Intent
+import android.os.IBinder
import android.platform.test.annotations.EnableFlags
import android.view.Display.DEFAULT_DISPLAY
+import android.view.WindowManager
+import android.view.WindowManager.TRANSIT_CLOSE
import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_BACK
import android.window.IWindowContainerToken
import android.window.TransitionInfo
import android.window.TransitionInfo.Change
import android.window.WindowContainerToken
+import android.window.WindowContainerTransaction
+import android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_REMOVE_TASK
import com.android.modules.utils.testing.ExtendedMockitoRule
import com.android.window.flags.Flags
+import com.android.wm.shell.MockToken
import com.android.wm.shell.ShellTaskOrganizer
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.shared.desktopmode.DesktopModeStatus
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
+import com.google.common.truth.Truth.assertThat
+import com.google.common.truth.Truth.assertWithMessage
import org.junit.Before
import org.junit.Rule
import org.junit.Test
+import org.mockito.ArgumentCaptor
+import org.mockito.ArgumentMatchers.eq
+import org.mockito.ArgumentMatchers.isA
import org.mockito.Mockito
import org.mockito.kotlin.any
+import org.mockito.kotlin.isNull
import org.mockito.kotlin.mock
import org.mockito.kotlin.never
import org.mockito.kotlin.spy
@@ -130,6 +142,27 @@ class DesktopTasksTransitionObserverTest {
verify(taskRepository).removeFreeformTask(task.displayId, task.taskId)
}
+ @Test
+ fun closeLastTask_wallpaperTokenExists_wallpaperIsRemoved() {
+ val mockTransition = Mockito.mock(IBinder::class.java)
+ val task = createTaskInfo(1, WINDOWING_MODE_FREEFORM)
+ val wallpaperToken = MockToken().token()
+ whenever(taskRepository.getVisibleTaskCount(task.displayId)).thenReturn(1)
+ whenever(taskRepository.wallpaperActivityToken).thenReturn(wallpaperToken)
+
+ transitionObserver.onTransitionReady(
+ transition = mockTransition,
+ info = createCloseTransition(task),
+ startTransaction = mock(),
+ finishTransaction = mock(),
+ )
+ transitionObserver.onTransitionFinished(mockTransition, false)
+
+ val wct = getLatestWct(type = TRANSIT_CLOSE)
+ assertThat(wct.hierarchyOps).hasSize(1)
+ wct.assertRemoveAt(index = 0, wallpaperToken)
+ }
+
private fun createBackNavigationTransition(
task: RunningTaskInfo?
): TransitionInfo {
@@ -160,6 +193,48 @@ class DesktopTasksTransitionObserverTest {
}
}
+ private fun createCloseTransition(
+ task: RunningTaskInfo?
+ ): TransitionInfo {
+ return TransitionInfo(TRANSIT_CLOSE, 0 /* flags */).apply {
+ addChange(
+ Change(mock(), mock()).apply {
+ mode = TRANSIT_CLOSE
+ parent = null
+ taskInfo = task
+ flags = flags
+ }
+ )
+ }
+ }
+
+ private fun getLatestWct(
+ @WindowManager.TransitionType type: Int = TRANSIT_OPEN,
+ handlerClass: Class<out Transitions.TransitionHandler>? = null
+ ): WindowContainerTransaction {
+ val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
+ if (handlerClass == null) {
+ Mockito.verify(transitions).startTransition(eq(type), arg.capture(), isNull())
+ } else {
+ Mockito.verify(transitions)
+ .startTransition(eq(type), arg.capture(), isA(handlerClass))
+ }
+ return arg.value
+ }
+
+ private fun WindowContainerTransaction.assertRemoveAt(index: Int, token: WindowContainerToken) {
+ assertIndexInBounds(index)
+ val op = hierarchyOps[index]
+ assertThat(op.type).isEqualTo(HIERARCHY_OP_TYPE_REMOVE_TASK)
+ assertThat(op.container).isEqualTo(token.asBinder())
+ }
+
+ private fun WindowContainerTransaction.assertIndexInBounds(index: Int) {
+ assertWithMessage("WCT does not have a hierarchy operation at index $index")
+ .that(hierarchyOps.size)
+ .isGreaterThan(index)
+ }
+
private fun createTaskInfo(id: Int, windowingMode: Int = WINDOWING_MODE_FREEFORM) =
RunningTaskInfo().apply {
taskId = id