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

Commit 87254782 authored by Jorge Gil's avatar Jorge Gil Committed by Android (Google) Code Review
Browse files

Merge "[20/N] Desks: Implement IDesktopTaskListener add/remove/activation APIs" into main

parents 353e415b 92b5c5ca
Loading
Loading
Loading
Loading
+69 −0
Original line number Diff line number Diff line
@@ -35,6 +35,9 @@ import com.android.wm.shell.shared.annotations.ShellMainThread
import java.io.PrintWriter
import java.util.concurrent.Executor
import java.util.function.Consumer
import kotlin.collections.component1
import kotlin.collections.component2
import kotlin.collections.forEach
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch

@@ -116,6 +119,7 @@ class DesktopRepository(
        }
    }

    private val deskChangeListeners = ArrayMap<DeskChangeListener, Executor>()
    private val activeTasksListeners = ArraySet<ActiveTasksListener>()
    private val visibleTasksListeners = ArrayMap<VisibleTasksListener, Executor>()

@@ -144,6 +148,11 @@ class DesktopRepository(
            SingleDesktopData()
        }

    /** Adds a listener to be notified of updates about desk changes. */
    fun addDeskChangeListener(listener: DeskChangeListener, executor: Executor) {
        deskChangeListeners[listener] = executor
    }

    /** Adds [activeTasksListener] to be notified of updates to active tasks. */
    fun addActiveTaskListener(activeTasksListener: ActiveTasksListener) {
        activeTasksListeners.add(activeTasksListener)
@@ -196,6 +205,11 @@ class DesktopRepository(
        return desktopExclusionRegion
    }

    /** Removes the previously registered listener. */
    fun removeDeskChangeListener(listener: DeskChangeListener) {
        deskChangeListeners.remove(listener)
    }

    /** Remove the previously registered [activeTasksListener] */
    fun removeActiveTasksListener(activeTasksListener: ActiveTasksListener) {
        activeTasksListeners.remove(activeTasksListener)
@@ -210,6 +224,9 @@ class DesktopRepository(
    fun addDesk(displayId: Int, deskId: Int) {
        logD("addDesk for displayId=%d and deskId=%d", displayId, deskId)
        desktopData.createDesk(displayId, deskId)
        deskChangeListeners.forEach { (listener, executor) ->
            executor.execute { listener.onDeskAdded(displayId = displayId, deskId = deskId) }
        }
    }

    /** Returns the ids of the existing desks in the given display. */
@@ -229,12 +246,37 @@ class DesktopRepository(
    /** Sets the given desk as the active one in the given display. */
    fun setActiveDesk(displayId: Int, deskId: Int) {
        logD("setActiveDesk for displayId=%d and deskId=%d", displayId, deskId)
        val oldActiveDeskId = desktopData.getActiveDesk(displayId)?.deskId ?: INVALID_DESK_ID
        desktopData.setActiveDesk(displayId = displayId, deskId = deskId)
        deskChangeListeners.forEach { (listener, executor) ->
            executor.execute {
                listener.onActiveDeskChanged(
                    displayId = displayId,
                    newActiveDeskId = deskId,
                    oldActiveDeskId = oldActiveDeskId,
                )
            }
        }
    }

    /** Sets the given desk as inactive if it was active. */
    fun setDeskInactive(deskId: Int) {
        val displayId = desktopData.getDisplayForDesk(deskId)
        val activeDeskId = desktopData.getActiveDesk(displayId)?.deskId ?: INVALID_DESK_ID
        if (activeDeskId == INVALID_DESK_ID || activeDeskId != deskId) {
            // Desk wasn't active.
            return
        }
        desktopData.setDeskInactive(deskId)
        deskChangeListeners.forEach { (listener, executor) ->
            executor.execute {
                listener.onActiveDeskChanged(
                    displayId = displayId,
                    newActiveDeskId = INVALID_DESK_ID,
                    oldActiveDeskId = deskId,
                )
            }
        }
    }

    /** Returns the id of the active desk in the given display, if any. */
@@ -897,8 +939,21 @@ class DesktopRepository(
                ?: return emptySet<Int>().also {
                    logW("Could not find desk to remove: deskId=%d", deskId)
                }
        val wasActive = desktopData.getActiveDesk(desk.displayId)?.deskId == desk.deskId
        val activeTasks = ArraySet(desk.activeTasks)
        desktopData.remove(desk.deskId)
        deskChangeListeners.forEach { (listener, executor) ->
            executor.execute {
                if (wasActive) {
                    listener.onActiveDeskChanged(
                        displayId = desk.displayId,
                        newActiveDeskId = INVALID_DESK_ID,
                        oldActiveDeskId = desk.deskId,
                    )
                }
                listener.onDeskRemoved(displayId = desk.displayId, deskId = desk.deskId)
            }
        }
        return activeTasks
    }

@@ -1021,6 +1076,18 @@ class DesktopRepository(
            }
    }

    /** Listens to changes of desks state. */
    interface DeskChangeListener {
        /** Called when a new desk is added to a display. */
        fun onDeskAdded(displayId: Int, deskId: Int)

        /** Called when a desk is removed from a display. */
        fun onDeskRemoved(displayId: Int, deskId: Int)

        /** Called when the active desk in a display has changed. */
        fun onActiveDeskChanged(displayId: Int, newActiveDeskId: Int, oldActiveDeskId: Int)
    }

    /** Listens to changes for active tasks in desktop mode. */
    interface ActiveTasksListener {
        fun onActiveTasksChanged(displayId: Int) {}
@@ -1281,6 +1348,8 @@ class DesktopRepository(

    companion object {
        private const val TAG = "DesktopRepository"

        @VisibleForTesting const val INVALID_DESK_ID = -1
    }
}

+52 −3
Original line number Diff line number Diff line
@@ -97,6 +97,7 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.Unminim
import com.android.wm.shell.desktopmode.DesktopModeUiEventLogger.DesktopUiEventEnum
import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.DragStartState
import com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType
import com.android.wm.shell.desktopmode.DesktopRepository.DeskChangeListener
import com.android.wm.shell.desktopmode.DesktopRepository.VisibleTasksListener
import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.Companion.DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS
import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.DragToDesktopStateListener
@@ -3497,7 +3498,47 @@ class DesktopTasksController(
        private lateinit var remoteListener:
            SingleInstanceRemoteListener<DesktopTasksController, IDesktopTaskListener>

        private val listener: VisibleTasksListener =
        private val deskChangeListener: DeskChangeListener =
            object : DeskChangeListener {
                override fun onDeskAdded(displayId: Int, deskId: Int) {
                    ProtoLog.v(
                        WM_SHELL_DESKTOP_MODE,
                        "IDesktopModeImpl: onDeskAdded display=%d deskId=%d",
                        displayId,
                        deskId,
                    )
                    remoteListener.call { l -> l.onDeskAdded(displayId, deskId) }
                }

                override fun onDeskRemoved(displayId: Int, deskId: Int) {
                    ProtoLog.v(
                        WM_SHELL_DESKTOP_MODE,
                        "IDesktopModeImpl: onDeskRemoved display=%d deskId=%d",
                        displayId,
                        deskId,
                    )
                    remoteListener.call { l -> l.onDeskRemoved(displayId, deskId) }
                }

                override fun onActiveDeskChanged(
                    displayId: Int,
                    newActiveDeskId: Int,
                    oldActiveDeskId: Int,
                ) {
                    ProtoLog.v(
                        WM_SHELL_DESKTOP_MODE,
                        "IDesktopModeImpl: onActiveDeskChanged display=%d new=%d old=%d",
                        displayId,
                        newActiveDeskId,
                        oldActiveDeskId,
                    )
                    remoteListener.call { l ->
                        l.onActiveDeskChanged(displayId, newActiveDeskId, oldActiveDeskId)
                    }
                }
            }

        private val visibleTasksListener: VisibleTasksListener =
            object : VisibleTasksListener {
                override fun onTasksVisibilityChanged(displayId: Int, visibleTasksCount: Int) {
                    ProtoLog.v(
@@ -3561,7 +3602,14 @@ class DesktopTasksController(
                    controller,
                    { c ->
                        run {
                            c.taskRepository.addVisibleTasksListener(listener, c.mainExecutor)
                            c.taskRepository.addDeskChangeListener(
                                deskChangeListener,
                                c.mainExecutor,
                            )
                            c.taskRepository.addVisibleTasksListener(
                                visibleTasksListener,
                                c.mainExecutor,
                            )
                            c.taskbarDesktopTaskListener = taskbarDesktopTaskListener
                            c.desktopModeEnterExitTransitionListener =
                                desktopModeEntryExitTransitionListener
@@ -3569,7 +3617,8 @@ class DesktopTasksController(
                    },
                    { c ->
                        run {
                            c.taskRepository.removeVisibleTasksListener(listener)
                            c.taskRepository.removeDeskChangeListener(deskChangeListener)
                            c.taskRepository.removeVisibleTasksListener(visibleTasksListener)
                            c.taskbarDesktopTaskListener = null
                            c.desktopModeEnterExitTransitionListener = null
                        }
+157 −0
Original line number Diff line number Diff line
@@ -31,12 +31,14 @@ import com.android.window.flags.Flags.FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND
import com.android.wm.shell.ShellTestCase
import com.android.wm.shell.TestShellExecutor
import com.android.wm.shell.common.ShellExecutor
import com.android.wm.shell.desktopmode.DesktopRepository.Companion.INVALID_DESK_ID
import com.android.wm.shell.desktopmode.persistence.Desktop
import com.android.wm.shell.desktopmode.persistence.DesktopPersistentRepository
import com.android.wm.shell.sysui.ShellInit
import com.google.common.truth.Truth.assertThat
import junit.framework.Assert.fail
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -1430,6 +1432,161 @@ class DesktopRepositoryTest(flags: FlagsParameterization) : ShellTestCase() {
            )
    }

    @Test
    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun addDesk_updatesListener() {
        val listener = TestDeskChangeListener()
        val executor = TestShellExecutor()
        repo.addDeskChangeListener(listener, executor)

        repo.addDesk(displayId = 0, deskId = 1)
        executor.flushAll()

        val lastAddition = assertNotNull(listener.lastAddition)
        assertThat(lastAddition.displayId).isEqualTo(0)
        assertThat(lastAddition.deskId).isEqualTo(1)
    }

    @Test
    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun removeDesk_updatesListener() {
        val listener = TestDeskChangeListener()
        val executor = TestShellExecutor()
        repo.addDeskChangeListener(listener, executor)
        repo.addDesk(displayId = 0, deskId = 1)

        repo.removeDesk(deskId = 1)
        executor.flushAll()

        val lastRemoval = assertNotNull(listener.lastRemoval)
        assertThat(lastRemoval.displayId).isEqualTo(0)
        assertThat(lastRemoval.deskId).isEqualTo(1)
    }

    @Test
    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun removeDesk_didNotExist_doesNotUpdateListener() {
        val listener = TestDeskChangeListener()
        val executor = TestShellExecutor()
        repo.addDeskChangeListener(listener, executor)
        repo.addDesk(displayId = 0, deskId = 1)

        repo.removeDesk(deskId = 2)
        executor.flushAll()

        assertThat(listener.lastRemoval).isNull()
    }

    @Test
    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun removeDesk_wasActive_updatesActiveChangeListener() {
        val listener = TestDeskChangeListener()
        val executor = TestShellExecutor()
        repo.addDeskChangeListener(listener, executor)
        repo.addDesk(displayId = 0, deskId = 1)
        repo.setActiveDesk(displayId = 0, deskId = 1)

        repo.removeDesk(deskId = 1)
        executor.flushAll()

        val lastActivationChange = assertNotNull(listener.lastActivationChange)
        assertThat(lastActivationChange.displayId).isEqualTo(0)
        assertThat(lastActivationChange.oldActive).isEqualTo(1)
        assertThat(lastActivationChange.newActive).isEqualTo(INVALID_DESK_ID)
    }

    @Test
    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun setDeskActive_fromNoActive_updatesListener() {
        val listener = TestDeskChangeListener()
        val executor = TestShellExecutor()
        repo.addDeskChangeListener(listener, executor)
        repo.addDesk(displayId = 1, deskId = 1)

        repo.setActiveDesk(displayId = 1, deskId = 1)
        executor.flushAll()

        val lastActivationChange = assertNotNull(listener.lastActivationChange)
        assertThat(lastActivationChange.displayId).isEqualTo(1)
        assertThat(lastActivationChange.oldActive).isEqualTo(INVALID_DESK_ID)
        assertThat(lastActivationChange.newActive).isEqualTo(1)
    }

    @Test
    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun setDeskActive_fromOtherActive_updatesListener() {
        val listener = TestDeskChangeListener()
        val executor = TestShellExecutor()
        repo.addDeskChangeListener(listener, executor)
        repo.addDesk(displayId = 1, deskId = 1)
        repo.addDesk(displayId = 1, deskId = 2)
        repo.setActiveDesk(displayId = 1, deskId = 1)

        repo.setActiveDesk(displayId = 1, deskId = 2)
        executor.flushAll()

        val lastActivationChange = assertNotNull(listener.lastActivationChange)
        assertThat(lastActivationChange.displayId).isEqualTo(1)
        assertThat(lastActivationChange.oldActive).isEqualTo(1)
        assertThat(lastActivationChange.newActive).isEqualTo(2)
    }

    @Test
    @EnableFlags(FLAG_ENABLE_MULTIPLE_DESKTOPS_BACKEND)
    fun setDeskInactive_updatesListener() {
        val listener = TestDeskChangeListener()
        val executor = TestShellExecutor()
        repo.addDeskChangeListener(listener, executor)
        repo.addDesk(displayId = 0, deskId = 1)
        repo.setActiveDesk(displayId = 0, deskId = 1)

        repo.setDeskInactive(deskId = 1)
        executor.flushAll()

        val lastActivationChange = assertNotNull(listener.lastActivationChange)
        assertThat(lastActivationChange.displayId).isEqualTo(0)
        assertThat(lastActivationChange.oldActive).isEqualTo(1)
        assertThat(lastActivationChange.newActive).isEqualTo(INVALID_DESK_ID)
    }

    private class TestDeskChangeListener : DesktopRepository.DeskChangeListener {
        var lastAddition: LastAddition? = null
            private set

        var lastRemoval: LastRemoval? = null
            private set

        var lastActivationChange: LastActivationChange? = null
            private set

        override fun onDeskAdded(displayId: Int, deskId: Int) {
            lastAddition = LastAddition(displayId, deskId)
        }

        override fun onDeskRemoved(displayId: Int, deskId: Int) {
            lastRemoval = LastRemoval(displayId, deskId)
        }

        override fun onActiveDeskChanged(
            displayId: Int,
            newActiveDeskId: Int,
            oldActiveDeskId: Int,
        ) {
            lastActivationChange =
                LastActivationChange(
                    displayId = displayId,
                    oldActive = oldActiveDeskId,
                    newActive = newActiveDeskId,
                )
        }

        data class LastAddition(val displayId: Int, val deskId: Int)

        data class LastRemoval(val displayId: Int, val deskId: Int)

        data class LastActivationChange(val displayId: Int, val oldActive: Int, val newActive: Int)
    }

    class TestListener : DesktopRepository.ActiveTasksListener {
        var activeChangesOnDefaultDisplay = 0
        var activeChangesOnSecondaryDisplay = 0