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

Commit 0bd76ee1 authored by Jorge Gil's avatar Jorge Gil
Browse files

Desks: Deactivate and clean up desk on exit using recents transition

Uses the already registed RecentsMixedHandler to let
DesktopTasksController handle the recents' finish. When the finish is
not returning to the app/desk (e.g. going Home), it appends the
desktop cleanup ops to the finishWCT.

This requires changing DesksTransitionObserver to handle merged
transitions and finished transitions too:
- Merges, because recents transitions finished with a book-end
  transition means the deactivation updates should happen when the
  book-end one is ready
- Finishes, because when there's no book-end transition, by the time the
  deactivation changes are added to the finishWCT and starts getting
  tracked by the observer, the transition has already gone through
  #onTransitionReady, so double-checking in #onTransitionFinished
  ensures the changes are reflected in the DesktopRepository.

Flag: com.android.window.flags.enable_multiple_desktops_backend
Bug: 402306937
Bug: 401023534
Test: enter desktop, swipe-to-home - verify new app launches from
taskbar open in fullscreen.
Test: enter desktop, swipe-to-overview, then swipe-to-home - verify new
launches from taskbar open in fullscreen.
Test: enter desktop, swipe-to-overview, select fullscreen tile - verify
new launches from taskbar open in fullscreen.
Test: enter desktop, quickswitch to fullscreen - verify new launches
from taskbar open in fullscreen

