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

Commit aa541bdb authored by Perry Wu's avatar Perry Wu Committed by Android (Google) Code Review
Browse files

Merge "[PIP2] Fix enter/exit animator" into main

parents de6e85d0 ca1e981d
Loading
Loading
Loading
Loading
+52 −6
Original line number Diff line number Diff line
@@ -22,6 +22,7 @@ import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.content.Context;
import android.graphics.Rect;
import android.view.Surface;
import android.view.SurfaceControl;

import androidx.annotation.NonNull;
@@ -51,8 +52,10 @@ public class PipEnterExitAnimator extends ValueAnimator

    @NonNull private final SurfaceControl mLeash;
    private final SurfaceControl.Transaction mStartTransaction;
    private final int mEnterAnimationDuration;
    private final SurfaceControl.Transaction mFinishTransaction;
    private final int mEnterExitAnimationDuration;
    private final @BOUNDS int mDirection;
    private final @Surface.Rotation int mRotation;

    // optional callbacks for tracking animation start and end
    @Nullable private Runnable mAnimationStartCallback;
@@ -62,37 +65,59 @@ public class PipEnterExitAnimator extends ValueAnimator
    private final Rect mStartBounds = new Rect();
    private final Rect mEndBounds = new Rect();

    @Nullable private final Rect mSourceRectHint;
    private final Rect mSourceRectHintInsets = new Rect();
    private final Rect mZeroInsets = new Rect(0, 0, 0, 0);

    // Bounds updated by the evaluator as animator is running.
    private final Rect mAnimatedRect = new Rect();

    private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
            mSurfaceControlTransactionFactory;
    private final RectEvaluator mRectEvaluator;
    private final RectEvaluator mInsetEvaluator;
    private final PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;

    public PipEnterExitAnimator(Context context,
            @NonNull SurfaceControl leash,
            SurfaceControl.Transaction startTransaction,
            SurfaceControl.Transaction finishTransaction,
            @NonNull Rect baseBounds,
            @NonNull Rect startBounds,
            @NonNull Rect endBounds,
            @BOUNDS int direction) {
            @Nullable Rect sourceRectHint,
            @BOUNDS int direction,
            @Surface.Rotation int rotation) {
        mLeash = leash;
        mStartTransaction = startTransaction;
        mFinishTransaction = finishTransaction;
        mBaseBounds.set(baseBounds);
        mStartBounds.set(startBounds);
        mAnimatedRect.set(startBounds);
        mEndBounds.set(endBounds);
        mRectEvaluator = new RectEvaluator(mAnimatedRect);
        mInsetEvaluator = new RectEvaluator(new Rect());
        mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context);
        mDirection = direction;
        mRotation = rotation;

        mSourceRectHint = sourceRectHint != null ? new Rect(sourceRectHint) : null;
        if (mSourceRectHint != null) {
            mSourceRectHintInsets.set(
                    mSourceRectHint.left - mBaseBounds.left,
                    mSourceRectHint.top - mBaseBounds.top,
                    mBaseBounds.right - mSourceRectHint.right,
                    mBaseBounds.bottom - mSourceRectHint.bottom
            );
        }

        mSurfaceControlTransactionFactory =
                new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
        mEnterAnimationDuration = context.getResources()
        mEnterExitAnimationDuration = context.getResources()
                .getInteger(R.integer.config_pipEnterAnimationDuration);

        setDuration(mEnterAnimationDuration);
        setObjectValues(startBounds, endBounds);
        setDuration(mEnterExitAnimationDuration);
        setEvaluator(mRectEvaluator);
        addListener(this);
        addUpdateListener(this);
@@ -118,6 +143,14 @@ public class PipEnterExitAnimator extends ValueAnimator

    @Override
    public void onAnimationEnd(@NonNull Animator animation) {
        if (mFinishTransaction != null) {
            // finishTransaction might override some state (eg. corner radii) so we want to
            // manually set the state to the end of the animation
            mPipSurfaceTransactionHelper.scaleAndCrop(mFinishTransaction, mLeash, mSourceRectHint,
                            mBaseBounds, mAnimatedRect, getInsets(1f), isInPipDirection(), 1f)
                    .round(mFinishTransaction, mLeash, isInPipDirection())
                    .shadow(mFinishTransaction, mLeash, isInPipDirection());
        }
        if (mAnimationEndCallback != null) {
            mAnimationEndCallback.run();
        }
@@ -127,19 +160,32 @@ public class PipEnterExitAnimator extends ValueAnimator
    public void onAnimationUpdate(@NonNull ValueAnimator animation) {
        final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
        final float fraction = getAnimatedFraction();
        Rect insets = getInsets(fraction);

        // TODO (b/350801661): implement fixed rotation

        mPipSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, null,
                mBaseBounds, mAnimatedRect, null, isInPipDirection(), fraction)
        mPipSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mSourceRectHint,
                mBaseBounds, mAnimatedRect, insets, isInPipDirection(), fraction)
                .round(tx, mLeash, isInPipDirection())
                .shadow(tx, mLeash, isInPipDirection());
        tx.apply();
    }

    private Rect getInsets(float fraction) {
        Rect startInsets = isInPipDirection() ? mZeroInsets : mSourceRectHintInsets;
        Rect endInsets = isInPipDirection() ? mSourceRectHintInsets : mZeroInsets;

        return mInsetEvaluator.evaluate(fraction, startInsets, endInsets);
    }

    private boolean isInPipDirection() {
        return mDirection == BOUNDS_ENTER;
    }

    private boolean isOutPipDirection() {
        return mDirection == BOUNDS_EXIT;
    }

    // no-ops

    @Override
