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

Commit 059a7f56 authored by Orhan Uysal's avatar Orhan Uysal
Browse files

Pipe all desk to desk transitions...

to DeskSwitchTransitionHandler. When a desk to desk transition is
detected on the MixedHandler delegate it to the correct handler.

Test: atest DeskTransitionObserverTest &
DesktopMixedTransitionHandlerTest
Test: Create 2 desks, switch between them using the taskbar icons,
observe the animation
Bug: 440224276
Flag: com.android.window.flags.keyboard_shortcuts_to_switch_desks

Change-Id: Ib0db7fcfe51f28f37fb5dd23f8b26e072871d1a7
parent 405a71b2
Loading
Loading
Loading
Loading
+6 −2
Original line number Original line Diff line number Diff line
@@ -1620,7 +1620,9 @@ public abstract class WMShellModule {
            @ShellMainThread Handler handler,
            @ShellMainThread Handler handler,
            ShellInit shellInit,
            ShellInit shellInit,
            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            RootTaskDisplayAreaOrganizer rootTaskDisplayAreaOrganizer,
            DesktopState desktopState
            DesktopState desktopState,
            Optional<DesksTransitionObserver> desksTransitionObserver,
            DeskSwitchTransitionHandler deskSwitchTransitionHandler
    ) {
    ) {
        if (!desktopState.canEnterDesktopMode()
        if (!desktopState.canEnterDesktopMode()
                && !desktopState.overridesShowAppHandle()) {
                && !desktopState.overridesShowAppHandle()) {
@@ -1640,7 +1642,9 @@ public abstract class WMShellModule {
                        interactionJankMonitor,
                        interactionJankMonitor,
                        handler,
                        handler,
                        shellInit,
                        shellInit,
                        rootTaskDisplayAreaOrganizer));
                        rootTaskDisplayAreaOrganizer,
                        desksTransitionObserver.get(),
                        deskSwitchTransitionHandler));
    }
    }


    @WMSingleton
    @WMSingleton
+86 −1
Original line number Original line Diff line number Diff line
@@ -37,6 +37,8 @@ import com.android.internal.protolog.ProtoLog
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_TASK_LIMIT_MINIMIZE
import com.android.wm.shell.desktopmode.DesktopModeTransitionTypes.TRANSIT_DESKTOP_MODE_TASK_LIMIT_MINIMIZE
import com.android.wm.shell.desktopmode.compatui.SystemModalsTransitionHandler
import com.android.wm.shell.desktopmode.compatui.SystemModalsTransitionHandler
import com.android.wm.shell.desktopmode.multidesks.DeskSwitchTransitionHandler
import com.android.wm.shell.desktopmode.multidesks.DesksTransitionObserver
import com.android.wm.shell.freeform.FreeformTaskTransitionHandler
import com.android.wm.shell.freeform.FreeformTaskTransitionHandler
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter
import com.android.wm.shell.freeform.FreeformTaskTransitionStarter
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
import com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE
@@ -63,6 +65,8 @@ class DesktopMixedTransitionHandler(
    @ShellMainThread private val handler: Handler,
    @ShellMainThread private val handler: Handler,
    shellInit: ShellInit,
    shellInit: ShellInit,
    private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
    private val rootTaskDisplayAreaOrganizer: RootTaskDisplayAreaOrganizer,
    private val desksTransitionObserver: DesksTransitionObserver,
    private val deskSwitchTransitionHandler: DeskSwitchTransitionHandler,
) : MixedTransitionHandler, FreeformTaskTransitionStarter {
) : MixedTransitionHandler, FreeformTaskTransitionStarter {


    init {
    init {
@@ -175,6 +179,17 @@ class DesktopMixedTransitionHandler(
        }
        }
    }
    }


    /** Starts a desk switch transition to be animated by this handler. */
    fun startSwitchDeskTransition(
        @WindowManager.TransitionType transitionType: Int,
        wct: WindowContainerTransaction,
    ): IBinder {
        return transitions.startTransition(transitionType, wct, /* handler= */ this).also {
            transition ->
            pendingMixedTransitions.add(PendingMixedTransition.SwitchDesk(transition = transition))
        }
    }

    /** Notifies this handler that there is a pending transition for it to handle. */
    /** Notifies this handler that there is a pending transition for it to handle. */
    fun addPendingMixedTransition(pendingMixedTransition: PendingMixedTransition) {
    fun addPendingMixedTransition(pendingMixedTransition: PendingMixedTransition) {
        pendingMixedTransitions.add(pendingMixedTransition)
        pendingMixedTransitions.add(pendingMixedTransition)
@@ -199,7 +214,13 @@ class DesktopMixedTransitionHandler(
    ): Boolean {
    ): Boolean {
        val pending =
        val pending =
            pendingMixedTransitions.find { pending -> pending.transition == transition }
            pendingMixedTransitions.find { pending -> pending.transition == transition }
                ?: return false.also { logV("No pending desktop transition") }
                ?: return handleNonPendingTransition(
                    transition,
                    info,
                    startTransaction,
                    finishTransaction,
                    finishCallback,
                )
        pendingMixedTransitions.remove(pending)
        pendingMixedTransitions.remove(pending)
        logV("Animating pending mixed transition: %s", pending)
        logV("Animating pending mixed transition: %s", pending)
        return when (pending) {
        return when (pending) {
@@ -229,6 +250,36 @@ class DesktopMixedTransitionHandler(
                    finishTransaction,
                    finishTransaction,
                    finishCallback,
                    finishCallback,
                )
                )
            is PendingMixedTransition.SwitchDesk ->
                animateSwitchDeskTransitionIfNeeded(
                    transition,
                    info,
                    startTransaction,
                    finishTransaction,
                    finishCallback,
                )
        }
    }

    private fun handleNonPendingTransition(
        transition: IBinder,
        info: TransitionInfo,
        startTransaction: SurfaceControl.Transaction,
        finishTransaction: SurfaceControl.Transaction,
        finishCallback: TransitionFinishCallback,
    ): Boolean {
        // This might be a core based transition that might cause a desk switch.
        return animateSwitchDeskTransitionIfNeeded(
                transition,
                info,
                startTransaction,
                finishTransaction,
                finishCallback,
            )
            .also { animated ->
                if (!animated) {
                    logV("No pending desktop transition")
                }
            }
            }
    }
    }


