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

Commit 5e95d262 authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes I9335b8cf,I25ed13aa into main

* changes:
  [13/N] Desks: Implement move to fullscreen from a desk
  [12/N] Desks: Move multi-desks backend flag usages to dev option
parents 70c77dcf 71d5260b
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -27,6 +27,7 @@ import android.hardware.display.DisplayManager;
import android.os.SystemProperties;
import android.view.Display;
import android.view.WindowManager;
import android.window.DesktopExperienceFlags;
import android.window.DesktopModeFlags;

import com.android.internal.R;
@@ -271,7 +272,7 @@ public class DesktopModeStatus {
     * frontend implementations).
     */
    public static boolean enableMultipleDesktops(@NonNull Context context) {
        return Flags.enableMultipleDesktopsBackend()
        return DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()
                && Flags.enableMultipleDesktopsFrontend()
                && canEnterDesktopMode(context);
    }
+2 −1
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ import android.provider.Settings.Global.DEVELOPMENT_FORCE_DESKTOP_MODE_ON_EXTERN
import android.view.Display.DEFAULT_DISPLAY
import android.view.IWindowManager
import android.view.WindowManager.TRANSIT_CHANGE
import android.window.DesktopExperienceFlags
import android.window.WindowContainerTransaction
import com.android.internal.protolog.ProtoLog
import com.android.window.flags.Flags
@@ -62,7 +63,7 @@ class DesktopDisplayEventHandler(
    private fun onInit() {
        displayController.addDisplayWindowListener(this)

        if (Flags.enableMultipleDesktopsBackend()) {
        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue()) {
            desktopTasksController.onDeskRemovedListener = this
        }
    }
+13 −13
Original line number Diff line number Diff line
@@ -16,7 +16,7 @@

package com.android.wm.shell.desktopmode

import com.android.window.flags.Flags
import android.window.DesktopExperienceFlags
import com.android.wm.shell.shared.desktopmode.DesktopModeTransitionSource.UNKNOWN
import com.android.wm.shell.sysui.ShellCommandHandler
import java.io.PrintWriter
@@ -56,7 +56,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
                pw.println("Error: task id should be an integer")
                return false
            }
        if (!Flags.enableMultipleDesktopsBackend()) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            return controller.moveTaskToDefaultDeskAndActivate(taskId, transitionSource = UNKNOWN)
        }
        if (args.size < 3) {
@@ -95,7 +95,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
    }

    private fun runCreateDesk(args: Array<String>, pw: PrintWriter): Boolean {
        if (!Flags.enableMultipleDesktopsBackend()) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            pw.println("Not supported.")
            return false
        }
@@ -116,7 +116,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
    }

    private fun runActivateDesk(args: Array<String>, pw: PrintWriter): Boolean {
        if (!Flags.enableMultipleDesktopsBackend()) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            pw.println("Not supported.")
            return false
        }
@@ -137,7 +137,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
    }

    private fun runRemoveDesk(args: Array<String>, pw: PrintWriter): Boolean {
        if (!Flags.enableMultipleDesktopsBackend()) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            pw.println("Not supported.")
            return false
        }
@@ -158,7 +158,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
    }

    private fun runRemoveAllDesks(args: Array<String>, pw: PrintWriter): Boolean {
        if (!Flags.enableMultipleDesktopsBackend()) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            pw.println("Not supported.")
            return false
        }
@@ -167,7 +167,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
    }

    private fun runMoveTaskToFront(args: Array<String>, pw: PrintWriter): Boolean {
        if (!Flags.enableMultipleDesktopsBackend()) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            pw.println("Not supported.")
            return false
        }
@@ -188,7 +188,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
    }

    private fun runMoveTaskOutOfDesk(args: Array<String>, pw: PrintWriter): Boolean {
        if (!Flags.enableMultipleDesktopsBackend()) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            pw.println("Not supported.")
            return false
        }
@@ -204,12 +204,12 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
                pw.println("Error: task id should be an integer")
                return false
            }
        pw.println("Not implemented.")
        return false
        controller.moveToFullscreen(taskId, transitionSource = UNKNOWN)
        return true
    }

    private fun runCanCreateDesk(args: Array<String>, pw: PrintWriter): Boolean {
        if (!Flags.enableMultipleDesktopsBackend()) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            pw.println("Not supported.")
            return false
        }
@@ -225,7 +225,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
    }

    private fun runGetActiveDeskId(args: Array<String>, pw: PrintWriter): Boolean {
        if (!Flags.enableMultipleDesktopsBackend()) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            pw.println("Not supported.")
            return false
        }