+6 −0
Original line number Diff line number Diff line
@@ -25,6 +25,7 @@ import android.graphics.Rect;
import android.os.Bundle;
import android.view.SurfaceControl;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import com.android.internal.util.Preconditions;
@@ -88,6 +89,11 @@ public class PipTaskListener implements ShellTaskOrganizer.TaskListener,
                : new PictureInPictureParams.Builder().build());
    }

    @NonNull
    public PictureInPictureParams getPictureInPictureParams() {
        return mPictureInPictureParams;
    }

    @Override
    public void onTaskInfoChanged(ActivityManager.RunningTaskInfo taskInfo) {
        PictureInPictureParams params = taskInfo.pictureInPictureParams;
+49 −9
Original line number Diff line number Diff line
@@ -36,6 +36,7 @@ import android.content.Context;
import android.graphics.Rect;
import android.os.Bundle;
import android.os.IBinder;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TransitionInfo;
import android.window.TransitionRequestInfo;
@@ -398,17 +399,22 @@ public class PipTransition extends PipTransitionController implements
        SurfaceControl pipLeash = mPipTransitionState.mPinnedTaskLeash;
        Preconditions.checkNotNull(pipLeash, "Leash is null for bounds transition.");

        Rect sourceRectHint = null;
        if (pipChange.getTaskInfo() != null
                && pipChange.getTaskInfo().pictureInPictureParams != null) {
            sourceRectHint = pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint();
        }

        PipEnterExitAnimator animator = new PipEnterExitAnimator(mContext, pipLeash,
                startTransaction, startBounds, startBounds, endBounds,
                PipEnterExitAnimator.BOUNDS_ENTER);
                startTransaction, finishTransaction, startBounds, startBounds, endBounds,
                sourceRectHint, PipEnterExitAnimator.BOUNDS_ENTER, Surface.ROTATION_0);

        tx.addTransactionCommittedListener(mPipScheduler.getMainExecutor(),
                this::onClientDrawAtTransitionEnd);
        finishWct.setBoundsChangeTransaction(pipTaskToken, tx);

        animator.setAnimationEndCallback(() -> {
            finishCallback.onTransitionFinished(finishWct.isEmpty() ? null : finishWct);
        });
        animator.setAnimationEndCallback(() ->
                finishCallback.onTransitionFinished(finishWct));

        animator.start();
        return true;
@@ -451,20 +457,54 @@ public class PipTransition extends PipTransitionController implements
        WindowContainerToken pipToken = mPipTransitionState.mPipTaskToken;

        TransitionInfo.Change pipChange = getChangeByToken(info, pipToken);
        if (pipChange == null) {
            // pipChange is null, check to see if we've reparented the PIP activity for
            // the multi activity case. If so we should use the activity leash instead
            for (TransitionInfo.Change change : info.getChanges()) {
                if (change.getTaskInfo() == null
                        && change.getLastParent() != null
                        && change.getLastParent().equals(pipToken)) {
                    pipChange = change;
                    break;
                }
            }

            // failsafe
            if (pipChange == null) {
                return false;
            }
        }

        // for multi activity, we need to manually set the leash layer
        if (pipChange.getTaskInfo() == null) {
            TransitionInfo.Change parent = getChangeByToken(info, pipChange.getParent());
            if (parent != null) {
                startTransaction.setLayer(parent.getLeash(), Integer.MAX_VALUE - 1);
            }
        }

        Rect startBounds = pipChange.getStartAbsBounds();
        Rect endBounds = pipChange.getEndAbsBounds();
        SurfaceControl pipLeash = pipChange.getLeash();
        Preconditions.checkNotNull(pipLeash, "Leash is null for exit transition.");

        Rect sourceRectHint = null;
        if (pipChange.getTaskInfo() != null
                && pipChange.getTaskInfo().pictureInPictureParams != null) {
            // single activity
            sourceRectHint = pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint();
        } else if (mPipTaskListener.getPictureInPictureParams().hasSourceBoundsHint()) {
            // multi activity
            sourceRectHint = mPipTaskListener.getPictureInPictureParams().getSourceRectHint();
        }

        PipEnterExitAnimator animator = new PipEnterExitAnimator(mContext, pipLeash,
                startTransaction, startBounds, startBounds, endBounds,
                PipEnterExitAnimator.BOUNDS_EXIT);
                startTransaction, finishTransaction, endBounds, startBounds, endBounds,
                sourceRectHint, PipEnterExitAnimator.BOUNDS_EXIT, Surface.ROTATION_0);

        animator.setAnimationEndCallback(() -> {
            finishCallback.onTransitionFinished(null);
            mPipTransitionState.setState(PipTransitionState.EXITED_PIP);
            finishCallback.onTransitionFinished(null);
        });

        animator.start();