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

Commit e1544cee authored by Treehugger Robot's avatar Treehugger Robot Committed by Android (Google) Code Review
Browse files

Merge "Do not force-exit desktop immersive during recents transition" into main

parents bc2e574f fcc21d7a
Loading
Loading
Loading
Loading
+23 −7
Original line number Diff line number Diff line
@@ -119,7 +119,8 @@ class DesktopImmersiveController(
        )
    }

    fun moveTaskToNonImmersive(taskInfo: RunningTaskInfo) {
    /** Starts a transition to move an immersive task out of immersive. */
    fun moveTaskToNonImmersive(taskInfo: RunningTaskInfo, reason: ExitReason) {
        if (inProgress) {
            logV(
                "Cannot start exit because transition(s) already in progress: %s",
@@ -131,7 +132,7 @@ class DesktopImmersiveController(
        val wct = WindowContainerTransaction().apply {
            setBounds(taskInfo.token, getExitDestinationBounds(taskInfo))
        }
        logV("Moving task ${taskInfo.taskId} out of immersive mode")
        logV("Moving task %d out of immersive mode, reason: %s", taskInfo.taskId, reason)
        val transition = transitions.startTransition(TRANSIT_CHANGE, wct, /* handler= */ this)
        state = TransitionState(
            transition = transition,
@@ -151,10 +152,11 @@ class DesktopImmersiveController(
    fun exitImmersiveIfApplicable(
        transition: IBinder,
        wct: WindowContainerTransaction,
        displayId: Int
        displayId: Int,
        reason: ExitReason,
    ) {
        if (!Flags.enableFullyImmersiveInDesktop()) return
        val result = exitImmersiveIfApplicable(wct, displayId)
        val result = exitImmersiveIfApplicable(wct, displayId, excludeTaskId = null, reason)
        result.asExit()?.runOnTransitionStart?.invoke(transition)
    }

@@ -170,6 +172,7 @@ class DesktopImmersiveController(
        wct: WindowContainerTransaction,
        displayId: Int,
        excludeTaskId: Int? = null,
        reason: ExitReason,
    ): ExitResult {
        if (!Flags.enableFullyImmersiveInDesktop()) return ExitResult.NoExit
        val immersiveTask = desktopRepository.getTaskInFullImmersiveState(displayId)
@@ -179,7 +182,10 @@ class DesktopImmersiveController(
        }
        val taskInfo = shellTaskOrganizer.getRunningTaskInfo(immersiveTask)
            ?: return ExitResult.NoExit
        logV("Appending immersive exit for task: $immersiveTask in display: $displayId")
        logV(
            "Appending immersive exit for task: %d in display: %d for reason: %s",
            immersiveTask, displayId, reason
        )
        wct.setBounds(taskInfo.token, getExitDestinationBounds(taskInfo))
        return ExitResult.Exit(
            exitingTask = immersiveTask,
@@ -198,14 +204,15 @@ class DesktopImmersiveController(
     */
    fun exitImmersiveIfApplicable(
        wct: WindowContainerTransaction,
        taskInfo: RunningTaskInfo
        taskInfo: RunningTaskInfo,
        reason: ExitReason,
    ): ExitResult {
        if (!Flags.enableFullyImmersiveInDesktop()) return ExitResult.NoExit
        if (desktopRepository.isTaskInFullImmersiveState(taskInfo.taskId)) {
            // A full immersive task is being minimized, make sure the immersive state is broken
            // (i.e. resize back to max bounds).
            wct.setBounds(taskInfo.token, getExitDestinationBounds(taskInfo))
            logV("Appending immersive exit for task: ${taskInfo.taskId}")
            logV("Appending immersive exit for task: %d for reason: %s", taskInfo.taskId, reason)
            return ExitResult.Exit(
                exitingTask = taskInfo.taskId,
                runOnTransitionStart = { transition ->
@@ -550,6 +557,15 @@ class DesktopImmersiveController(
        ENTER, EXIT
    }

    /** The reason for moving the task out of desktop immersive mode. */
    enum class ExitReason {
        APP_NOT_IMMERSIVE, // The app stopped requesting immersive treatment.
        USER_INTERACTION, // Explicit user intent request, e.g. a button click.
        TASK_LAUNCH, // A task launched/moved on top of the immersive task.
        MINIMIZED, // The immersive task was minimized.
        CLOSED, // The immersive task was closed.
    }

    private fun logV(msg: String, vararg arguments: Any?) {
        ProtoLog.v(WM_SHELL_DESKTOP_MODE, "%s: $msg", TAG, *arguments)
    }
+60 −17
Original line number Diff line number Diff line
@@ -70,7 +70,6 @@ import com.android.internal.jank.InteractionJankMonitor
import com.android.internal.policy.ScreenDecorationsUtils
import com.android.internal.protolog.ProtoLog
import com.android.window.flags.Flags
import com.android.window.flags.Flags.enableMoveToNextDisplayShortcut
import com.android.wm.shell.Flags.enableFlexibleSplit
import com.android.wm.shell.R
import com.android.wm.shell.RootTaskDisplayAreaOrganizer
@@ -133,6 +132,8 @@ import com.android.wm.shell.desktopmode.DesktopModeEventLogger.Companion.ResizeT
import com.android.wm.shell.desktopmode.DragToDesktopTransitionHandler.Companion.DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS
import com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION
import com.android.wm.shell.desktopmode.ExitDesktopTaskTransitionHandler.FULLSCREEN_ANIMATION_DURATION
import com.android.wm.shell.recents.RecentsTransitionStateListener.RecentsTransitionState
import com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING

/** Handles moving tasks in and out of desktop */
class DesktopTasksController(
@@ -209,7 +210,9 @@ class DesktopTasksController(
    val draggingTaskId
        get() = dragToDesktopTransitionHandler.draggingTaskId

    private var recentsAnimationRunning = false
    @RecentsTransitionState
    private var recentsTransitionState = TRANSITION_STATE_NOT_RUNNING

    private lateinit var splitScreenController: SplitScreenController
    lateinit var freeformTaskTransitionStarter: FreeformTaskTransitionStarter
    // Launch cookie used to identify a drag and drop transition to fullscreen after it has begun.
@@ -238,10 +241,15 @@ class DesktopTasksController(
        dragToDesktopTransitionHandler.dragToDesktopStateListener = dragToDesktopStateListener
        recentsTransitionHandler.addTransitionStateListener(
            object : RecentsTransitionStateListener {
                override fun onAnimationStateChanged(running: Boolean) {
                    logV("Recents animation state changed running=%b", running)
                    recentsAnimationRunning = running
                    desktopTilingDecorViewModel.onOverviewAnimationStateChange(running)
                override fun onTransitionStateChanged(@RecentsTransitionState state: Int) {
                    logV(
                        "Recents transition state changed: %s",
                        RecentsTransitionStateListener.stateToString(state)
                    )
                    recentsTransitionState = state
                    desktopTilingDecorViewModel.onOverviewAnimationStateChange(
                        RecentsTransitionStateListener.isAnimating(state)
                    )
                }
            }
        )
@@ -381,6 +389,7 @@ class DesktopTasksController(
            wct = wct,
            displayId = DEFAULT_DISPLAY,
            excludeTaskId = taskId,
            reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
        )
        wct.startTask(
            taskId,
@@ -413,6 +422,7 @@ class DesktopTasksController(
            wct = wct,
            displayId = task.displayId,
            excludeTaskId = task.taskId,
            reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
        )
        // Bring other apps to front first
        val taskIdToMinimize =
@@ -460,7 +470,11 @@ class DesktopTasksController(
            bringDesktopAppsToFrontBeforeShowingNewTask(taskInfo.displayId, wct, taskInfo.taskId)
        addMoveToDesktopChanges(wct, taskInfo)
        val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(
            wct, taskInfo.displayId)
            wct = wct,
            displayId = taskInfo.displayId,
            excludeTaskId = null,
            reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH
        )
        val transition = dragToDesktopTransitionHandler.finishDragToDesktopTransition(wct)
        desktopModeEnterExitTransitionListener?.onEnterDesktopModeTransitionStarted(
            DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS.toInt()
@@ -508,8 +522,11 @@ class DesktopTasksController(
                taskId
            )
        )
        return desktopImmersiveController.exitImmersiveIfApplicable(wct, taskInfo).asExit()
            ?.runOnTransitionStart
        return desktopImmersiveController.exitImmersiveIfApplicable(
            wct = wct,
            taskInfo = taskInfo,
            reason = DesktopImmersiveController.ExitReason.CLOSED
        ).asExit()?.runOnTransitionStart
    }

    fun minimizeTask(taskInfo: RunningTaskInfo) {
@@ -518,7 +535,11 @@ class DesktopTasksController(
        val wct = WindowContainerTransaction()
        performDesktopExitCleanupIfNeeded(taskId, wct)
        // Notify immersive handler as it might need to exit immersive state.
        val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(wct, taskInfo)
        val exitResult = desktopImmersiveController.exitImmersiveIfApplicable(
            wct = wct,
            taskInfo = taskInfo,
            reason = DesktopImmersiveController.ExitReason.MINIMIZED
        )

        wct.reorder(taskInfo.token, false)
        val transition = freeformTaskTransitionStarter.startMinimizedModeTransition(wct)
@@ -675,6 +696,7 @@ class DesktopTasksController(
            wct = wct,
            displayId = displayId,
            excludeTaskId = launchingTaskId,
            reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
        )
        if (remoteTransition == null) {
            val t = desktopMixedTransitionHandler.startLaunchTransition(
@@ -766,7 +788,10 @@ class DesktopTasksController(
    /** Moves a task in/out of full immersive state within the desktop. */
    fun toggleDesktopTaskFullImmersiveState(taskInfo: RunningTaskInfo) {
        if (taskRepository.isTaskInFullImmersiveState(taskInfo.taskId)) {
            exitDesktopTaskFromFullImmersive(taskInfo)
            exitDesktopTaskFromFullImmersive(
                taskInfo,
                DesktopImmersiveController.ExitReason.USER_INTERACTION,
            )
        } else {
            moveDesktopTaskToFullImmersive(taskInfo)
        }
@@ -777,9 +802,12 @@ class DesktopTasksController(
        desktopImmersiveController.moveTaskToImmersive(taskInfo)
    }

    private fun exitDesktopTaskFromFullImmersive(taskInfo: RunningTaskInfo) {
    private fun exitDesktopTaskFromFullImmersive(
        taskInfo: RunningTaskInfo,
        reason: DesktopImmersiveController.ExitReason,
    ) {
        check(taskInfo.isFreeform) { "Task must already be in freeform" }
        desktopImmersiveController.moveTaskToNonImmersive(taskInfo)
        desktopImmersiveController.moveTaskToNonImmersive(taskInfo, reason)
    }

    /**
@@ -1292,6 +1320,8 @@ class DesktopTasksController(
        // Check if we should skip handling this transition
        var reason = ""
        val triggerTask = request.triggerTask
        val recentsAnimationRunning =
            RecentsTransitionStateListener.isAnimating(recentsTransitionState)
        var shouldHandleMidRecentsFreeformLaunch =
            recentsAnimationRunning && isFreeformRelaunch(triggerTask, request)
        val isDragAndDropFullscreenTransition = taskContainsDragAndDropCookie(triggerTask)
@@ -1479,6 +1509,7 @@ class DesktopTasksController(
                    wct = wct,
                    displayId = callingTask.displayId,
                    excludeTaskId = requestedTaskId,
                    reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
                )
            val transition = transitions.startTransition(TRANSIT_OPEN, wct, null)
            taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
@@ -1628,7 +1659,12 @@ class DesktopTasksController(
        }
        // Desktop Mode is showing and we're launching a new Task:
        // 1) Exit immersive if needed.
        desktopImmersiveController.exitImmersiveIfApplicable(transition, wct, task.displayId)
        desktopImmersiveController.exitImmersiveIfApplicable(
            transition = transition,
            wct = wct,
            displayId = task.displayId,
            reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH,
        )
        // 2) minimize a Task if needed.
        val taskIdToMinimize = addAndGetMinimizeChanges(task.displayId, wct, task.taskId)
        addPendingAppLaunchTransition(transition, task.taskId, taskIdToMinimize)
@@ -1665,7 +1701,10 @@ class DesktopTasksController(
                taskIdToMinimize?.let { addPendingMinimizeTransition(transition, it) }
                addPendingAppLaunchTransition(transition, task.taskId, taskIdToMinimize)
                desktopImmersiveController.exitImmersiveIfApplicable(
                    transition, wct, task.displayId
                    transition,
                    wct,
                    task.displayId,
                    reason = DesktopImmersiveController.ExitReason.TASK_LAUNCH
                )
            }
        } else if (taskRepository.isActiveTask(task.taskId)) {
@@ -2282,9 +2321,13 @@ class DesktopTasksController(
        if (!Flags.enableFullyImmersiveInDesktop()) return
        val inImmersive = taskRepository.isTaskInFullImmersiveState(taskInfo.taskId)
        val requestingImmersive = taskInfo.requestingImmersive
        if (inImmersive && !requestingImmersive) {
        if (inImmersive && !requestingImmersive
            && !RecentsTransitionStateListener.isRunning(recentsTransitionState)) {
            // Exit immersive if the app is no longer requesting it.
            exitDesktopTaskFromFullImmersive(taskInfo)
            exitDesktopTaskFromFullImmersive(
                taskInfo,
                DesktopImmersiveController.ExitReason.APP_NOT_IMMERSIVE
            )
        }
    }

+4 −2
Original line number Diff line number Diff line
@@ -665,8 +665,10 @@ public class RecentTasksController implements TaskStackListenerCallback,
                }
                mTransitionHandler.addTransitionStateListener(new RecentsTransitionStateListener() {
                    @Override
                    public void onAnimationStateChanged(boolean running) {
                        executor.execute(() -> listener.accept(running));
                    public void onTransitionStateChanged(@RecentsTransitionState int state) {
                        executor.execute(() -> {
                            listener.accept(RecentsTransitionStateListener.isAnimating(state));
                        });
                    }
                });
            });
+15 −6
Original line number Diff line number Diff line
@@ -32,6 +32,9 @@ import static android.view.WindowManager.TRANSIT_TO_FRONT;
import static android.window.TransitionInfo.FLAG_MOVED_TO_TOP;
import static android.window.TransitionInfo.FLAG_TRANSLUCENT;

import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_ANIMATING;
import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_NOT_RUNNING;
import static com.android.wm.shell.recents.RecentsTransitionStateListener.TRANSITION_STATE_REQUESTED;
import static com.android.wm.shell.shared.ShellSharedConstants.KEY_EXTRA_SHELL_CAN_HAND_OFF_ANIMATION;
import static com.android.wm.shell.shared.split.SplitBounds.KEY_EXTRA_SPLIT_BOUNDS;
import static com.android.wm.shell.transition.Transitions.TRANSIT_END_RECENTS_TRANSITION;
@@ -166,13 +169,19 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
        // only care about latest one.
        mAnimApp = appThread;

        for (int i = 0; i < mStateListeners.size(); i++) {
            mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_REQUESTED);
        }
        // TODO(b/366021931): Formalize this later
        final boolean isSyntheticRequest = options.containsKey("is_synthetic_recents_transition");
        final boolean isSyntheticRequest = options.getBoolean(
                "is_synthetic_recents_transition", /* defaultValue= */ false);
        final IBinder transition;
        if (isSyntheticRequest) {
            return startSyntheticRecentsTransition(listener);
            transition = startSyntheticRecentsTransition(listener);
        } else {
            return startRealRecentsTransition(intent, fillIn, options, listener);
            transition = startRealRecentsTransition(intent, fillIn, options, listener);
        }
        return transition;
    }

    /**
@@ -542,7 +551,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
            mPendingFinishTransition = null;
            mControllers.remove(this);
            for (int i = 0; i < mStateListeners.size(); i++) {
                mStateListeners.get(i).onAnimationStateChanged(false);
                mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_NOT_RUNNING);
            }
        }

@@ -578,7 +587,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
                        new RemoteAnimationTarget[0],
                        new Rect(0, 0, 0, 0), new Rect(), new Bundle());
                for (int i = 0; i < mStateListeners.size(); i++) {
                    mStateListeners.get(i).onAnimationStateChanged(true);
                    mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_ANIMATING);
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Error starting recents animation", e);
@@ -809,7 +818,7 @@ public class RecentsTransitionHandler implements Transitions.TransitionHandler,
                        wallpapers.toArray(new RemoteAnimationTarget[wallpapers.size()]),
                        new Rect(0, 0, 0, 0), new Rect(), b);
                for (int i = 0; i < mStateListeners.size(); i++) {
                    mStateListeners.get(i).onAnimationStateChanged(true);
                    mStateListeners.get(i).onTransitionStateChanged(TRANSITION_STATE_ANIMATING);
                }
            } catch (RemoteException e) {
                Slog.e(TAG, "Error starting recents animation", e);
+38 −3
Original line number Diff line number Diff line
@@ -16,12 +16,47 @@

package com.android.wm.shell.recents;

import android.os.IBinder;
import android.annotation.IntDef;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/** The listener for the events from {@link RecentsTransitionHandler}. */
public interface RecentsTransitionStateListener {

    /** Notifies whether the recents animation is running. */
    default void onAnimationStateChanged(boolean running) {
    @IntDef(prefix = { "TRANSITION_STATE_" }, value = {
            TRANSITION_STATE_NOT_RUNNING,
            TRANSITION_STATE_REQUESTED,
            TRANSITION_STATE_ANIMATING,
    })
    @Retention(RetentionPolicy.SOURCE)
    @interface RecentsTransitionState {}

    int TRANSITION_STATE_NOT_RUNNING = 1;
    int TRANSITION_STATE_REQUESTED = 2;
    int TRANSITION_STATE_ANIMATING = 3;

    /** Notifies whether the recents transition state changes. */
    default void onTransitionStateChanged(@RecentsTransitionState int state) {
    }

    /** Returns whether the recents transition is running. */
    static boolean isRunning(@RecentsTransitionState int state) {
        return state >= TRANSITION_STATE_REQUESTED;
    }

    /** Returns whether the recents transition is animating. */
    static boolean isAnimating(@RecentsTransitionState int state) {
        return state >= TRANSITION_STATE_ANIMATING;
    }

    /** Returns a string representation of the given state. */
    static String stateToString(@RecentsTransitionState int state) {
        return switch (state) {
            case TRANSITION_STATE_NOT_RUNNING -> "TRANSITION_STATE_NOT_RUNNING";
            case TRANSITION_STATE_REQUESTED -> "TRANSITION_STATE_REQUESTED";
            case TRANSITION_STATE_ANIMATING -> "TRANSITION_STATE_ANIMATING";
            default -> "UNKNOWN";
        };
    }
}
Loading