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

Commit dafa4517 authored by mattsziklay's avatar mattsziklay
Browse files

Combine bounds change and move-to-center animations.

Changes the animations for drag to desktop such that the task moves to
the center and changes to default freeform bounds at the same time.

Rather than cutting to the end of the shrink animation, we pause it and
use its current scale and position in the following animation. We then
animate scale to 1 and bounds to the default value.

Video: http://recall/-/epz9aQ1b0dZUySDQa3VwBZ/cTh9tIbYucFflebAPJj0hs
Bug: 315527000
Test: Manual
Change-Id: I46c9f163f42af830fe186c2d9abe030da263eb2f
parent 689af7a5
Loading
Loading
Loading
Loading
+31 −50
Original line number Diff line number Diff line
@@ -369,58 +369,41 @@ class DragToDesktopTransitionHandler(
            val startBounds = draggedTaskChange.startAbsBounds
            val endBounds = draggedTaskChange.endAbsBounds

            // TODO(b/301106941): Instead of forcing-finishing the animation that scales the
            //  surface down and then starting another that scales it back up to the final size,
            //  blend the two animations.
            state.dragAnimator.endAnimator()
            // Using [DRAG_FREEFORM_SCALE] to calculate animated width/height is possible because
            // it is known that the animation scale is finished because the animation was
            // force-ended above. This won't be true when the two animations are blended.
            val animStartWidth = (startBounds.width() * DRAG_FREEFORM_SCALE).toInt()
            val animStartHeight = (startBounds.height() * DRAG_FREEFORM_SCALE).toInt()
            // Using end bounds here to find the left/top also assumes the center animation has
            // finished and the surface is placed exactly in the center of the screen which matches
            // the end/default bounds of the now freeform task.
            val animStartLeft = endBounds.centerX() - (animStartWidth / 2)
            val animStartTop = endBounds.centerY() - (animStartHeight / 2)
            val animStartBounds = Rect(
                    animStartLeft,
                    animStartTop,
                    animStartLeft + animStartWidth,
                    animStartTop + animStartHeight
            // Pause any animation that may be currently playing; we will use the relevant
            // details of that animation here.
            state.dragAnimator.cancelAnimator()
            // We still apply scale to task bounds; as we animate the bounds to their
            // end value, animate scale to 1.
            val startScale = state.dragAnimator.scale
            val startPosition = state.dragAnimator.position
            val unscaledStartWidth = startBounds.width()
            val unscaledStartHeight = startBounds.height()
            val unscaledStartBounds = Rect(
                startPosition.x.toInt(),
                startPosition.y.toInt(),
                startPosition.x.toInt() + unscaledStartWidth,
                startPosition.y.toInt() + unscaledStartHeight
            )


            dragToDesktopStateListener?.onCommitToDesktopAnimationStart(t)
            t.apply {
                setScale(draggedTaskLeash, 1f, 1f)
                setPosition(
                        draggedTaskLeash,
                        animStartBounds.left.toFloat(),
                        animStartBounds.top.toFloat()
                )
                setWindowCrop(
                        draggedTaskLeash,
                        animStartBounds.width(),
                        animStartBounds.height()
                )
            }
            // Accept the merge by applying the merging transaction (applied by #showResizeVeil)
            // and finish callback. Show the veil and position the task at the first frame before
            // starting the final animation.
            onTaskResizeAnimationListener.onAnimationStart(state.draggedTaskId, t, animStartBounds)
            onTaskResizeAnimationListener.onAnimationStart(state.draggedTaskId, t,
                unscaledStartBounds)
            finishCallback.onTransitionFinished(null /* wct */)

            // Because the task surface was scaled down during the drag, we must use the animated
            // bounds instead of the [startAbsBounds].
            val tx: SurfaceControl.Transaction = transactionSupplier.get()
            ValueAnimator.ofObject(rectEvaluator, animStartBounds, endBounds)
            ValueAnimator.ofObject(rectEvaluator, unscaledStartBounds, endBounds)
                    .setDuration(DRAG_TO_DESKTOP_FINISH_ANIM_DURATION_MS)
                    .apply {
                        addUpdateListener { animator ->
                            val animBounds = animator.animatedValue as Rect
                            val animFraction = animator.animatedFraction
                            // Progress scale from starting value to 1 as animation plays.
                            val animScale = startScale + animFraction * (1 - startScale)
                            tx.apply {
                                setScale(draggedTaskLeash, 1f, 1f)
                                setScale(draggedTaskLeash, animScale, animScale)
                                setPosition(
                                     draggedTaskLeash,
                                     animBounds.left.toFloat(),
@@ -493,10 +476,8 @@ class DragToDesktopTransitionHandler(
        val draggedTaskChange = state.draggedTaskChange
                ?: throw IllegalStateException("Expected non-null task change")
        val sc = draggedTaskChange.leash
        // TODO(b/301106941): Don't end the animation and start one to scale it back, merge them
        //  instead.
        // End the animation that shrinks the window when task is first dragged from fullscreen
        dragToDesktopAnimator.endAnimator()
        // Pause the animation that shrinks the window when task is first dragged from fullscreen
        dragToDesktopAnimator.cancelAnimator()
        // Then animate the scaled window back to its original bounds.
        val x: Float = dragToDesktopAnimator.position.x
        val y: Float = dragToDesktopAnimator.position.y
+6 −70
Original line number Diff line number Diff line
@@ -32,16 +32,8 @@ import static android.view.WindowInsets.Type.statusBars;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_BOTTOM_OR_RIGHT;
import static com.android.wm.shell.common.split.SplitScreenConstants.SPLIT_POSITION_TOP_OR_LEFT;
import static com.android.wm.shell.compatui.AppCompatUtils.isSingleTopActivityTranslucent;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_DESKTOP_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_FULLSCREEN_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_LEFT_INDICATOR;
import static com.android.wm.shell.desktopmode.DesktopModeVisualIndicator.IndicatorType.TO_SPLIT_RIGHT_INDICATOR;
import static com.android.wm.shell.desktopmode.EnterDesktopTaskTransitionHandler.FREEFORM_ANIMATION_DURATION;
import static com.android.wm.shell.windowdecor.MoveToDesktopAnimator.DRAG_FREEFORM_SCALE;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;

import android.annotation.NonNull;
import android.app.ActivityManager;
import android.app.ActivityManager.RunningTaskInfo;
@@ -849,26 +841,18 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
            }
            case MotionEvent.ACTION_UP: {
                if (mTransitionDragActive) {
                    final DesktopModeVisualIndicator.IndicatorType indicatorType =
                    mDesktopTasksController.updateVisualIndicator(relevantDecor.mTaskInfo,
                            relevantDecor.mTaskSurface, ev.getRawX(), ev.getRawY());
                    mTransitionDragActive = false;
                    if (indicatorType == TO_DESKTOP_INDICATOR
                            || indicatorType == TO_SPLIT_LEFT_INDICATOR
                            || indicatorType == TO_SPLIT_RIGHT_INDICATOR) {
                        if (DesktopModeStatus.isEnabled()) {
                            animateToDesktop(relevantDecor, ev);
                        }
                        mMoveToDesktopAnimator = null;
                        return;
                    } else if (mMoveToDesktopAnimator != null) {
                    if (mMoveToDesktopAnimator != null) {
                        // Though this isn't a hover event, we need to update handle's hover state
                        // as it likely will change.
                        relevantDecor.updateHoverAndPressStatus(ev);
                        mDesktopTasksController.onDragPositioningEndThroughStatusBar(
                                new PointF(ev.getRawX(), ev.getRawY()),
                                relevantDecor.mTaskInfo,
                                calculateFreeformBounds(ev.getDisplayId(), DRAG_FREEFORM_SCALE));
                                calculateFreeformBounds(ev.getDisplayId(),
                                        DesktopTasksController.DESKTOP_MODE_INITIAL_BOUNDS_SCALE));
                        mMoveToDesktopAnimator = null;
                        return;
                    } else {
@@ -937,54 +921,6 @@ public class DesktopModeWindowDecorViewModel implements WindowDecorViewModel {
                (int) (screenHeight * (adjustmentPercentage + scale)));
    }

    /**
     * Blocks relayout until transition is finished and transitions to Desktop
     */
    private void animateToDesktop(DesktopModeWindowDecoration relevantDecor,
            MotionEvent ev) {
        centerAndMoveToDesktopWithAnimation(relevantDecor, ev);
    }

    /**
     * Animates a window to the center, grows to freeform size, and transitions to Desktop Mode.
     * @param relevantDecor the window decor of the task to be animated
     * @param ev the motion event that triggers the animation
     * TODO(b/315527000): This animation needs to be adjusted to allow snap left/right cases.
     *  Currently fullscreen -> split snap still animates to center screen before readjusting.
     */
    private void centerAndMoveToDesktopWithAnimation(DesktopModeWindowDecoration relevantDecor,
            MotionEvent ev) {
        ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
        animator.setDuration(FREEFORM_ANIMATION_DURATION);
        final SurfaceControl sc = relevantDecor.mTaskSurface;
        final Rect endBounds = calculateFreeformBounds(ev.getDisplayId(), DRAG_FREEFORM_SCALE);
        final Transaction t = mTransactionFactory.get();
        final float diffX = endBounds.centerX() - ev.getRawX();
        final float diffY = endBounds.top - ev.getRawY();
        final float startingX = ev.getRawX() - DRAG_FREEFORM_SCALE
                * mDragToDesktopAnimationStartBounds.width() / 2;

        animator.addUpdateListener(animation -> {
            final float animatorValue = (float) animation.getAnimatedValue();
            final float x = startingX + diffX * animatorValue;
            final float y = ev.getRawY() + diffY * animatorValue;
            t.setPosition(sc, x, y);
            t.apply();
        });
        animator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                mDesktopTasksController.onDragPositioningEndThroughStatusBar(
                        new PointF(ev.getRawX(), ev.getRawY()),
                        relevantDecor.mTaskInfo,
                        calculateFreeformBounds(ev.getDisplayId(),
                                DesktopTasksController
                                        .DESKTOP_MODE_INITIAL_BOUNDS_SCALE));
            }
        });
        animator.start();
    }

    @Nullable
    private DesktopModeWindowDecoration getRelevantWindowDecor(MotionEvent ev) {
        final DesktopModeWindowDecoration focusedDecor = getFocusedDecor();
+7 −6
Original line number Diff line number Diff line
@@ -31,15 +31,16 @@ class MoveToDesktopAnimator @JvmOverloads constructor(

    private val animatedTaskWidth
        get() = dragToDesktopAnimator.animatedValue as Float * startBounds.width()
    val scale: Float
        get() = dragToDesktopAnimator.animatedValue as Float
    private val dragToDesktopAnimator: ValueAnimator = ValueAnimator.ofFloat(1f,
            DRAG_FREEFORM_SCALE)
            .setDuration(ANIMATION_DURATION.toLong())
            .apply {
                val t = SurfaceControl.Transaction()
                val cornerRadius = ScreenDecorationsUtils.getWindowCornerRadius(context)
                addUpdateListener { animation ->
                    val animatorValue = animation.animatedValue as Float
                    t.setScale(taskSurface, animatorValue, animatorValue)
                addUpdateListener {
                    t.setScale(taskSurface, scale, scale)
                            .setCornerRadius(taskSurface, cornerRadius)
                            .apply()
                }
@@ -90,9 +91,9 @@ class MoveToDesktopAnimator @JvmOverloads constructor(
    }

    /**
     * Ends the animation, setting the scale and position to the final animation value
     * Cancels the animation, intended to be used when another animator will take over.
     */
    fun endAnimator() {
        dragToDesktopAnimator.end()
    fun cancelAnimator() {
        dragToDesktopAnimator.cancel()
    }
}
 No newline at end of file
+1 −1
Original line number Diff line number Diff line
@@ -190,7 +190,7 @@ class DragToDesktopTransitionHandlerTest : ShellTestCase() {
        handler.cancelDragToDesktopTransition()

        // Cancel animation should run since it had already started.
        verify(dragAnimator).endAnimator()
        verify(dragAnimator).cancelAnimator()
    }

    @Test