@@ -423,6 +474,38 @@ class DesktopMixedTransitionHandler(
        )
        )
    }
    }


    private fun animateSwitchDeskTransitionIfNeeded(
        transition: IBinder,
        info: TransitionInfo,
        startTransaction: SurfaceControl.Transaction,
        finishTransaction: SurfaceControl.Transaction,
        finishCallback: TransitionFinishCallback,
    ): Boolean {
        desksTransitionObserver.findDeskToDeskTransition(transition)?.let { deskToDesk ->
            with(deskToDesk) {
                logV(
                    "Animating mixed desk switch transition from desk=%s to desk%s",
                    fromDeskId,
                    toDeskId,
                )
                deskSwitchTransitionHandler.addPendingTransition(
                    transition,
                    userId,
                    displayId,
                    fromDeskId,
                    toDeskId,
                )
            }
        } ?: return false
        return deskSwitchTransitionHandler.startAnimation(
            transition,
            info,
            startTransaction,
            finishTransaction,
            finishCallback,
        )
    }

    override fun onTransitionConsumed(
    override fun onTransitionConsumed(
        transition: IBinder,
        transition: IBinder,
        aborted: Boolean,
        aborted: Boolean,
@@ -580,6 +663,8 @@ class DesktopMixedTransitionHandler(
            val minimizingTask: Int,
            val minimizingTask: Int,
            val isLastTask: Boolean,
            val isLastTask: Boolean,
        ) : PendingMixedTransition()
        ) : PendingMixedTransition()

        data class SwitchDesk(override val transition: IBinder) : PendingMixedTransition()
    }
    }


    private fun logV(msg: String, vararg arguments: Any?) {
    private fun logV(msg: String, vararg arguments: Any?) {
+7 −1
Original line number Original line Diff line number Diff line
@@ -2265,7 +2265,13 @@ class DesktopTasksController(
                )
                )
            }
            }
        val t =
        val t =
            if (remoteTransition == null) {
            // If a desk is active and we are activating a new desk, start switch desk transition.
            if (repository.isAnyDeskActive(displayId) && shouldActivateDesk) {
                desktopMixedTransitionHandler.startSwitchDeskTransition(
                    transitionType = transitionType,
                    wct = launchTransaction,
                )
            } else if (remoteTransition == null) {
                logV("startLaunchTransition -- no remoteTransition -- wct = $launchTransaction")
                logV("startLaunchTransition -- no remoteTransition -- wct = $launchTransaction")
                desktopMixedTransitionHandler.startLaunchTransition(
                desktopMixedTransitionHandler.startLaunchTransition(
                    transitionType = transitionType,
                    transitionType = transitionType,
+22 −0
Original line number Original line Diff line number Diff line
@@ -67,6 +67,23 @@ class DeskSwitchTransitionHandler(


    private val pendingTransitions = mutableMapOf<IBinder, PendingSwitch>()
    private val pendingTransitions = mutableMapOf<IBinder, PendingSwitch>()


    /** Adds a pending transition that will switch between two desks in the same display. */
    fun addPendingTransition(
        transition: IBinder,
        userId: Int,
        displayId: Int,
        fromDeskId: Int,
        toDeskId: Int,
    ) {
        pendingTransitions[transition] =
            PendingSwitch(
                displayId = displayId,
                userId = userId,
                fromDeskId = fromDeskId,
                toDeskId = toDeskId,
            )
    }

    /** Starts a transition to switch between two desks in the same display. */
    /** Starts a transition to switch between two desks in the same display. */
    fun startTransition(
    fun startTransition(
        wct: WindowContainerTransaction,
        wct: WindowContainerTransaction,
@@ -268,6 +285,11 @@ class DeskSwitchTransitionHandler(
                if (animFraction >= FADE_IN_START_FRACTION && !isFadeInStarted) {
                if (animFraction >= FADE_IN_START_FRACTION && !isFadeInStarted) {
                    isFadeInStarted = true
                    isFadeInStarted = true
                    val fadeInTx = transactionProvider()
                    val fadeInTx = transactionProvider()
                    // Set the desk alpha to 1 so its children can be shown
                    fadeInTx.apply {
                        changes.toDesk?.leash?.let { leash -> setAlpha(leash, 1f) }
                        apply()
                    }
                    PhysicsAnimator.getInstance(
                    PhysicsAnimator.getInstance(
                            DeskSwitchAnimationUtils.DeskOpacityChange(
                            DeskSwitchAnimationUtils.DeskOpacityChange(
                                leashes = changes.toDeskTasks.map { it.leash },
                                leashes = changes.toDeskTasks.map { it.leash },
+99 −18
Original line number Original line Diff line number Diff line
@@ -56,7 +56,13 @@ class DesksTransitionObserver(
    @ShellMainThread private val mainScope: CoroutineScope,
    @ShellMainThread private val mainScope: CoroutineScope,
    private val desktopModeEventLogger: DesktopModeEventLogger,
    private val desktopModeEventLogger: DesktopModeEventLogger,
) {
) {
    // Tracks the desk transitions used to keep track of the desk state. This is usually removed
    // when the transition is ready. This map represents what a single shell transition is causing
    // in terms of the desks state.
    private val deskTransitions = mutableMapOf<IBinder, MutableSet<DeskTransition>>()
    private val deskTransitions = mutableMapOf<IBinder, MutableSet<DeskTransition>>()
    // Tracks the desk transitions that are ongoing. This won't be removed until transition is
    // finished.
    private val runningDesksTransitions = mutableMapOf<IBinder, MutableSet<DeskTransition>>()


    /** Adds a pending desk transition to be tracked. */
    /** Adds a pending desk transition to be tracked. */
    fun addPendingTransition(transition: DeskTransition) {
    fun addPendingTransition(transition: DeskTransition) {
@@ -77,14 +83,16 @@ class DesksTransitionObserver(
            name = "DesksTransitionObserver#onTransitionReady",
            name = "DesksTransitionObserver#onTransitionReady",
        ) {
        ) {
            if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
            if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
            val deskTransitions = deskTransitions.remove(transition)
            val readyDeskTransitions = deskTransitions.remove(transition)
            deskTransitions?.forEach { deskTransition ->
            readyDeskTransitions?.forEach { readyDeskTransition ->
                handleDeskTransition(info, deskTransition)
                handleDeskTransition(info, readyDeskTransition)
            }
            }
            if (deskTransitions.isNullOrEmpty()) {
            if (readyDeskTransitions.isNullOrEmpty()) {
                // A desk transition could also occur without shell having started it or
                // A desk transition could also occur without shell having started it or
                // intercepting it, check for that here in case launch roots need to be updated.
                // intercepting it, check for that here in case launch roots need to be updated.
                handleIndependentDeskTransitionIfNeeded(info)
                handleIndependentDeskTransitionIfNeeded(info)
            } else {
                runningDesksTransitions[transition] = readyDeskTransitions
            }
            }
        }
        }


@@ -94,12 +102,19 @@ class DesksTransitionObserver(
     */
     */
    fun onTransitionMerged(merged: IBinder, playing: IBinder) {
    fun onTransitionMerged(merged: IBinder, playing: IBinder) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
        val transitions = deskTransitions.remove(merged) ?: return
        deskTransitions.remove(merged)?.let { transitions ->
            deskTransitions[playing] =
            deskTransitions[playing] =
                transitions
                transitions
                    .map { deskTransition -> deskTransition.copyWithToken(token = playing) }
                    .map { deskTransition -> deskTransition.copyWithToken(token = playing) }
                    .toMutableSet()
                    .toMutableSet()
        }
        }
        runningDesksTransitions.remove(merged)?.let { transitions ->
            runningDesksTransitions[playing] =
                transitions
                    .map { deskTransition -> deskTransition.copyWithToken(token = playing) }
                    .toMutableSet()
        }
    }


    /**
    /**
     * Called when any transition finishes, which may include transitions not tracked by this
     * Called when any transition finishes, which may include transitions not tracked by this
@@ -112,8 +127,9 @@ class DesksTransitionObserver(
     */
     */
    fun onTransitionFinished(transition: IBinder) {
    fun onTransitionFinished(transition: IBinder) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
        val deskTransitions = deskTransitions.remove(transition) ?: return
        runningDesksTransitions.remove(transition)
        deskTransitions.forEach { deskTransition ->
        deskTransitions.remove(transition)?.let { finishedDeskTransitions ->
            finishedDeskTransitions.forEach { deskTransition ->
                if (deskTransition is DeskTransition.DeactivateDesk) {
                if (deskTransition is DeskTransition.DeactivateDesk) {
                    handleDeactivateDeskTransition(null, deskTransition)
                    handleDeactivateDeskTransition(null, deskTransition)
                } else {
                } else {
@@ -124,6 +140,7 @@ class DesksTransitionObserver(
                }
                }
            }
            }
        }
        }
    }


    private fun handleDeskTransition(info: TransitionInfo, deskTransition: DeskTransition) {
    private fun handleDeskTransition(info: TransitionInfo, deskTransition: DeskTransition) {
        logD("Desk transition ready: %s", deskTransition)
        logD("Desk transition ready: %s", deskTransition)
@@ -596,6 +613,70 @@ class DesksTransitionObserver(
        return UserSwitch(oldUserId = currentUserId, newUserId = newUserId)
        return UserSwitch(oldUserId = currentUserId, newUserId = newUserId)
    }
    }


    /**
     * Given a [transition] finds whether it's a desk to desk transition in the same display.
     *
     * A user switch where one users desk deactivates and another user's desk activates does not
     * count as a desk to desk transition.
     *
     * @return A [DeskToDeskTransition] if a valid desk switch is found. Otherwise, returns null.
     */
    fun findDeskToDeskTransition(transition: IBinder): DeskToDeskTransition? {
        val running = runningDesksTransitions[transition] ?: return null

        // Check if it's a user switch where same transition activating one user and deactivating
        // another.
        if (running.map { it.userId }.distinct().size > 1) return null
        val potentialDeskSwitchTransitionsByDisplayId =
            running
                .filter { transition ->
                    transition is DeskTransition.ActivateDesk ||
                        transition is DeskTransition.ActivateDeskWithTask ||
                        transition is DeskTransition.DeactivateDesk
                }
                .groupBy(
                    { transition ->
                        when (transition) {
                            is DeskTransition.ActivateDesk -> transition.displayId
                            is DeskTransition.ActivateDeskWithTask -> transition.displayId
                            is DeskTransition.DeactivateDesk -> transition.displayId
                            else -> error("Unexpected transition type: $transition")
                        }
                    },
                    { it },
                )
        for ((displayId, transitions) in potentialDeskSwitchTransitionsByDisplayId.entries) {
            val fromDesk =
                transitions.firstOrNull { it is DeskTransition.DeactivateDesk }
                    as? DeskTransition.DeactivateDesk ?: continue
            val toDesk =
                transitions.firstOrNull {
                    it is DeskTransition.ActivateDeskWithTask || it is DeskTransition.ActivateDesk
                } ?: continue
            val fromDeskId = fromDesk.deskId
            val toDeskId =
                when (toDesk) {
                    is DeskTransition.ActivateDesk -> toDesk.deskId
                    is DeskTransition.ActivateDeskWithTask -> toDesk.deskId
                    else -> error("Unexpected transition type: $toDesk")
                }
            if (fromDeskId == toDeskId) continue
            return DeskToDeskTransition(displayId, fromDesk.userId, fromDeskId, toDeskId)
        }
        return null
    }

    /**
     * Represents a transition between two different desks. [fromDeskId] is never the same as the
     * [toDeskId].
     */
    data class DeskToDeskTransition(
        val displayId: Int,
        val userId: Int,
        val fromDeskId: Int,
        val toDeskId: Int,
    )

    data class UserSwitch(val oldUserId: Int, val newUserId: Int)
    data class UserSwitch(val oldUserId: Int, val newUserId: Int)


    private fun TransitionInfo.isRecentsType() =
    private fun TransitionInfo.isRecentsType() =
Loading