@@ -246,7 +246,7 @@ class DesktopModeShellCommandHandler(private val controller: DesktopTasksControl
    }

    override fun printShellCommandHelp(pw: PrintWriter, prefix: String) {
        if (!Flags.enableMultipleDesktopsBackend()) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            pw.println("$prefix moveTaskToDesk <taskId> ")
            pw.println("$prefix  Move a task with given id to desktop mode.")
            pw.println("$prefix moveToNextDisplay <taskId> ")
+181 −75
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.util.ArrayMap
import android.util.ArraySet
import android.util.SparseArray
import android.view.Display.INVALID_DISPLAY
import android.window.DesktopExperienceFlags
import android.window.DesktopModeFlags
import androidx.core.util.forEach
import androidx.core.util.valueIterator
@@ -137,7 +138,7 @@ class DesktopRepository(
    private var desktopGestureExclusionExecutor: Executor? = null

    private val desktopData: DesktopData =
        if (Flags.enableMultipleDesktopsBackend()) {
        if (DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) {
            MultiDesktopData()
        } else {
            SingleDesktopData()
@@ -226,10 +227,19 @@ class DesktopRepository(
        desktopData.setActiveDesk(displayId = displayId, deskId = deskId)
    }

    /** Sets the given desk as inactive if it was active. */
    fun setDeskInactive(deskId: Int) {
        desktopData.setDeskInactive(deskId)
    }

    /** Returns the id of the active desk in the given display, if any. */
    @VisibleForTesting
    fun getActiveDeskId(displayId: Int): Int? = desktopData.getActiveDesk(displayId)?.deskId

    /** Returns the id of the desk to which this task belongs. */
    fun getDeskIdForTask(taskId: Int): Int? =
        desktopData.desksSequence().find { desk -> desk.activeTasks.contains(taskId) }?.deskId

    /**
     * Adds task with [taskId] to the list of freeform tasks on [displayId]'s active desk.
     *
@@ -270,20 +280,40 @@ class DesktopRepository(
    @VisibleForTesting
    fun removeActiveTask(taskId: Int, excludedDeskId: Int? = null) {
        val affectedDisplays = mutableSetOf<Int>()
        desktopData.forAllDesks { displayId, desk ->
            if (desk.deskId != excludedDeskId && desk.activeTasks.remove(taskId)) {
        desktopData
            .desksSequence()
            .filter { desk -> desk.displayId != excludedDeskId }
            .forEach { desk ->
                val removed = removeActiveTaskFromDesk(desk.deskId, taskId, notifyListeners = false)
                if (removed) {
                    logD(
                        "Removed active task=%d displayId=%d deskId=%d",
                        taskId,
                    displayId,
                        desk.displayId,
                        desk.deskId,
                    )
                affectedDisplays.add(displayId)
                    affectedDisplays.add(desk.displayId)
                }
            }
        affectedDisplays.forEach { displayId -> updateActiveTasksListeners(displayId) }
    }

    private fun removeActiveTaskFromDesk(
        deskId: Int,
        taskId: Int,
        notifyListeners: Boolean = true,
    ): Boolean {
        val desk = desktopData.getDesk(deskId) ?: return false
        if (desk.activeTasks.remove(taskId)) {
            logD("Removed active task=%d from deskId=%d", taskId, desk.deskId)
            if (notifyListeners) {
                updateActiveTasksListeners(desk.displayId)
            }
            return true
        }
        return false
    }

    /**
     * Adds given task to the closing task list for [displayId]'s active desk.
     *
@@ -322,10 +352,22 @@ class DesktopRepository(

    fun isActiveTask(taskId: Int) = desksSequence().any { taskId in it.activeTasks }

    @VisibleForTesting
    fun isActiveTaskInDesk(taskId: Int, deskId: Int): Boolean {
        val desk = desktopData.getDesk(deskId) ?: return false
        return taskId in desk.activeTasks
    }

    fun isClosingTask(taskId: Int) = desksSequence().any { taskId in it.closingTasks }

    fun isVisibleTask(taskId: Int) = desksSequence().any { taskId in it.visibleTasks }

    @VisibleForTesting
    fun isVisibleTaskInDesk(taskId: Int, deskId: Int): Boolean {
        val desk = desktopData.getDesk(deskId) ?: return false
        return taskId in desk.visibleTasks
    }

    fun isMinimizedTask(taskId: Int) = desksSequence().any { taskId in it.minimizedTasks }

    /**
@@ -415,12 +457,19 @@ class DesktopRepository(
    /** Removes task from visible tasks of all desks except [excludedDeskId]. */
    private fun removeVisibleTask(taskId: Int, excludedDeskId: Int? = null) {
        desktopData.forAllDesks { displayId, desk ->
            if (desk.deskId != excludedDeskId && desk.visibleTasks.remove(taskId)) {
                notifyVisibleTaskListeners(displayId, desk.visibleTasks.size)
            if (desk.deskId != excludedDeskId) {
                removeVisibleTaskFromDesk(deskId = desk.deskId, taskId = taskId)
            }
        }
    }

    private fun removeVisibleTaskFromDesk(deskId: Int, taskId: Int) {
        val desk = desktopData.getDesk(deskId) ?: return
        if (desk.visibleTasks.remove(taskId)) {
            notifyVisibleTaskListeners(desk.displayId, desk.visibleTasks.size)
        }
    }

    /**
     * Updates visibility of a freeform task with [taskId] on [displayId] and notifies listeners.
     *
@@ -576,15 +625,26 @@ class DesktopRepository(
    /**
     * Set whether the given task is the full-immersive task in this display's active desk.
     *
     * TODO: b/389960283 - add explicit [deskId] argument.
     * TODO: b/389960283 - consider forcing callers to use [setTaskInFullImmersiveStateInDesk] with
     *   an explicit desk id instead of using this function and defaulting to the active one.
     */
    fun setTaskInFullImmersiveState(displayId: Int, taskId: Int, immersive: Boolean) {
        val desktopData = desktopData.getActiveDesk(displayId) ?: return
        val activeDesk = desktopData.getActiveDesk(displayId) ?: return
        setTaskInFullImmersiveStateInDesk(
            deskId = activeDesk.deskId,
            taskId = taskId,
            immersive = immersive,
        )
    }

    /** Sets whether the given task is the full-immersive task in the given desk. */
    fun setTaskInFullImmersiveStateInDesk(deskId: Int, taskId: Int, immersive: Boolean) {
        val desk = desktopData.getDesk(deskId) ?: return
        if (immersive) {
            desktopData.fullImmersiveTaskId = taskId
            desk.fullImmersiveTaskId = taskId
        } else {
            if (desktopData.fullImmersiveTaskId == taskId) {
                desktopData.fullImmersiveTaskId = null
            if (desk.fullImmersiveTaskId == taskId) {
                desk.fullImmersiveTaskId = null
            }
        }
    }
@@ -674,7 +734,8 @@ class DesktopRepository(
    /**
     * Minimizes the task for [taskId] and [displayId]'s active display.
     *
     * TODO: b/389960283 - add explicit [deskId] argument.
     * TODO: b/389960283 - consider forcing callers to use [minimizeTaskInDesk] with an explicit
     *   desk id instead of using this function and defaulting to the active one.
     */
    fun minimizeTask(displayId: Int, taskId: Int) {
        if (displayId == INVALID_DISPLAY) {
@@ -683,32 +744,41 @@ class DesktopRepository(
            getDisplayIdForTask(taskId)?.let { minimizeTask(it, taskId) }
                ?: logW("Minimize task: No display id found for task: taskId=%d", taskId)
            return
        } else {
            logD("Minimize Task: display=%d, task=%d", displayId, taskId)
            desktopData.getActiveDesk(displayId)?.minimizedTasks?.add(taskId)
                ?: logD("Minimize task: No active desk found for task: taskId=%d", taskId)
        }
        updateTask(displayId, taskId, isVisible = false)
        val deskId = desktopData.getActiveDesk(displayId)?.deskId
        if (deskId == null) {
            logD("Minimize task: No active desk found for task: taskId=%d", taskId)
            return
        }
        minimizeTaskInDesk(displayId, deskId, taskId)
    }

    /** Minimizes the task in its desk. */
    @VisibleForTesting
    fun minimizeTaskInDesk(displayId: Int, deskId: Int, taskId: Int) {
        logD("Minimize Task: displayId=%d deskId=%d, task=%d", displayId, deskId, taskId)
        desktopData.getDesk(deskId)?.minimizedTasks?.add(taskId)
            ?: logD("Minimize task: No active desk found for task: taskId=%d", taskId)
        updateTaskInDesk(displayId, deskId, taskId, isVisible = false)
        if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
            updatePersistentRepository(displayId)
            updatePersistentRepositoryForDesk(deskId)
        }
    }

    /**
     * Unminimizes the task for [taskId] and [displayId].
     *
     * TODO: b/389960283 - consider adding an explicit [deskId] argument.
     * TODO: b/389960283 - consider using [unminimizeTaskFromDesk] instead.
     */
    fun unminimizeTask(displayId: Int, taskId: Int) {
        logD("Unminimize Task: display=%d, task=%d", displayId, taskId)
        var removed = false
        desktopData.forAllDesks(displayId) { desk ->
            if (desk.minimizedTasks.remove(taskId)) {
                removed = true
            }
        desktopData.forAllDesks(displayId) { desk -> unminimizeTaskFromDesk(desk.deskId, taskId) }
    }
        if (!removed) {
            logW("Unminimize Task: display=%d, task=%d, no task data", displayId, taskId)

    private fun unminimizeTaskFromDesk(deskId: Int, taskId: Int) {
        logD("Unminimize Task: deskId=%d, taskId=%d", deskId, taskId)
        if (desktopData.getDesk(deskId)?.minimizedTasks?.remove(taskId) != true) {
            logW("Unminimize Task: deskId=%d, taskId=%d, no task data", deskId, taskId)
        }
    }

@@ -729,7 +799,7 @@ class DesktopRepository(
     * Removes [taskId] from the respective display. If [INVALID_DISPLAY], the original display id
     * will be looked up from the task id.
     *
     * TODO: b/389960283 - consider adding an explicit [deskId] argument.
     * TODO: b/389960283 - consider using [removeTaskFromDesk] instead.
     */
    fun removeTask(displayId: Int, taskId: Int) {
        logD("Removes freeform task: taskId=%d", taskId)
@@ -745,6 +815,19 @@ class DesktopRepository(
    private fun removeTaskFromDisplay(displayId: Int, taskId: Int) {
        logD("Removes freeform task: taskId=%d, displayId=%d", taskId, displayId)
        desktopData.forAllDesks(displayId) { desk ->
            removeTaskFromDesk(deskId = desk.deskId, taskId = taskId)
        }
    }

    /** Removes the given task from the given desk. */
    fun removeTaskFromDesk(deskId: Int, taskId: Int) {
        logD("removeTaskFromDesk: deskId=%d, taskId=%d", taskId, deskId)
        // TODO: b/362720497 - consider not clearing bounds on any removal, such as when moving
        //  it between desks. It might be better to allow restoring to the previous bounds as long
        //  as they're valid (probably valid if in the same display).
        boundsBeforeMaximizeByTaskId.remove(taskId)
        boundsBeforeFullImmersiveByTaskId.remove(taskId)
        val desk = desktopData.getDesk(deskId) ?: return
        if (desk.freeformTasksInZOrder.remove(taskId)) {
            logD(
                "Remaining freeform tasks in desk: %d, tasks: %s",
@@ -752,17 +835,13 @@ class DesktopRepository(
                desk.freeformTasksInZOrder.toDumpString(),
            )
        }
        }
        boundsBeforeMaximizeByTaskId.remove(taskId)
        boundsBeforeFullImmersiveByTaskId.remove(taskId)
        // Remove task from unminimized task if it is minimized.
        unminimizeTask(displayId, taskId)
        unminimizeTaskFromDesk(deskId, taskId)
        // Mark task as not in immersive if it was immersive.
        setTaskInFullImmersiveState(displayId = displayId, taskId = taskId, immersive = false)
        removeActiveTask(taskId)
        removeVisibleTask(taskId)
        if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue()) {
            updatePersistentRepository(displayId)
        setTaskInFullImmersiveStateInDesk(deskId = deskId, taskId = taskId, immersive = false)
        removeActiveTaskFromDesk(deskId = deskId, taskId = taskId)
        removeVisibleTaskFromDesk(deskId = deskId, taskId = taskId)
        if (DesktopModeFlags.ENABLE_DESKTOP_WINDOWING_PERSISTENCE.isTrue) {
            updatePersistentRepositoryForDesk(desk.deskId)
        }
    }

@@ -832,11 +911,18 @@ class DesktopRepository(
    private fun updatePersistentRepository(displayId: Int) {
        val desks = desktopData.desksSequence(displayId).map { desk -> desk.deepCopy() }.toList()
        mainCoroutineScope.launch {
            desks.forEach { desk ->
            desks.forEach { desk -> updatePersistentRepositoryForDesk(desk) }
        }
    }

    private fun updatePersistentRepositoryForDesk(deskId: Int) {
        val desk = desktopData.getDesk(deskId)?.deepCopy() ?: return
        mainCoroutineScope.launch { updatePersistentRepositoryForDesk(desk) }
    }

    private suspend fun updatePersistentRepositoryForDesk(desk: Desk) {
        try {
            persistentRepository.addOrUpdateDesktop(
                        // Use display id as desk id for now since only once desk per display
                        // is supported.
                userId = userId,
                desktopId = desk.deskId,
                visibleTasks = desk.visibleTasks,
@@ -850,8 +936,6 @@ class DesktopRepository(
            )
        }
    }
        }
    }

    internal fun dump(pw: PrintWriter, prefix: String) {
        val innerPrefix = "$prefix  "
@@ -866,21 +950,27 @@ class DesktopRepository(
        desktopData
            .desksSequence()
            .groupBy { it.displayId }
            .forEach { (displayId, desks) ->
            .map { (displayId, desks) ->
                Triple(displayId, desktopData.getActiveDesk(displayId)?.deskId, desks)
            }
            .forEach { (displayId, activeDeskId, desks) ->
                pw.println("${prefix}Display #$displayId:")
                pw.println("${innerPrefix}activeDesk=$activeDeskId")
                pw.println("${innerPrefix}desks:")
                val desksPrefix = "$innerPrefix  "
                desks.forEach { desk ->
                    pw.println("${innerPrefix}Desk #${desk.deskId}:")
                    pw.print("$innerPrefix  activeTasks=")
                    pw.println("${desksPrefix}Desk #${desk.deskId}:")
                    pw.print("$desksPrefix  activeTasks=")
                    pw.println(desk.activeTasks.toDumpString())
                    pw.print("$innerPrefix  visibleTasks=")
                    pw.print("$desksPrefix  visibleTasks=")
                    pw.println(desk.visibleTasks.toDumpString())
                    pw.print("$innerPrefix  freeformTasksInZOrder=")
                    pw.print("$desksPrefix  freeformTasksInZOrder=")
                    pw.println(desk.freeformTasksInZOrder.toDumpString())
                    pw.print("$innerPrefix  minimizedTasks=")
                    pw.print("$desksPrefix  minimizedTasks=")
                    pw.println(desk.minimizedTasks.toDumpString())
                    pw.print("$innerPrefix  fullImmersiveTaskId=")
                    pw.print("$desksPrefix  fullImmersiveTaskId=")
                    pw.println(desk.fullImmersiveTaskId)
                    pw.print("$innerPrefix  topTransparentFullscreenTaskId=")
                    pw.print("$desksPrefix  topTransparentFullscreenTaskId=")
                    pw.println(desk.topTransparentFullscreenTaskId)
                }
            }
@@ -910,6 +1000,9 @@ class DesktopRepository(
        /** Sets the given desk as the active desk in the given display. */
        fun setActiveDesk(displayId: Int, deskId: Int)

        /** Sets the desk as inactive if it was active. */
        fun setDeskInactive(deskId: Int)

        /**
         * Returns the default desk in the given display. Useful when the system wants to activate a
         * desk but doesn't care about which one it activates (e.g. when putting a window into a
@@ -990,6 +1083,11 @@ class DesktopRepository(
            // existence of visible desktop windows, among other factors.
        }

        override fun setDeskInactive(deskId: Int) {
            // No-op, in single-desk setups, which desktop is "active" is determined by the
            // existence of visible desktop windows, among other factors.
        }

        override fun getDefaultDesk(displayId: Int): Desk = getDesk(deskId = displayId)

        override fun getAllActiveDesks(): Set<Desk> =
@@ -1058,6 +1156,14 @@ class DesktopRepository(
            display.activeDeskId = desk.deskId
        }

        override fun setDeskInactive(deskId: Int) {
            desktopDisplays.forEach { id, display ->
                if (display.activeDeskId == deskId) {
                    display.activeDeskId = null
                }
            }
        }

        override fun getDefaultDesk(displayId: Int): Desk? {
            val display = desktopDisplays[displayId] ?: return null
            return display.orderedDesks.find { it.deskId == display.activeDeskId }
+6 −0
Original line number Diff line number Diff line
@@ -42,6 +42,12 @@ class DesktopTaskChangeListener(private val desktopUserRepositories: DesktopUser
            desktopUserRepositories.getProfile(taskInfo.userId)
        if (!desktopRepository.isActiveTask(taskInfo.taskId)) return

        // TODO: b/394281403 - with multiple desks, it's possible to have a non-freeform task
        //  inside a desk, so this should be decoupled from windowing mode.
        //  Also, changes in/out of desks are handled by the [DesksTransitionObserver], which has
        //  more specific information about the desk involved in the transition, which might be
        //  more accurate than assuming it's always the default/active desk in the display, as this
        //  method does.
        // Case 1: Freeform task is changed in Desktop Mode.
        if (isFreeformTask(taskInfo)) {
            if (taskInfo.isVisible) {
Loading