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

Commit 966860db authored by Tracy Zhou's avatar Tracy Zhou Committed by Android (Google) Code Review
Browse files

Merge "Implement the new PiP animation (fade-in)." into qt-dev

parents 35ed6c34 9c675d4f
Loading
Loading
Loading
Loading
+3 −1
Original line number Diff line number Diff line
@@ -41,9 +41,11 @@ interface IRecentsAnimationController {
     * with remote animation targets should be relinquished. If {@param moveHomeToTop} is true, then
     * the home activity should be moved to the top. Otherwise, the home activity is hidden and the
     * user is returned to the app.
     * @param sendUserLeaveHint If set to true, {@link Activity#onUserLeaving} will be sent to the
     *                          top resumed app, false otherwise.
     */
    @UnsupportedAppUsage
    void finish(boolean moveHomeToTop);
    void finish(boolean moveHomeToTop, boolean sendUserLeaveHint);

    /**
     * Called by the handler to indicate that the recents animation input consumer should be
+8 −2
Original line number Diff line number Diff line
@@ -77,9 +77,15 @@ public class RecentsAnimationControllerCompat {
        }
    }

    public void finish(boolean toHome) {
    /**
     * Finish the current recents animation.
     * @param toHome Going to home or back to the previous app.
     * @param sendUserLeaveHint determines whether userLeaveHint will be set true to the previous
     *                          app.
     */
    public void finish(boolean toHome, boolean sendUserLeaveHint) {
        try {
            mAnimationController.finish(toHome);
            mAnimationController.finish(toHome, sendUserLeaveHint);
        } catch (RemoteException e) {
            Log.e(TAG, "Failed to finish recents animation", e);
        }
+74 −19
Original line number Diff line number Diff line
@@ -73,6 +73,13 @@ public class BoundsAnimationController {
    /** Schedule a PiP mode changed callback when this animation ends. */
    public static final int SCHEDULE_PIP_MODE_CHANGED_ON_END = 2;

    public static final int BOUNDS = 0;
    public static final int FADE_IN = 1;

    @IntDef({BOUNDS, FADE_IN}) public @interface AnimationType {}

    private static final int FADE_IN_DURATION = 500;

    // Only accessed on UI thread.
    private ArrayMap<BoundsAnimationTarget, BoundsAnimator> mRunningAnimations = new ArrayMap<>();

@@ -115,6 +122,7 @@ public class BoundsAnimationController {
    private boolean mFinishAnimationAfterTransition = false;
    private final AnimationHandler mAnimationHandler;
    private Choreographer mChoreographer;
    private @AnimationType int mAnimationType;

    private static final int WAIT_FOR_DRAW_TIMEOUT_MS = 3000;

@@ -140,6 +148,7 @@ public class BoundsAnimationController {
            implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {

        private final BoundsAnimationTarget mTarget;
        private final @AnimationType int mAnimationType;
        private final Rect mFrom = new Rect();
        private final Rect mTo = new Rect();
        private final Rect mTmpRect = new Rect();
@@ -166,8 +175,8 @@ public class BoundsAnimationController {

        // Depending on whether we are animating from
        // a smaller to a larger size
        private final int mFrozenTaskWidth;
        private final int mFrozenTaskHeight;
        private int mFrozenTaskWidth;
        private int mFrozenTaskHeight;

        // Timeout callback to ensure we continue the animation if waiting for resuming or app
        // windows drawn fails
@@ -176,12 +185,13 @@ public class BoundsAnimationController {
            resume();
        };

        BoundsAnimator(BoundsAnimationTarget target, Rect from, Rect to,
                @SchedulePipModeChangedState int schedulePipModeChangedState,
        BoundsAnimator(BoundsAnimationTarget target, @AnimationType int animationType, Rect from,
                Rect to, @SchedulePipModeChangedState int schedulePipModeChangedState,
                @SchedulePipModeChangedState int prevShedulePipModeChangedState,
                boolean moveFromFullscreen, boolean moveToFullscreen, Rect frozenTask) {
            super();
            mTarget = target;
            mAnimationType = animationType;
            mFrom.set(from);
            mTo.set(to);
            mSchedulePipModeChangedState = schedulePipModeChangedState;
@@ -195,6 +205,7 @@ public class BoundsAnimationController {
            // to their final size immediately so we can use scaling to make the window
            // larger. Likewise if we are going from bigger to smaller, we want to wait until
            // the end so we don't have to upscale from the smaller finished size.
            if (mAnimationType == BOUNDS) {
                if (animatingToLargerSize()) {
                    mFrozenTaskWidth = mTo.width();
                    mFrozenTaskHeight = mTo.height();
@@ -203,6 +214,7 @@ public class BoundsAnimationController {
                    mFrozenTaskHeight = frozenTask.isEmpty() ? mFrom.height() : frozenTask.height();
                }
            }
        }

        @Override
        public void onAnimationStart(Animator animation) {
@@ -222,8 +234,9 @@ public class BoundsAnimationController {
            // otherwise.
            boolean continueAnimation;
            if (mPrevSchedulePipModeChangedState == NO_PIP_MODE_CHANGED_CALLBACKS) {
                continueAnimation = mTarget.onAnimationStart(mSchedulePipModeChangedState ==
                        SCHEDULE_PIP_MODE_CHANGED_ON_START, false /* forceUpdate */);
                continueAnimation = mTarget.onAnimationStart(
                        mSchedulePipModeChangedState == SCHEDULE_PIP_MODE_CHANGED_ON_START,
                        false /* forceUpdate */, mAnimationType);

                // When starting an animation from fullscreen, pause here and wait for the
                // windows-drawn signal before we start the rest of the transition down into PiP.
@@ -238,7 +251,8 @@ public class BoundsAnimationController {
                // However, we still need to report to them that they are leaving PiP, so this will
                // force an update via a mode changed callback.
                continueAnimation = mTarget.onAnimationStart(
                        true /* schedulePipModeChangedCallback */, true /* forceUpdate */);
                        true /* schedulePipModeChangedCallback */, true /* forceUpdate */,
                        mAnimationType);
            } else {
                // The animation is already running, but we should check that the TaskStack is still
                // valid before continuing with the animation
@@ -285,6 +299,13 @@ public class BoundsAnimationController {
        @Override
        public void onAnimationUpdate(ValueAnimator animation) {
            final float value = (Float) animation.getAnimatedValue();
            if (mAnimationType == FADE_IN) {
                if (!mTarget.setPinnedStackAlpha(value)) {
                    cancelAndCallAnimationEnd();
                }
                return;
            }

            final float remains = 1 - value;
            mTmpRect.left = (int) (mFrom.left * remains + mTo.left * value + 0.5f);
            mTmpRect.top = (int) (mFrom.top * remains + mTo.top * value + 0.5f);
@@ -408,16 +429,29 @@ public class BoundsAnimationController {

    public void animateBounds(final BoundsAnimationTarget target, Rect from, Rect to,
            int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
            boolean moveFromFullscreen, boolean moveToFullscreen) {
            boolean moveFromFullscreen, boolean moveToFullscreen,
            @AnimationType int animationType) {
        animateBoundsImpl(target, from, to, animationDuration, schedulePipModeChangedState,
                moveFromFullscreen, moveToFullscreen);
                moveFromFullscreen, moveToFullscreen, animationType);
    }

    @VisibleForTesting
    BoundsAnimator animateBoundsImpl(final BoundsAnimationTarget target, Rect from, Rect to,
            int animationDuration, @SchedulePipModeChangedState int schedulePipModeChangedState,
            boolean moveFromFullscreen, boolean moveToFullscreen) {
            boolean moveFromFullscreen, boolean moveToFullscreen,
            @AnimationType int animationType) {
        final BoundsAnimator existing = mRunningAnimations.get(target);
        // animateBoundsImpl gets called twice for each animation. The second time we get the final
        // to rect that respects the shelf, which is when we want to resize. Our signal for fade in
        // comes in from how to enter into pip, but we also need to use the to and from rect to
        // decide which animation we want to run finally.
        boolean shouldResize = false;
        if (isRunningFadeInAnimation(target)) {
            shouldResize = true;
            if (from.contains(to)) {
                animationType = FADE_IN;
            }
        }
        final boolean replacing = existing != null;
        @SchedulePipModeChangedState int prevSchedulePipModeChangedState =
                NO_PIP_MODE_CHANGED_CALLBACKS;
@@ -477,18 +511,34 @@ public class BoundsAnimationController {
            // Since we are replacing, we skip both animation start and end callbacks
            existing.cancel();
        }
        final BoundsAnimator animator = new BoundsAnimator(target, from, to,
        if (shouldResize) {
            target.setPinnedStackSize(to, null);
        }
        final BoundsAnimator animator = new BoundsAnimator(target, animationType, from, to,
                schedulePipModeChangedState, prevSchedulePipModeChangedState,
                moveFromFullscreen, moveToFullscreen, frozenTask);
        mRunningAnimations.put(target, animator);
        animator.setFloatValues(0f, 1f);
        animator.setDuration((animationDuration != -1 ? animationDuration
                : DEFAULT_TRANSITION_DURATION) * DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
        animator.setDuration(animationType == FADE_IN ? FADE_IN_DURATION
                : (animationDuration != -1 ? animationDuration : DEFAULT_TRANSITION_DURATION)
                        * DEBUG_ANIMATION_SLOW_DOWN_FACTOR);
        animator.setInterpolator(mFastOutSlowInInterpolator);
        animator.start();
        return animator;
    }

    public void setAnimationType(@AnimationType int animationType) {
        mAnimationType = animationType;
    }

    /** return the current animation type. */
    public @AnimationType int getAnimationType() {
        @AnimationType int animationType = mAnimationType;
        // Default to BOUNDS.
        mAnimationType = BOUNDS;
        return animationType;
    }

    public Handler getHandler() {
        return mHandler;
    }
@@ -498,6 +548,11 @@ public class BoundsAnimationController {
        mHandler.post(this::resume);
    }

    private boolean isRunningFadeInAnimation(final BoundsAnimationTarget target) {
        final BoundsAnimator existing = mRunningAnimations.get(target);
        return existing != null && existing.mAnimationType == FADE_IN && existing.isStarted();
    }

    private void resume() {
        for (int i = 0; i < mRunningAnimations.size(); i++) {
            final BoundsAnimator b = mRunningAnimations.valueAt(i);
+5 −1
Original line number Diff line number Diff line
@@ -32,7 +32,8 @@ interface BoundsAnimationTarget {
     * callbacks
     * @return whether to continue the animation
     */
    boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate);
    boolean onAnimationStart(boolean schedulePipModeChangedCallback, boolean forceUpdate,
            @BoundsAnimationController.AnimationType int animationType);

    /**
     * @return Whether the animation should be paused waiting for the windows to draw before
@@ -53,6 +54,9 @@ interface BoundsAnimationTarget {
     */
    boolean setPinnedStackSize(Rect stackBounds, Rect taskBounds);

    /** Sets the alpha of the animation target */
    boolean setPinnedStackAlpha(float alpha);

    /**
     * Callback for the target to inform it that the animation has ended, so it can do some
     * necessary cleanup.
+23 −5
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@ import static android.os.Trace.TRACE_TAG_ACTIVITY_MANAGER;
import static android.view.WindowManager.TRANSIT_NONE;

import static com.android.server.wm.ActivityStackSupervisor.PRESERVE_WINDOWS;
import static com.android.server.wm.BoundsAnimationController.BOUNDS;
import static com.android.server.wm.BoundsAnimationController.FADE_IN;
import static com.android.server.wm.RecentsAnimationController.REORDER_KEEP_IN_PLACE;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_ORIGINAL_POSITION;
import static com.android.server.wm.RecentsAnimationController.REORDER_MOVE_TO_TOP;
@@ -201,7 +203,8 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
        }
    }

    private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode) {
    private void finishAnimation(@RecentsAnimationController.ReorderMode int reorderMode,
            boolean sendUserLeaveHint) {
        synchronized (mService.mGlobalLock) {
            if (DEBUG) Slog.d(TAG, "onAnimationFinished(): controller="
                    + mWindowManager.getRecentsAnimationController()
@@ -246,7 +249,18 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
                    if (reorderMode == REORDER_MOVE_TO_TOP) {
                        // Bring the target stack to the front
                        mStackSupervisor.mNoAnimActivities.add(targetActivity);

                        if (sendUserLeaveHint) {
                            // Setting this allows the previous app to PiP.
                            mStackSupervisor.mUserLeaving = true;
                            targetStack.moveTaskToFrontLocked(targetActivity.getTaskRecord(),
                                    true /* noAnimation */, null /* activityOptions */,
                                    targetActivity.appTimeTracker,
                                    "RecentsAnimation.onAnimationFinished()");
                        } else {
                            targetStack.moveToFront("RecentsAnimation.onAnimationFinished()");
                        }

                        if (DEBUG) {
                            final ActivityStack topStack = getTopNonAlwaysOnTopStack();
                            if (topStack != targetStack) {
@@ -300,11 +314,11 @@ class RecentsAnimation implements RecentsAnimationCallbacks,

    @Override
    public void onAnimationFinished(@RecentsAnimationController.ReorderMode int reorderMode,
            boolean runSychronously) {
            boolean runSychronously, boolean sendUserLeaveHint) {
        if (runSychronously) {
            finishAnimation(reorderMode);
            finishAnimation(reorderMode, sendUserLeaveHint);
        } else {
            mService.mH.post(() -> finishAnimation(reorderMode));
            mService.mH.post(() -> finishAnimation(reorderMode, sendUserLeaveHint));
        }
    }

@@ -317,6 +331,10 @@ class RecentsAnimation implements RecentsAnimationCallbacks,
        }
        final RecentsAnimationController controller =
                mWindowManager.getRecentsAnimationController();
        final DisplayContent dc =
                mService.mRootActivityContainer.getDefaultDisplay().mDisplayContent;
        dc.mBoundsAnimationController.setAnimationType(
                controller.shouldCancelWithDeferredScreenshot() ? FADE_IN : BOUNDS);

        // Cancel running recents animation and screenshot previous task when the next
        // transition starts in below cases:
Loading