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

Commit 2238fdb8 authored by Ats Jenk's avatar Ats Jenk Committed by Android (Google) Code Review
Browse files

Merge "Store desktop tasks per display id" into udc-dev

parents 3b764784 2ee5002a
Loading
Loading
Loading
Loading
+15 −12
Original line number Diff line number Diff line
@@ -21,6 +21,7 @@ import static android.app.WindowConfiguration.ACTIVITY_TYPE_STANDARD;
import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;
import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
import static android.app.WindowConfiguration.WINDOWING_MODE_UNDEFINED;
import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.WindowManager.TRANSIT_CHANGE;
import static android.view.WindowManager.TRANSIT_NONE;
import static android.view.WindowManager.TRANSIT_OPEN;
@@ -264,10 +265,10 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll
    /**
     * Show apps on desktop
     */
    void showDesktopApps() {
    void showDesktopApps(int displayId) {
        // Bring apps to front, ignoring their visibility status to always ensure they are on top.
        WindowContainerTransaction wct = new WindowContainerTransaction();
        bringDesktopAppsToFront(wct);
        bringDesktopAppsToFront(displayId, wct);

        if (!wct.isEmpty()) {
            if (Transitions.ENABLE_SHELL_TRANSITIONS) {
@@ -280,12 +281,12 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll
    }

    /** Get number of tasks that are marked as visible */
    int getVisibleTaskCount() {
        return mDesktopModeTaskRepository.getVisibleTaskCount();
    int getVisibleTaskCount(int displayId) {
        return mDesktopModeTaskRepository.getVisibleTaskCount(displayId);
    }

    private void bringDesktopAppsToFront(WindowContainerTransaction wct) {
        final ArraySet<Integer> activeTasks = mDesktopModeTaskRepository.getActiveTasks();
    private void bringDesktopAppsToFront(int displayId, WindowContainerTransaction wct) {
        final ArraySet<Integer> activeTasks = mDesktopModeTaskRepository.getActiveTasks(displayId);
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront: tasks=%s", activeTasks.size());

        final List<RunningTaskInfo> taskInfos = new ArrayList<>();
@@ -386,6 +387,7 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll
    @Override
    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
            @NonNull TransitionRequestInfo request) {
        RunningTaskInfo triggerTask = request.getTriggerTask();
        // Only do anything if we are in desktop mode and opening/moving-to-front a task/app in
        // freeform
        if (!DesktopModeStatus.isActive(mContext)) {
@@ -399,16 +401,15 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll
                    WindowManager.transitTypeToString(request.getType()));
            return null;
        }
        if (request.getTriggerTask() == null
                || request.getTriggerTask().getWindowingMode() != WINDOWING_MODE_FREEFORM) {
        if (triggerTask == null || triggerTask.getWindowingMode() != WINDOWING_MODE_FREEFORM) {
            ProtoLog.d(WM_SHELL_DESKTOP_MODE, "skip shell transition request: not freeform task");
            return null;
        }
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "handle shell transition request: %s", request);

        WindowContainerTransaction wct = new WindowContainerTransaction();
        bringDesktopAppsToFront(wct);
        wct.reorder(request.getTriggerTask().token, true /* onTop */);
        bringDesktopAppsToFront(triggerTask.displayId, wct);
        wct.reorder(triggerTask.token, true /* onTop */);

        return wct;
    }
@@ -493,16 +494,18 @@ public class DesktopModeController implements RemoteCallable<DesktopModeControll
            mController = null;
        }

        // TODO(b/278084491): pass in display id
        public void showDesktopApps() {
            executeRemoteCallWithTaskPermission(mController, "showDesktopApps",
                    DesktopModeController::showDesktopApps);
                    controller -> controller.showDesktopApps(DEFAULT_DISPLAY));
        }

        // TODO(b/278084491): pass in display id
        @Override
        public int getVisibleTaskCount() throws RemoteException {
            int[] result = new int[1];
            executeRemoteCallWithTaskPermission(mController, "getVisibleTaskCount",
                    controller -> result[0] = controller.getVisibleTaskCount(),
                    controller -> result[0] = controller.getVisibleTaskCount(DEFAULT_DISPLAY),
                    true /* blocking */
            );
            return result[0];
+105 −44
Original line number Diff line number Diff line
@@ -20,6 +20,8 @@ import android.graphics.Region
import android.util.ArrayMap
import android.util.ArraySet
import android.util.SparseArray
import androidx.core.util.forEach
import androidx.core.util.keyIterator
import androidx.core.util.valueIterator
import java.util.concurrent.Executor
import java.util.function.Consumer
@@ -29,14 +31,18 @@ import java.util.function.Consumer
 */
class DesktopModeTaskRepository {

    /** Task data that is tracked per display */
    private data class DisplayData(
        /**
     * Set of task ids that are marked as active in desktop mode.
     * Active tasks in desktop mode are freeform tasks that are visible or have been visible after
     * desktop mode was activated.
     * Task gets removed from this list when it vanishes. Or when desktop mode is turned off.
         * Set of task ids that are marked as active in desktop mode. Active tasks in desktop mode
         * are freeform tasks that are visible or have been visible after desktop mode was
         * activated. Task gets removed from this list when it vanishes. Or when desktop mode is
         * turned off.
         */
    private val activeTasks = ArraySet<Int>()
    private val visibleTasks = ArraySet<Int>()
        val activeTasks: ArraySet<Int> = ArraySet(),
        val visibleTasks: ArraySet<Int> = ArraySet(),
    )

    // Tasks currently in freeform mode, ordered from top to bottom (top is at index 0).
    private val freeformTasksInZOrder = mutableListOf<Int>()
    private val activeTasksListeners = ArraySet<ActiveTasksListener>()
@@ -47,9 +53,22 @@ class DesktopModeTaskRepository {
    private var desktopGestureExclusionListener: Consumer<Region>? = null
    private var desktopGestureExclusionExecutor: Executor? = null

    private val displayData =
        object : SparseArray<DisplayData>() {
            /**
     * Add a [ActiveTasksListener] to be notified of updates to active tasks in the repository.
             * Get the [DisplayData] associated with this [displayId]
             *
             * Creates a new instance if one does not exist
             */
            fun getOrCreate(displayId: Int): DisplayData {
                if (!contains(displayId)) {
                    put(displayId, DisplayData())
                }
                return get(displayId)
            }
        }

    /** Add a [ActiveTasksListener] to be notified of updates to active tasks in the repository. */
    fun addActiveTaskListener(activeTasksListener: ActiveTasksListener) {
        activeTasksListeners.add(activeTasksListener)
    }
@@ -57,10 +76,17 @@ class DesktopModeTaskRepository {
    /**
     * Add a [VisibleTasksListener] to be notified when freeform tasks are visible or not.
     */
    fun addVisibleTasksListener(visibleTasksListener: VisibleTasksListener, executor: Executor) {
        visibleTasksListeners.put(visibleTasksListener, executor)
        executor.execute(
                Runnable { visibleTasksListener.onVisibilityChanged(visibleTasks.size > 0) })
    fun addVisibleTasksListener(
        visibleTasksListener: VisibleTasksListener,
        executor: Executor
    ) {
        visibleTasksListeners[visibleTasksListener] = executor
        displayData.keyIterator().forEach { displayId ->
            val visibleTasks = getVisibleTaskCount(displayId)
            executor.execute {
                visibleTasksListener.onVisibilityChanged(displayId, visibleTasks > 0)
            }
        }
    }

    /**
@@ -100,14 +126,21 @@ class DesktopModeTaskRepository {
    }

    /**
     * Mark a task with given [taskId] as active.
     * Mark a task with given [taskId] as active on given [displayId]
     *
     * @return `true` if the task was not active
     * @return `true` if the task was not active on given [displayId]
     */
    fun addActiveTask(taskId: Int): Boolean {
        val added = activeTasks.add(taskId)
    fun addActiveTask(displayId: Int, taskId: Int): Boolean {
        // Check if task is active on another display, if so, remove it
        displayData.forEach { id, data ->
            if (id != displayId && data.activeTasks.remove(taskId)) {
                activeTasksListeners.onEach { it.onActiveTasksChanged(id) }
            }
        }

        val added = displayData.getOrCreate(displayId).activeTasks.add(taskId)
        if (added) {
            activeTasksListeners.onEach { it.onActiveTasksChanged() }
            activeTasksListeners.onEach { it.onActiveTasksChanged(displayId) }
        }
        return added
    }
@@ -118,65 +151,93 @@ class DesktopModeTaskRepository {
     * @return `true` if the task was active
     */
    fun removeActiveTask(taskId: Int): Boolean {
        val removed = activeTasks.remove(taskId)
        if (removed) {
            activeTasksListeners.onEach { it.onActiveTasksChanged() }
        var result = false
        displayData.forEach { displayId, data ->
            if (data.activeTasks.remove(taskId)) {
                activeTasksListeners.onEach { it.onActiveTasksChanged(displayId) }
                result = true
            }
        return removed
        }
        return result
    }

    /**
     * Check if a task with the given [taskId] was marked as an active task
     */
    fun isActiveTask(taskId: Int): Boolean {
        return activeTasks.contains(taskId)
        return displayData.valueIterator().asSequence().any { data ->
            data.activeTasks.contains(taskId)
        }
    }

    /**
     * Whether a task is visible.
     */
    fun isVisibleTask(taskId: Int): Boolean {
        return visibleTasks.contains(taskId)
        return displayData.valueIterator().asSequence().any { data ->
            data.visibleTasks.contains(taskId)
        }
    }

    /**
     * Get a set of the active tasks
     * Get a set of the active tasks for given [displayId]
     */
    fun getActiveTasks(): ArraySet<Int> {
        return ArraySet(activeTasks)
    fun getActiveTasks(displayId: Int): ArraySet<Int> {
        return ArraySet(displayData[displayId]?.activeTasks)
    }

    /**
     * Get a list of freeform tasks, ordered from top-bottom (top at index 0).
     */
     // TODO(b/278084491): pass in display id
    fun getFreeformTasksInZOrder(): List<Int> {
        return freeformTasksInZOrder
    }

    /**
     * Updates whether a freeform task with this id is visible or not and notifies listeners.
     *
     * If the task was visible on a different display with a different displayId, it is removed from
     * the set of visible tasks on that display. Listeners will be notified.
     */
    fun updateVisibleFreeformTasks(taskId: Int, visible: Boolean) {
        val prevCount: Int = visibleTasks.size
    fun updateVisibleFreeformTasks(displayId: Int, taskId: Int, visible: Boolean) {
        if (visible) {
            // Task is visible. Check if we need to remove it from any other display.
            val otherDisplays = displayData.keyIterator().asSequence().filter { it != displayId }
            for (otherDisplayId in otherDisplays) {
                if (displayData[otherDisplayId].visibleTasks.remove(taskId)) {
                    // Task removed from other display, check if we should notify listeners
                    if (displayData[otherDisplayId].visibleTasks.isEmpty()) {
                        notifyVisibleTaskListeners(otherDisplayId, hasVisibleFreeformTasks = false)
                    }
                }
            }
        }

        val prevCount = getVisibleTaskCount(displayId)
        if (visible) {
            visibleTasks.add(taskId)
            displayData.getOrCreate(displayId).visibleTasks.add(taskId)
        } else {
            visibleTasks.remove(taskId)
            displayData[displayId]?.visibleTasks?.remove(taskId)
        }
        val newCount = getVisibleTaskCount(displayId)
        // Check if count changed and if there was no tasks or this is the first task
        if (prevCount != newCount && (prevCount == 0 || newCount == 0)) {
            notifyVisibleTaskListeners(displayId, newCount > 0)
        }
        if (prevCount == 0 && visibleTasks.size == 1 ||
                prevCount > 0 && visibleTasks.size == 0) {
            for ((listener, executor) in visibleTasksListeners) {
                executor.execute(
                        Runnable { listener.onVisibilityChanged(visibleTasks.size > 0) })
    }

    private fun notifyVisibleTaskListeners(displayId: Int, hasVisibleFreeformTasks: Boolean) {
        visibleTasksListeners.forEach { (listener, executor) ->
            executor.execute { listener.onVisibilityChanged(displayId, hasVisibleFreeformTasks) }
        }
    }

    /**
     * Get number of tasks that are marked as visible
     * Get number of tasks that are marked as visible on given [displayId]
     */
    fun getVisibleTaskCount(): Int {
        return visibleTasks.size
    fun getVisibleTaskCount(displayId: Int): Int {
        return displayData[displayId]?.visibleTasks?.size ?: 0
    }

    /**
@@ -226,7 +287,7 @@ class DesktopModeTaskRepository {
         * Called when the active tasks change in desktop mode.
         */
        @JvmDefault
        fun onActiveTasksChanged() {}
        fun onActiveTasksChanged(displayId: Int) {}
    }

    /**
@@ -237,6 +298,6 @@ class DesktopModeTaskRepository {
         * Called when the desktop starts or stops showing freeform tasks.
         */
        @JvmDefault
        fun onVisibilityChanged(hasVisibleFreeformTasks: Boolean) {}
        fun onVisibilityChanged(displayId: Int, hasVisibleFreeformTasks: Boolean) {}
    }
}
+23 −20
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@ import android.graphics.Rect
import android.graphics.Region
import android.os.IBinder
import android.os.SystemProperties
import android.view.Display.DEFAULT_DISPLAY
import android.view.SurfaceControl
import android.view.WindowManager.TRANSIT_CHANGE
import android.view.WindowManager.TRANSIT_NONE
@@ -97,10 +98,11 @@ class DesktopTasksController(
    }

    /** Show all tasks, that are part of the desktop, on top of launcher */
    fun showDesktopApps() {
    fun showDesktopApps(displayId: Int) {
        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "showDesktopApps")
        val wct = WindowContainerTransaction()
        bringDesktopAppsToFront(wct)
        // TODO(b/278084491): pass in display id
        bringDesktopAppsToFront(displayId, wct)

        // Execute transaction if there are pending operations
        if (!wct.isEmpty) {
@@ -114,8 +116,8 @@ class DesktopTasksController(
    }

    /** Get number of tasks that are marked as visible */
    fun getVisibleTaskCount(): Int {
        return desktopModeTaskRepository.getVisibleTaskCount()
    fun getVisibleTaskCount(displayId: Int): Int {
        return desktopModeTaskRepository.getVisibleTaskCount(displayId)
    }

    /** Move a task with given `taskId` to desktop */
@@ -129,7 +131,7 @@ class DesktopTasksController(

        val wct = WindowContainerTransaction()
        // Bring other apps to front first
        bringDesktopAppsToFront(wct)
        bringDesktopAppsToFront(task.displayId, wct)
        addMoveToDesktopChanges(wct, task.token)
        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
            transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
@@ -165,7 +167,7 @@ class DesktopTasksController(
            freeformBounds: Rect
    ) {
        val wct = WindowContainerTransaction()
        bringDesktopAppsToFront(wct)
        bringDesktopAppsToFront(taskInfo.displayId, wct)
        addMoveToDesktopChanges(wct, taskInfo.getToken())
        wct.setBounds(taskInfo.token, freeformBounds)

@@ -244,9 +246,9 @@ class DesktopTasksController(
            ?: WINDOWING_MODE_UNDEFINED
    }

    private fun bringDesktopAppsToFront(wct: WindowContainerTransaction) {
    private fun bringDesktopAppsToFront(displayId: Int, wct: WindowContainerTransaction) {
        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "bringDesktopAppsToFront")
        val activeTasks = desktopModeTaskRepository.getActiveTasks()
        val activeTasks = desktopModeTaskRepository.getActiveTasks(displayId)

        // First move home to front and then other tasks on top of it
        moveHomeTaskToFront(wct)
@@ -290,18 +292,17 @@ class DesktopTasksController(
        request: TransitionRequestInfo
    ): WindowContainerTransaction? {
        // Check if we should skip handling this transition
        val task: RunningTaskInfo? = request.triggerTask
        val shouldHandleRequest =
            when {
                // Only handle open or to front transitions
                request.type != TRANSIT_OPEN && request.type != TRANSIT_TO_FRONT -> false
                // Only handle when it is a task transition
                task == null -> false
                request.triggerTask == null -> false
                // Only handle standard type tasks
                task.activityType != ACTIVITY_TYPE_STANDARD -> false
                request.triggerTask.activityType != ACTIVITY_TYPE_STANDARD -> false
                // Only handle fullscreen or freeform tasks
                task.windowingMode != WINDOWING_MODE_FULLSCREEN &&
                    task.windowingMode != WINDOWING_MODE_FREEFORM -> false
                request.triggerTask.windowingMode != WINDOWING_MODE_FULLSCREEN &&
                        request.triggerTask.windowingMode != WINDOWING_MODE_FREEFORM -> false
                // Otherwise process it
                else -> true
            }
@@ -310,10 +311,11 @@ class DesktopTasksController(
            return null
        }

        val activeTasks = desktopModeTaskRepository.getActiveTasks()
        val task: RunningTaskInfo = request.triggerTask
        val activeTasks = desktopModeTaskRepository.getActiveTasks(task.displayId)

        // Check if we should switch a fullscreen task to freeform
        if (task?.windowingMode == WINDOWING_MODE_FULLSCREEN) {
        if (task.windowingMode == WINDOWING_MODE_FULLSCREEN) {
            // If there are any visible desktop tasks, switch the task to freeform
            if (activeTasks.any { desktopModeTaskRepository.isVisibleTask(it) }) {
                ProtoLog.d(
@@ -329,7 +331,7 @@ class DesktopTasksController(
        }

        // CHeck if we should switch a freeform task to fullscreen
        if (task?.windowingMode == WINDOWING_MODE_FREEFORM) {
        if (task.windowingMode == WINDOWING_MODE_FREEFORM) {
            // If no visible desktop tasks, switch this task to freeform as the transition came
            // outside of this controller
            if (activeTasks.none { desktopModeTaskRepository.isVisibleTask(it) }) {
@@ -559,20 +561,21 @@ class DesktopTasksController(
            controller = null
        }

        // TODO(b/278084491): pass in display id
        override fun showDesktopApps() {
            ExecutorUtils.executeRemoteCallWithTaskPermission(
                controller,
                "showDesktopApps",
                Consumer(DesktopTasksController::showDesktopApps)
            )
                "showDesktopApps"
            ) { c -> c.showDesktopApps(DEFAULT_DISPLAY) }
        }

        // TODO(b/278084491): pass in display id
        override fun getVisibleTaskCount(): Int {
            val result = IntArray(1)
            ExecutorUtils.executeRemoteCallWithTaskPermission(
                controller,
                "getVisibleTaskCount",
                { controller -> result[0] = controller.getVisibleTaskCount() },
                { controller -> result[0] = controller.getVisibleTaskCount(DEFAULT_DISPLAY) },
                true /* blocking */
            )
            return result[0]
+7 −5
Original line number Diff line number Diff line
@@ -94,11 +94,12 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
            mDesktopModeTaskRepository.ifPresent(repository -> {
                repository.addOrMoveFreeformTaskToTop(taskInfo.taskId);
                if (taskInfo.isVisible) {
                    if (repository.addActiveTask(taskInfo.taskId)) {
                    if (repository.addActiveTask(taskInfo.displayId, taskInfo.taskId)) {
                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                                "Adding active freeform task: #%d", taskInfo.taskId);
                    }
                    repository.updateVisibleFreeformTasks(taskInfo.taskId, true);
                    repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId,
                            true);
                }
            });
        }
@@ -117,7 +118,7 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
                    ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                            "Removing active freeform task: #%d", taskInfo.taskId);
                }
                repository.updateVisibleFreeformTasks(taskInfo.taskId, false);
                repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId, false);
            });
        }

@@ -137,12 +138,13 @@ public class FreeformTaskListener implements ShellTaskOrganizer.TaskListener,
        if (DesktopModeStatus.isAnyEnabled()) {
            mDesktopModeTaskRepository.ifPresent(repository -> {
                if (taskInfo.isVisible) {
                    if (repository.addActiveTask(taskInfo.taskId)) {
                    if (repository.addActiveTask(taskInfo.displayId, taskInfo.taskId)) {
                        ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
                                "Adding active freeform task: #%d", taskInfo.taskId);
                    }
                }
                repository.updateVisibleFreeformTasks(taskInfo.taskId, taskInfo.isVisible);
                repository.updateVisibleFreeformTasks(taskInfo.displayId, taskInfo.taskId,
                        taskInfo.isVisible);
            });
        }
    }
+1 −1
Original line number Diff line number Diff line
@@ -245,7 +245,7 @@ public class RecentTasksController implements TaskStackListenerCallback,
    }

    @Override
    public void onActiveTasksChanged() {
    public void onActiveTasksChanged(int displayId) {
        notifyRecentTasksChanged();
    }

Loading