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

Commit 5d346146 authored by Maryam Dehaini's avatar Maryam Dehaini Committed by Android (Google) Code Review
Browse files

Merge "Add animation for fullscreen to desktop transition from handle menu" into udc-qpr-dev

parents 889d4e08 0c742dfd
Loading
Loading
Loading
Loading
+8 −3
Original line number Diff line number Diff line
@@ -176,9 +176,13 @@ class DesktopTasksController(
    }

    /** Move a task with given `taskId` to desktop */
    fun moveToDesktop(taskId: Int, wct: WindowContainerTransaction = WindowContainerTransaction()) {
    fun moveToDesktop(
            decor: DesktopModeWindowDecoration,
            taskId: Int,
            wct: WindowContainerTransaction = WindowContainerTransaction()
    ) {
        shellTaskOrganizer.getRunningTaskInfo(taskId)?.let {
            task -> moveToDesktop(task, wct)
            task -> moveToDesktop(decor, task, wct)
        }
    }

@@ -186,6 +190,7 @@ class DesktopTasksController(
     * Move a task to desktop
     */
    fun moveToDesktop(
            decor: DesktopModeWindowDecoration,
            task: RunningTaskInfo,
            wct: WindowContainerTransaction = WindowContainerTransaction()
    ) {
@@ -199,7 +204,7 @@ class DesktopTasksController(
        addMoveToDesktopChanges(wct, task)

        if (Transitions.ENABLE_SHELL_TRANSITIONS) {
            transitions.startTransition(TRANSIT_CHANGE, wct, null /* handler */)
            enterDesktopTaskTransitionHandler.moveToDesktop(wct, decor)
        } else {
            shellTaskOrganizer.applyTransaction(wct)
        }
+197 −111
Original line number Diff line number Diff line
@@ -20,6 +20,7 @@ import static android.app.WindowConfiguration.WINDOWING_MODE_FREEFORM;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.app.ActivityManager;
import android.graphics.PointF;
@@ -36,6 +37,7 @@ import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.wm.shell.transition.Transitions;
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration;
import com.android.wm.shell.windowdecor.MoveToDesktopAnimator;

import java.util.ArrayList;
@@ -60,6 +62,7 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
    private final List<IBinder> mPendingTransitionTokens = new ArrayList<>();
    private Consumer<SurfaceControl.Transaction> mOnAnimationFinishedCallback;
    private MoveToDesktopAnimator mMoveToDesktopAnimator;
    private DesktopModeWindowDecoration mDesktopModeWindowDecoration;

    public EnterDesktopTaskTransitionHandler(
            Transitions transitions) {
@@ -128,6 +131,18 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
                onAnimationEndCallback);
    }

    /**
     * Starts Transition of type TRANSIT_MOVE_TO_DESKTOP
     * @param wct WindowContainerTransaction for transition
     * @param decor {@link DesktopModeWindowDecoration} of task being animated
     */
    public void moveToDesktop(@NonNull WindowContainerTransaction wct,
            DesktopModeWindowDecoration decor) {
        mDesktopModeWindowDecoration = decor;
        startTransition(Transitions.TRANSIT_MOVE_TO_DESKTOP, wct,
                null /* onAnimationEndCallback */);
    }

    @Override
    public boolean startAnimation(@NonNull IBinder transition, @NonNull TransitionInfo info,
            @NonNull SurfaceControl.Transaction startT,
@@ -167,8 +182,77 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
        }

        final ActivityManager.RunningTaskInfo taskInfo = change.getTaskInfo();
        if (type == Transitions.TRANSIT_MOVE_TO_DESKTOP
                && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
            return animateMoveToDesktop(change, startT, finishCallback);
        }

        if (type == Transitions.TRANSIT_START_DRAG_TO_DESKTOP_MODE
                && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
            return animateStartDragToDesktopMode(change, startT, finishT, finishCallback);
        }

        final Rect endBounds = change.getEndAbsBounds();
        if (type == Transitions.TRANSIT_FINALIZE_DRAG_TO_DESKTOP_MODE
                && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
                && !endBounds.isEmpty()) {
            return animateFinalizeDragToDesktopMode(change, startT, finishT, finishCallback,
                    endBounds);
        }

        if (type == Transitions.TRANSIT_CANCEL_DRAG_TO_DESKTOP_MODE
                && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
            return animateCancelDragToDesktopMode(change, startT, finishT, finishCallback,
                    endBounds);
        }

        return false;
    }

    private boolean animateMoveToDesktop(
            @NonNull TransitionInfo.Change change,
            @NonNull SurfaceControl.Transaction startT,
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
        if (mDesktopModeWindowDecoration == null) {
            Slog.e(TAG, "Window Decoration is not available for this transition");
            return false;
        }

        final SurfaceControl leash = change.getLeash();
        final Rect startBounds = change.getStartAbsBounds();
        startT.setPosition(leash, startBounds.left, startBounds.right)
                .setWindowCrop(leash, startBounds.width(), startBounds.height())
                .show(leash);
        mDesktopModeWindowDecoration.showResizeVeil(startT, startBounds);

        final ValueAnimator animator = ValueAnimator.ofObject(new RectEvaluator(),
                change.getStartAbsBounds(), change.getEndAbsBounds());
        animator.setDuration(FREEFORM_ANIMATION_DURATION);
        SurfaceControl.Transaction t = mTransactionSupplier.get();
        animator.addUpdateListener(animation -> {
            final Rect animationValue = (Rect) animator.getAnimatedValue();
            t.setPosition(leash, animationValue.left, animationValue.right)
                    .setWindowCrop(leash, animationValue.width(), animationValue.height())
                    .show(leash);
            mDesktopModeWindowDecoration.updateResizeVeil(t, animationValue);
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mDesktopModeWindowDecoration.hideResizeVeil();
                mTransitions.getMainExecutor().execute(
                        () -> finishCallback.onTransitionFinished(null, null));
            }
        });
        animator.start();
        return true;
    }

    private boolean animateStartDragToDesktopMode(
            @NonNull TransitionInfo.Change change,
            @NonNull SurfaceControl.Transaction startT,
            @NonNull SurfaceControl.Transaction finishT,
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
        // Transitioning to freeform but keeping fullscreen bounds, so the crop is set
        // to null and we don't require an animation
        final SurfaceControl sc = change.getLeash();
@@ -193,10 +277,12 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
        return true;
    }

        Rect endBounds = change.getEndAbsBounds();
        if (type == Transitions.TRANSIT_FINALIZE_DRAG_TO_DESKTOP_MODE
                && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM
                && !endBounds.isEmpty()) {
    private boolean animateFinalizeDragToDesktopMode(
            @NonNull TransitionInfo.Change change,
            @NonNull SurfaceControl.Transaction startT,
            @NonNull SurfaceControl.Transaction finishT,
            @NonNull Transitions.TransitionFinishCallback finishCallback,
            @NonNull Rect endBounds) {
        // This Transition animates a task to freeform bounds after being dragged into freeform
        // mode and brings the remaining freeform tasks to front
        final SurfaceControl sc = change.getLeash();
@@ -245,9 +331,12 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
        animator.start();
        return true;
    }

        if (type == Transitions.TRANSIT_CANCEL_DRAG_TO_DESKTOP_MODE
                && taskInfo.getWindowingMode() == WINDOWING_MODE_FREEFORM) {
    private boolean animateCancelDragToDesktopMode(
            @NonNull TransitionInfo.Change change,
            @NonNull SurfaceControl.Transaction startT,
            @NonNull SurfaceControl.Transaction finishT,
            @NonNull Transitions.TransitionFinishCallback finishCallback,
            @NonNull Rect endBounds) {
        // This Transition animates a task to fullscreen after being dragged from the status
        // bar and then released back into the status bar area
        final SurfaceControl sc = change.getLeash();
@@ -296,9 +385,6 @@ public class EnterDesktopTaskTransitionHandler implements Transitions.Transition
        return true;
    }

        return false;
    }

    @Nullable
    @Override
    public WindowContainerTransaction handleRequest(@NonNull IBinder transition,
+3 −0
Original line number Diff line number Diff line
@@ -168,6 +168,9 @@ public class Transitions implements RemoteCallable<Transitions>,
    public static final int TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE =
            WindowManager.TRANSIT_FIRST_CUSTOM + 14;

    /** Transition to animate task to desktop. */
    public static final int TRANSIT_MOVE_TO_DESKTOP = WindowManager.TRANSIT_FIRST_CUSTOM + 15;

    private final WindowOrganizer mOrganizer;
    private final Context mContext;
    private final ShellExecutor mMainExecutor;
+4 −2
Original line number Diff line number Diff line
@@ -222,7 +222,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                && (info.getType() == Transitions.TRANSIT_FINALIZE_DRAG_TO_DESKTOP_MODE
                || info.getType() == Transitions.TRANSIT_CANCEL_DRAG_TO_DESKTOP_MODE
                || info.getType() == Transitions.TRANSIT_EXIT_DESKTOP_MODE
                || info.getType() == Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE)) {
                || info.getType() == Transitions.TRANSIT_DESKTOP_MODE_TOGGLE_RESIZE
                || info.getType() == Transitions.TRANSIT_MOVE_TO_DESKTOP)) {
            mWindowDecorByTaskId.get(change.getTaskInfo().taskId)
                    .addTransitionPausingRelayout(transition);
        }
@@ -356,7 +357,8 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                    // App sometimes draws before the insets from WindowDecoration#relayout have
                    // been added, so they must be added here
                    mWindowDecorByTaskId.get(mTaskId).addCaptionInset(wct);
                    mDesktopTasksController.get().moveToDesktop(mTaskId, wct);
                    decoration.incrementRelayoutBlock();
                    mDesktopTasksController.get().moveToDesktop(decoration, mTaskId, wct);
                }
                decoration.closeHandleMenu();
            } else if (id == R.id.fullscreen_button) {
+21 −9
Original line number Diff line number Diff line
@@ -57,6 +57,7 @@ import com.android.wm.shell.sysui.ShellController
import com.android.wm.shell.sysui.ShellInit
import com.android.wm.shell.transition.Transitions
import com.android.wm.shell.transition.Transitions.ENABLE_SHELL_TRANSITIONS
import com.android.wm.shell.windowdecor.DesktopModeWindowDecoration
import com.google.common.truth.Truth.assertThat
import com.google.common.truth.Truth.assertWithMessage
import org.junit.After
@@ -92,6 +93,7 @@ class DesktopTasksControllerTest : ShellTestCase() {
    @Mock lateinit var mToggleResizeDesktopTaskTransitionHandler:
            ToggleResizeDesktopTaskTransitionHandler
    @Mock lateinit var launchAdjacentController: LaunchAdjacentController
    @Mock lateinit var desktopModeWindowDecoration: DesktopModeWindowDecoration

    private lateinit var mockitoSession: StaticMockitoSession
    private lateinit var controller: DesktopTasksController
@@ -276,8 +278,8 @@ class DesktopTasksControllerTest : ShellTestCase() {
    fun moveToDesktop_displayFullscreen_windowingModeSetToFreeform() {
        val task = setUpFullscreenTask()
        task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FULLSCREEN
        controller.moveToDesktop(task)
        val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
        controller.moveToDesktop(desktopModeWindowDecoration, task)
        val wct = getLatestMoveToDesktopWct()
        assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
            .isEqualTo(WINDOWING_MODE_FREEFORM)
    }
@@ -286,15 +288,15 @@ class DesktopTasksControllerTest : ShellTestCase() {
    fun moveToDesktop_displayFreeform_windowingModeSetToUndefined() {
        val task = setUpFullscreenTask()
        task.configuration.windowConfiguration.displayWindowingMode = WINDOWING_MODE_FREEFORM
        controller.moveToDesktop(task)
        val wct = getLatestWct(expectTransition = TRANSIT_CHANGE)
        controller.moveToDesktop(desktopModeWindowDecoration, task)
        val wct = getLatestMoveToDesktopWct()
        assertThat(wct.changes[task.token.asBinder()]?.windowingMode)
                .isEqualTo(WINDOWING_MODE_UNDEFINED)
    }

    @Test
    fun moveToDesktop_nonExistentTask_doesNothing() {
        controller.moveToDesktop(999)
        controller.moveToDesktop(desktopModeWindowDecoration, 999)
        verifyWCTNotExecuted()
    }

@@ -305,9 +307,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
        val fullscreenTask = setUpFullscreenTask()
        markTaskHidden(freeformTask)

        controller.moveToDesktop(fullscreenTask)
        controller.moveToDesktop(desktopModeWindowDecoration, fullscreenTask)

        with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
        with(getLatestMoveToDesktopWct()) {
            // Operations should include home task, freeform task
            assertThat(hierarchyOps).hasSize(3)
            assertReorderSequence(homeTask, freeformTask, fullscreenTask)
@@ -327,9 +329,9 @@ class DesktopTasksControllerTest : ShellTestCase() {
        val freeformTaskSecond = setUpFreeformTask(displayId = SECOND_DISPLAY)
        markTaskHidden(freeformTaskSecond)

        controller.moveToDesktop(fullscreenTaskDefault)
        controller.moveToDesktop(desktopModeWindowDecoration, fullscreenTaskDefault)

        with(getLatestWct(expectTransition = TRANSIT_CHANGE)) {
        with(getLatestMoveToDesktopWct()) {
            // Check that hierarchy operations do not include tasks from second display
            assertThat(hierarchyOps.map { it.container })
                .doesNotContain(homeTaskSecond.token.asBinder())
@@ -721,6 +723,16 @@ class DesktopTasksControllerTest : ShellTestCase() {
        return arg.value
    }

    private fun getLatestMoveToDesktopWct(): WindowContainerTransaction {
        val arg = ArgumentCaptor.forClass(WindowContainerTransaction::class.java)
        if (ENABLE_SHELL_TRANSITIONS) {
            verify(enterDesktopTransitionHandler).moveToDesktop(arg.capture(), any())
        } else {
            verify(shellTaskOrganizer).applyTransaction(arg.capture())
        }
        return arg.value
    }

    private fun verifyWCTNotExecuted() {
        if (ENABLE_SHELL_TRANSITIONS) {
            verify(transitions, never()).startTransition(anyInt(), any(), isNull())