Change-Id: I34b9a581db3af5e160e32b005d35742089f55cb7
parent 25ef3aab
Loading
Loading
Loading
Loading
+36 −5
Original line number Diff line number Diff line
@@ -465,6 +465,30 @@ class DesktopTasksController(
        return isFreeformDisplay
    }

    /** Called when the recents transition that started while in desktop is finishing. */
    fun onRecentsInDesktopAnimationFinishing(
        transition: IBinder,
        finishWct: WindowContainerTransaction,
        returnToApp: Boolean,
    ) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
        logV("onRecentsInDesktopAnimationFinishing returnToApp=%b", returnToApp)
        if (returnToApp) return
        // Home/Recents only exists in the default display.
        val activeDesk = taskRepository.getActiveDeskId(DEFAULT_DISPLAY) ?: return
        // Not going back to the active desk, deactivate it.
        val runOnTransitStart =
            performDesktopExitCleanUp(
                wct = finishWct,
                deskId = activeDesk,
                displayId = DEFAULT_DISPLAY,
                willExitDesktop = true,
                shouldEndUpAtHome = true,
                fromRecentsTransition = true,
            )
        runOnTransitStart?.invoke(transition)
    }

    /** Creates a new desk in the given display. */
    fun createDesk(displayId: Int) {
        if (displayId == Display.INVALID_DISPLAY) {
@@ -1937,17 +1961,24 @@ class DesktopTasksController(
        displayId: Int,
        willExitDesktop: Boolean,
        shouldEndUpAtHome: Boolean = true,
        fromRecentsTransition: Boolean = false,
    ): RunOnTransitStart? {
        if (!willExitDesktop) return null
        desktopModeEnterExitTransitionListener?.onExitDesktopModeTransitionStarted(
            FULLSCREEN_ANIMATION_DURATION
        )
        // No need to clean up the wallpaper / reorder home when coming from a recents transition.
        if (
            !fromRecentsTransition ||
                !DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue
        ) {
            removeWallpaperActivity(wct, displayId)
            if (shouldEndUpAtHome) {
            // If the transition should end up with user going to home, launch home with a pending
            // intent.
                // If the transition should end up with user going to home, launch home with a
                // pending intent.
                addLaunchHomePendingIntent(wct, displayId)
            }
        }
        return prepareDeskDeactivationIfNeeded(wct, deskId)
    }

+17 −6
Original line number Diff line number Diff line
@@ -18,9 +18,12 @@ package com.android.wm.shell.desktopmode.multidesks
import android.os.IBinder

/** Represents shell-started transitions involving desks. */
sealed class DeskTransition {
sealed interface DeskTransition {
    /** The transition token. */
    abstract val token: IBinder
    val token: IBinder

    /** Returns a copy of this desk transition with a new transition token. */
    fun copyWithToken(token: IBinder): DeskTransition

    /** A transition to remove a desk and its tasks from a display. */
    data class RemoveDesk(
@@ -29,11 +32,15 @@ sealed class DeskTransition {
        val deskId: Int,
        val tasks: Set<Int>,
        val onDeskRemovedListener: OnDeskRemovedListener?,
    ) : DeskTransition()
    ) : DeskTransition {
        override fun copyWithToken(token: IBinder): DeskTransition = copy(token)
    }

    /** A transition to activate a desk in its display. */
    data class ActivateDesk(override val token: IBinder, val displayId: Int, val deskId: Int) :
        DeskTransition()
        DeskTransition {
        override fun copyWithToken(token: IBinder): DeskTransition = copy(token)
    }

    /** A transition to activate a desk by moving an outside task to it. */
    data class ActiveDeskWithTask(
@@ -41,8 +48,12 @@ sealed class DeskTransition {
        val displayId: Int,
        val deskId: Int,
        val enterTaskId: Int,
    ) : DeskTransition()
    ) : DeskTransition {
        override fun copyWithToken(token: IBinder): DeskTransition = copy(token)
    }

    /** A transition to deactivate a desk. */
    data class DeactivateDesk(override val token: IBinder, val deskId: Int) : DeskTransition()
    data class DeactivateDesk(override val token: IBinder, val deskId: Int) : DeskTransition {
        override fun copyWithToken(token: IBinder): DeskTransition = copy(token)
    }
}
+78 −27
Original line number Diff line number Diff line
@@ -39,6 +39,7 @@ class DesksTransitionObserver(
        val transitions = deskTransitions[transition.token] ?: mutableSetOf()
        transitions += transition
        deskTransitions[transition.token] = transitions
        logD("Added pending desk transition: %s", transition)
    }

    /**
@@ -51,6 +52,43 @@ class DesksTransitionObserver(
        deskTransitions.forEach { deskTransition -> handleDeskTransition(info, deskTransition) }
    }

    /**
     * Called when a transition is merged with another transition, which may include transitions not
     * tracked by this observer.
     */
    fun onTransitionMerged(merged: IBinder, playing: IBinder) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
        val transitions = deskTransitions.remove(merged) ?: return
        deskTransitions[playing] =
            transitions
                .map { deskTransition -> deskTransition.copyWithToken(token = playing) }
                .toMutableSet()
    }

    /**
     * Called when any transition finishes, which may include transitions not tracked by this
     * observer.
     *
     * Most [DeskTransition]s are not handled here because [onTransitionReady] handles them and
     * removes them from the map. However, there can be cases where the transition was added after
     * [onTransitionReady] had already been called and they need to be handled here, such as the
     * swipe-to-home recents transition when there is no book-end transition.
     */
    fun onTransitionFinished(transition: IBinder) {
        if (!DesktopExperienceFlags.ENABLE_MULTIPLE_DESKTOPS_BACKEND.isTrue) return
        val deskTransitions = deskTransitions.remove(transition) ?: return
        deskTransitions.forEach { deskTransition ->
            if (deskTransition is DeskTransition.DeactivateDesk) {
                handleDeactivateDeskTransition(null, deskTransition)
            } else {
                logW(
                    "Unexpected desk transition finished without being handled: %s",
                    deskTransition,
                )
            }
        }
    }

    private fun handleDeskTransition(info: TransitionInfo, deskTransition: DeskTransition) {
        logD("Desk transition ready: %s", deskTransition)
        val desktopRepository = desktopUserRepositories.current
@@ -102,12 +140,23 @@ class DesksTransitionObserver(
                    )
                }
            }
            is DeskTransition.DeactivateDesk -> {
                var visibleDeactivation = false
                for (change in info.changes) {
            is DeskTransition.DeactivateDesk -> handleDeactivateDeskTransition(info, deskTransition)
        }
    }

    private fun handleDeactivateDeskTransition(
        info: TransitionInfo?,
        deskTransition: DeskTransition.DeactivateDesk,
    ) {
        logD("handleDeactivateDeskTransition: %s", deskTransition)
        val desktopRepository = desktopUserRepositories.current
        var deskChangeFound = false

        val changes = info?.changes ?: emptyList()
        for (change in changes) {
            val isDeskChange = desksOrganizer.isDeskChange(change, deskTransition.deskId)
            if (isDeskChange) {
                        visibleDeactivation = true
                deskChangeFound = true
                continue
            }
            val taskId = change.taskInfo?.taskId ?: continue
@@ -125,18 +174,20 @@ class DesksTransitionObserver(
        // deactivated. Some interactions, such as the desk deactivating because it's
        // occluded by a fullscreen task result in a transition change, but others, such
        // as transitioning from an empty desk to home may not.
                if (!visibleDeactivation) {
        if (!deskChangeFound) {
            logD("Deactivating desk without transition change")
        }
        desktopRepository.setDeskInactive(deskId = deskTransition.deskId)
    }
        }
    }

    private fun logD(msg: String, vararg arguments: Any?) {
        ProtoLog.d(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
    }

    private fun logW(msg: String, vararg arguments: Any?) {
        ProtoLog.w(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
    }

    private companion object {
        private const val TAG = "DesksTransitionObserver"
    }
+2 −0
Original line number Diff line number Diff line
@@ -207,6 +207,7 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs

    @Override
    public void onTransitionMerged(@NonNull IBinder merged, @NonNull IBinder playing) {
        mDesksTransitionObserver.ifPresent(o -> o.onTransitionMerged(merged, playing));
        if (DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue()) {
            // TODO(b/367268953): Remove when DesktopTaskListener is introduced.
            mDesktopImmersiveController.ifPresent(h -> h.onTransitionMerged(merged, playing));
@@ -232,6 +233,7 @@ public class FreeformTaskTransitionObserver implements Transitions.TransitionObs

    @Override
    public void onTransitionFinished(@NonNull IBinder transition, boolean aborted) {
        mDesksTransitionObserver.ifPresent(o -> o.onTransitionFinished(transition));
        if (DesktopModeFlags.ENABLE_FULLY_IMMERSIVE_IN_DESKTOP.isTrue()) {
            // TODO(b/367268953): Remove when DesktopTaskListener is introduced.
            mDesktopImmersiveController.ifPresent(h -> h.onTransitionFinished(transition, aborted));
+3 −0
Original line number Diff line number Diff line
@@ -394,6 +394,9 @@ public class DefaultMixedHandler implements MixedTransitionHandler,
                if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_SPLIT) {
                    ((RecentsMixedTransition) mixed).onAnimateRecentsDuringSplitFinishing(
                            returnToApp, finishWct, finishT);
                } else if (mixed.mType == MixedTransition.TYPE_RECENTS_DURING_DESKTOP) {
                    ((RecentsMixedTransition) mixed).onAnimateRecentsDuringDesktopFinishing(
                            returnToApp, finishWct);
                }
            }
        }
Loading