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

Commit 6bf89062 authored by Ats Jenk's avatar Ats Jenk Committed by Automerger Merge Worker
Browse files

Merge "Store desktop tasks per display id" into udc-dev am: 2238fdb8

parents 857b22c3 2238fdb8
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