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

Commit 79768e01 authored by Ivan Tkachenko's avatar Ivan Tkachenko Committed by Android (Google) Code Review
Browse files

Merge "Fix empty desktop mode after closing the last window (part 2)" into main

parents 2af3c050 a67e1528
Loading
Loading
Loading
Loading
+5 −6
Original line number Diff line number Diff line
@@ -234,17 +234,16 @@ class DesktopModeTaskRepository {
    }

    /**
     * Check if a task with the given [taskId] is the only active, non-closing, not-minimized task
     * Check if a task with the given [taskId] is the only visible, non-closing, not-minimized task
     * on its display
     */
    fun isOnlyActiveNonClosingTask(taskId: Int): Boolean {
        return displayData.valueIterator().asSequence().any { data ->
            data.activeTasks
    fun isOnlyVisibleNonClosingTask(taskId: Int): Boolean =
        displayData.valueIterator().asSequence().any { data ->
            data.visibleTasks
                .subtract(data.closingTasks)
                .subtract(data.minimizedTasks)
                .singleOrNull() == taskId
        }
    }

    /** Get a set of the active tasks for given [displayId] */
    fun getActiveTasks(displayId: Int): ArraySet<Int> {
+12 −10
Original line number Diff line number Diff line
@@ -40,7 +40,6 @@ import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_NONE
import android.view.WindowManager.TRANSIT_OPEN
import android.view.WindowManager.TRANSIT_TO_BACK
import android.view.WindowManager.TRANSIT_TO_FRONT
import android.window.RemoteTransition
import android.window.TransitionInfo
@@ -76,6 +75,7 @@ import com.android.wm.shell.recents.RecentsTransitionStateListener
import com.android.wm.shell.shared.DesktopModeStatus
import com.android.wm.shell.shared.DesktopModeStatus.DESKTOP_DENSITY_OVERRIDE
import com.android.wm.shell.shared.DesktopModeStatus.useDesktopOverrideDensity
import com.android.wm.shell.shared.TransitionUtil
import com.android.wm.shell.shared.annotations.ExternalThread
import com.android.wm.shell.shared.annotations.ShellMainThread
import com.android.wm.shell.splitscreen.SplitScreenController
@@ -446,7 +446,7 @@ class DesktopTasksController(
     * @param taskId task id of the window that's being closed
     */
    fun onDesktopWindowClose(wct: WindowContainerTransaction, displayId: Int, taskId: Int) {
        if (desktopModeTaskRepository.isOnlyActiveNonClosingTask(taskId)) {
        if (desktopModeTaskRepository.isOnlyVisibleNonClosingTask(taskId)) {
            removeWallpaperActivity(wct)
        }
        if (!desktopModeTaskRepository.addClosingTask(displayId, taskId)) {
@@ -879,8 +879,8 @@ class DesktopTasksController(
                    reason = "recents animation is running"
                    false
                }
                // Handle back navigation for the last window if wallpaper available
                shouldHandleBackNavigation(request) -> true
                // Handle task closing for the last window if wallpaper is available
                shouldHandleTaskClosing(request) -> true
                // Only handle open or to front transitions
                request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> {
                    reason = "transition type not handled (${request.type})"
@@ -918,7 +918,8 @@ class DesktopTasksController(
        val result =
            triggerTask?.let { task ->
                when {
                    request.type == TRANSIT_TO_BACK -> handleBackNavigation(task)
                    // Check if the closing task needs to be handled
                    TransitionUtil.isClosingType(request.type) -> handleTaskClosing(task)
                    // Check if the task has a top transparent activity
                    shouldLaunchAsModal(task) -> handleIncompatibleTaskLaunch(task)
                    // Check if the task has a top systemUI activity
@@ -960,9 +961,10 @@ class DesktopTasksController(
    private fun shouldLaunchAsModal(task: TaskInfo) =
        Flags.enableDesktopWindowingModalsPolicy() && isSingleTopActivityTranslucent(task)

    private fun shouldHandleBackNavigation(request: TransitionRequestInfo): Boolean {
    private fun shouldHandleTaskClosing(request: TransitionRequestInfo): Boolean {
        return Flags.enableDesktopWindowingWallpaperActivity() &&
            request.type == TRANSIT_TO_BACK
            TransitionUtil.isClosingType(request.type) &&
            request.triggerTask != null
    }

    private fun handleFreeformTaskLaunch(
@@ -1029,10 +1031,10 @@ class DesktopTasksController(
        return WindowContainerTransaction().also { wct -> addMoveToFullscreenChanges(wct, task) }
    }

    /** Handle back navigation by removing wallpaper activity if it's the last active task */
    private fun handleBackNavigation(task: RunningTaskInfo): WindowContainerTransaction? {
    /** Handle task closing by removing wallpaper activity if it's the last active task */
    private fun handleTaskClosing(task: RunningTaskInfo): WindowContainerTransaction? {
        val wct = if (
            desktopModeTaskRepository.isOnlyActiveNonClosingTask(task.taskId) &&
            desktopModeTaskRepository.isOnlyVisibleNonClosingTask(task.taskId) &&
                desktopModeTaskRepository.wallpaperActivityToken != null
        ) {
            // Remove wallpaper activity when the last active task is removed
+0 −4
Original line number Diff line number Diff line
@@ -122,10 +122,6 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
            mDesktopModeTaskRepository.ifPresent(repository -> {
                repository.removeFreeformTask(taskInfo.displayId, taskInfo.taskId);
                repository.unminimizeTask(taskInfo.displayId, taskInfo.taskId);
                if (repository.removeClosingTask(taskInfo.taskId)) {
                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                            "Removing closing freeform task: #%d", taskInfo.taskId);
                }
                if (repository.removeActiveTask(taskInfo.taskId)) {
                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                            "Removing active freeform task: #%d", taskInfo.taskId);
+1 −0
Original line number Diff line number Diff line
@@ -46,6 +46,7 @@ android_test {
        "androidx.dynamicanimation_dynamicanimation",
        "dagger2",
        "frameworks-base-testutils",
        "kotlin-test",
        "kotlinx-coroutines-android",
        "kotlinx-coroutines-core",
        "mockito-kotlin2",
+56 −51
Original line number Diff line number Diff line
@@ -119,86 +119,91 @@ class DesktopModeTaskRepositoryTest : ShellTestCase() {
    }

    @Test
    fun isOnlyActiveNonClosingTask_noActiveNonClosingTasks() {
        // Not an active task
        assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse()
    fun isOnlyVisibleNonClosingTask_noTasks() {
        // No visible tasks
        assertThat(repo.isOnlyVisibleNonClosingTask(1)).isFalse()
        assertThat(repo.isClosingTask(1)).isFalse()
    }

    @Test
    fun isOnlyActiveNonClosingTask_singleActiveNonClosingTask() {
        repo.addActiveTask(DEFAULT_DISPLAY, 1)
        // The only active task
        assertThat(repo.isActiveTask(1)).isTrue()
    fun isOnlyVisibleNonClosingTask_singleVisibleNonClosingTask() {
        repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)

        // The only visible task
        assertThat(repo.isVisibleTask(1)).isTrue()
        assertThat(repo.isClosingTask(1)).isFalse()
        assertThat(repo.isOnlyActiveNonClosingTask(1)).isTrue()
        // Not an active task
        assertThat(repo.isActiveTask(99)).isFalse()
        assertThat(repo.isOnlyVisibleNonClosingTask(1)).isTrue()
        // Not a visible task
        assertThat(repo.isVisibleTask(99)).isFalse()
        assertThat(repo.isClosingTask(99)).isFalse()
        assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse()
        assertThat(repo.isOnlyVisibleNonClosingTask(99)).isFalse()
    }

    @Test
    fun isOnlyActiveNonClosingTask_singleActiveClosingTask() {
        repo.addActiveTask(DEFAULT_DISPLAY, 1)
    fun isOnlyVisibleNonClosingTask_singleVisibleClosingTask() {
        repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
        repo.addClosingTask(DEFAULT_DISPLAY, 1)
        // The active task that's closing
        assertThat(repo.isActiveTask(1)).isTrue()

        // A visible task that's closing
        assertThat(repo.isVisibleTask(1)).isTrue()
        assertThat(repo.isClosingTask(1)).isTrue()
        assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse()
        // Not an active task
        assertThat(repo.isActiveTask(99)).isFalse()
        assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse()
        assertThat(repo.isOnlyVisibleNonClosingTask(1)).isFalse()
        // Not a visible task
        assertThat(repo.isVisibleTask(99)).isFalse()
        assertThat(repo.isOnlyVisibleNonClosingTask(99)).isFalse()
    }

    @Test
    fun isOnlyActiveNonClosingTask_singleActiveMinimizedTask() {
        repo.addActiveTask(DEFAULT_DISPLAY, 1)
    fun isOnlyVisibleNonClosingTask_singleVisibleMinimizedTask() {
        repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
        repo.minimizeTask(DEFAULT_DISPLAY, 1)
        // The active task that's closing
        assertThat(repo.isActiveTask(1)).isTrue()

        // The visible task that's closing
        assertThat(repo.isVisibleTask(1)).isTrue()
        assertThat(repo.isMinimizedTask(1)).isTrue()
        assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse()
        // Not an active task
        assertThat(repo.isActiveTask(99)).isFalse()
        assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse()
        assertThat(repo.isOnlyVisibleNonClosingTask(1)).isFalse()
        // Not a visible task
        assertThat(repo.isVisibleTask(99)).isFalse()
        assertThat(repo.isOnlyVisibleNonClosingTask(99)).isFalse()
    }

    @Test
    fun isOnlyActiveNonClosingTask_multipleActiveNonClosingTasks() {
        repo.addActiveTask(DEFAULT_DISPLAY, 1)
        repo.addActiveTask(DEFAULT_DISPLAY, 2)
    fun isOnlyVisibleNonClosingTask_multipleVisibleNonClosingTasks() {
        repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
        repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true)

        // Not the only task
        assertThat(repo.isActiveTask(1)).isTrue()
        assertThat(repo.isVisibleTask(1)).isTrue()
        assertThat(repo.isClosingTask(1)).isFalse()
        assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse()
        assertThat(repo.isOnlyVisibleNonClosingTask(1)).isFalse()
        // Not the only task
        assertThat(repo.isActiveTask(2)).isTrue()
        assertThat(repo.isVisibleTask(2)).isTrue()
        assertThat(repo.isClosingTask(2)).isFalse()
        assertThat(repo.isOnlyActiveNonClosingTask(2)).isFalse()
        // Not an active task
        assertThat(repo.isActiveTask(99)).isFalse()
        assertThat(repo.isOnlyVisibleNonClosingTask(2)).isFalse()
        // Not a visible task
        assertThat(repo.isVisibleTask(99)).isFalse()
        assertThat(repo.isClosingTask(99)).isFalse()
        assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse()
        assertThat(repo.isOnlyVisibleNonClosingTask(99)).isFalse()
    }

    @Test
    fun isOnlyActiveNonClosingTask_multipleDisplays() {
        repo.addActiveTask(DEFAULT_DISPLAY, 1)
        repo.addActiveTask(DEFAULT_DISPLAY, 2)
        repo.addActiveTask(SECOND_DISPLAY, 3)
    fun isOnlyVisibleNonClosingTask_multipleDisplays() {
        repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 1, visible = true)
        repo.updateVisibleFreeformTasks(DEFAULT_DISPLAY, taskId = 2, visible = true)
        repo.updateVisibleFreeformTasks(SECOND_DISPLAY, taskId = 3, visible = true)

        // Not the only task on DEFAULT_DISPLAY
        assertThat(repo.isActiveTask(1)).isTrue()
        assertThat(repo.isOnlyActiveNonClosingTask(1)).isFalse()
        assertThat(repo.isVisibleTask(1)).isTrue()
        assertThat(repo.isOnlyVisibleNonClosingTask(1)).isFalse()
        // Not the only task on DEFAULT_DISPLAY
        assertThat(repo.isActiveTask(2)).isTrue()
        assertThat(repo.isOnlyActiveNonClosingTask(2)).isFalse()
        // The only active task on SECOND_DISPLAY
        assertThat(repo.isActiveTask(3)).isTrue()
        assertThat(repo.isOnlyActiveNonClosingTask(3)).isTrue()
        // Not an active task
        assertThat(repo.isActiveTask(99)).isFalse()
        assertThat(repo.isOnlyActiveNonClosingTask(99)).isFalse()
        assertThat(repo.isVisibleTask(2)).isTrue()
        assertThat(repo.isOnlyVisibleNonClosingTask(2)).isFalse()
        // The only visible task on SECOND_DISPLAY
        assertThat(repo.isVisibleTask(3)).isTrue()
        assertThat(repo.isOnlyVisibleNonClosingTask(3)).isTrue()
        // Not a visible task
        assertThat(repo.isVisibleTask(99)).isFalse()
        assertThat(repo.isOnlyVisibleNonClosingTask(99)).isFalse()
    }

    @Test
Loading