Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4f2a93a4 authored by Daichi Hirono's avatar Daichi Hirono
Browse files

Fix the condition for removing desktop wallpaper

This change fixes a condition that led to an ANR error when a task was
moved from the default display to another.

Previously, DesktopWallpaperActivity was removed when the last desktop
task was removed (e.g. the task closed or left desktop mode). However,
if other desktop tasks remained on a different display,
DesktopWallpaperActivity remained on the default display. In this case,
DesktopWallpaperActivity became the topmost task on the default display,
and the system server attempted to give it focus. Because
DesktopWallpaperActivity is not focusable, the system server could not
find a focusable window, eventually causing an ANR.

This commit corrects the condition for removing the desktop wallpaper.
Now, DesktopWallpaperActivity is removed when the last desktop task on
the default display is removed.

Bug: 381361395
Test: DesktopTasksControllerTest#moveToNextDisplay_removeWallpaper
Flag: com.android.window.flags.enable_per_display_desktop_wallpaper_activity
Change-Id: I7f142b3cc4282109c716e80b65f8b9e2cc343787
parent 3ffdc22a
Loading
Loading
Loading
Loading
+9 −2
Original line number Diff line number Diff line
@@ -220,11 +220,18 @@ class DesktopRepository(
    fun isMinimizedTask(taskId: Int) = desktopTaskDataSequence().any { taskId in it.minimizedTasks }

    /** Checks if a task is the only visible, non-closing, non-minimized task on its display. */
    fun isOnlyVisibleNonClosingTask(taskId: Int): Boolean =
        desktopTaskDataSequence().any {
    fun isOnlyVisibleNonClosingTask(taskId: Int, displayId: Int = INVALID_DISPLAY): Boolean {
        val seq =
            if (displayId != INVALID_DISPLAY) {
                sequenceOf(desktopTaskDataByDisplayId[displayId]).filterNotNull()
            } else {
                desktopTaskDataSequence()
            }
        return seq.any {
            it.visibleTasks.subtract(it.closingTasks).subtract(it.minimizedTasks).singleOrNull() ==
                taskId
        }
    }

    fun getActiveTasks(displayId: Int): ArraySet<Int> =
        ArraySet(desktopTaskDataByDisplayId[displayId]?.activeTasks)
+25 −8
Original line number Diff line number Diff line
@@ -571,7 +571,7 @@ class DesktopTasksController(
    ): ((IBinder) -> Unit)? {
        val taskId = taskInfo.taskId
        desktopTilingDecorViewModel.removeTaskIfTiled(displayId, taskId)
        performDesktopExitCleanupIfNeeded(taskId, wct)
        performDesktopExitCleanupIfNeeded(taskId, displayId, wct)
        taskRepository.addClosingTask(displayId, taskId)
        taskbarDesktopTaskListener?.onTaskbarCornerRoundingUpdate(
            doesAnyTaskRequireTaskbarRounding(displayId, taskId)
@@ -610,7 +610,7 @@ class DesktopTasksController(
        val taskId = taskInfo.taskId
        val displayId = taskInfo.displayId
        val wct = WindowContainerTransaction()
        performDesktopExitCleanupIfNeeded(taskId, wct)
        performDesktopExitCleanupIfNeeded(taskId, displayId, wct)
        // Notify immersive handler as it might need to exit immersive state.
        val exitResult =
            desktopImmersiveController.exitImmersiveIfApplicable(
@@ -864,6 +864,10 @@ class DesktopTasksController(
        if (!task.isFreeform) addMoveToDesktopChanges(wct, task, displayId)
        wct.reparent(task.token, displayAreaInfo.token, true /* onTop */)

        if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
            performDesktopExitCleanupIfNeeded(task.taskId, task.displayId, wct)
        }

        transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
    }

@@ -1348,10 +1352,23 @@ class DesktopTasksController(
     * Remove wallpaper activity if task provided is last task and wallpaper activity token is not
     * null
     */
    private fun performDesktopExitCleanupIfNeeded(taskId: Int, wct: WindowContainerTransaction) {
    private fun performDesktopExitCleanupIfNeeded(
        taskId: Int,
        displayId: Int,
        wct: WindowContainerTransaction,
    ) {
        if (Flags.enablePerDisplayDesktopWallpaperActivity()) {
            if (!taskRepository.isOnlyVisibleNonClosingTask(taskId, displayId)) {
                return
            }
            if (displayId != DEFAULT_DISPLAY) {
                return
            }
        } else {
            if (!taskRepository.isOnlyVisibleNonClosingTask(taskId)) {
                return
            }
        }
        desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(
            FULLSCREEN_ANIMATION_DURATION
        )
@@ -1844,7 +1861,7 @@ class DesktopTasksController(
        if (!isDesktopModeShowing(task.displayId)) return null

        val wct = WindowContainerTransaction()
        performDesktopExitCleanupIfNeeded(task.taskId, wct)
        performDesktopExitCleanupIfNeeded(task.taskId, task.displayId, wct)

        if (!DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_BACK_NAVIGATION.isTrue()) {
            taskRepository.addClosingTask(task.displayId, task.taskId)
@@ -1927,7 +1944,7 @@ class DesktopTasksController(
            wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())
        }

        performDesktopExitCleanupIfNeeded(taskInfo.taskId, wct)
        performDesktopExitCleanupIfNeeded(taskInfo.taskId, taskInfo.displayId, wct)
    }

    private fun cascadeWindow(bounds: Rect, displayLayout: DisplayLayout, displayId: Int) {
@@ -1961,7 +1978,7 @@ class DesktopTasksController(
        // want it overridden in multi-window.
        wct.setDensityDpi(taskInfo.token, getDefaultDensityDpi())

        performDesktopExitCleanupIfNeeded(taskInfo.taskId, wct)
        performDesktopExitCleanupIfNeeded(taskInfo.taskId, taskInfo.displayId, wct)
    }

    /** Returns the ID of the Task that will be minimized, or null if no task will be minimized. */
+25 −0
Original line number Diff line number Diff line
@@ -81,6 +81,7 @@ import com.android.dx.mockito.inline.extended.ExtendedMockito.never
import com.android.dx.mockito.inline.extended.StaticMockitoSession
import com.android.internal.jank.InteractionJankMonitor
import com.android.window.flags.Flags
import com.android.window.flags.Flags.FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY
import com.android.window.flags.Flags.FLAG_ENABLE_DESKTOP_WINDOWING_MODE
import com.android.window.flags.Flags.FLAG_ENABLE_FULLY_IMMERSIVE_IN_DESKTOP
import com.android.wm.shell.MockToken
@@ -1624,6 +1625,30 @@ class DesktopTasksControllerTest : ShellTestCase() {
    }
  }

  @Test
  @EnableFlags(FLAG_ENABLE_PER_DISPLAY_DESKTOP_WALLPAPER_ACTIVITY)
  fun moveToNextDisplay_removeWallpaper() {
    // Set up two display ids
    whenever(rootTaskDisplayAreaOrganizer.displayIds)
      .thenReturn(intArrayOf(DEFAULT_DISPLAY, SECOND_DISPLAY))
    // Create a mock for the target display area: second display
    val secondDisplayArea = DisplayAreaInfo(MockToken().token(), SECOND_DISPLAY, 0)
    whenever(rootTaskDisplayAreaOrganizer.getDisplayAreaInfo(SECOND_DISPLAY))
      .thenReturn(secondDisplayArea)
    // Add a task and a wallpaper
    val task = setUpFreeformTask(displayId = DEFAULT_DISPLAY)
    val wallpaperToken = MockToken().token()
    taskRepository.wallpaperActivityToken = wallpaperToken

    controller.moveToNextDisplay(task.taskId)

    with(getLatestWct(type = TRANSIT_CHANGE)) {
      val wallpaperChange = hierarchyOps.find { op -> op.container == wallpaperToken.asBinder() }
      assertThat(wallpaperChange).isNotNull()
      assertThat(wallpaperChange!!.type).isEqualTo(HIERARCHY_OP_TYPE_REMOVE_TASK)
    }
  }

  @Test
  fun getTaskWindowingMode() {
    val fullscreenTask = setUpFullscreenTask()