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

Commit 1d30d8b4 authored by Ikram Gabiyev's avatar Ikram Gabiyev Committed by Android (Google) Code Review
Browse files

Merge "Refactor 3-btn-nav with flipv2" into main

parents 158b20c5 15db4793
Loading
Loading
Loading
Loading
+159 −0
Original line number Diff line number Diff line
/*
 * Copyright (C) 2024 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.android.wm.shell.pip2.animation;

import android.animation.Animator;
import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.PointF;
import android.graphics.Rect;
import android.view.Surface;
import android.view.SurfaceControl;
import android.window.TransitionInfo;

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

import com.android.wm.shell.R;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;
import com.android.wm.shell.shared.animation.Interpolators;

/**
 * Animator that handles bounds animations for entering PIP.
 */
public class PipEnterAnimator extends ValueAnimator
        implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
    @NonNull private final SurfaceControl mLeash;
    private final SurfaceControl.Transaction mStartTransaction;
    private final SurfaceControl.Transaction mFinishTransaction;

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

    private final RectEvaluator mRectEvaluator;
    private final Rect mEndBounds = new Rect();
    @Nullable private final Rect mSourceRectHint;
    private final @Surface.Rotation int mRotation;
    @Nullable private Runnable mAnimationStartCallback;
    @Nullable private Runnable mAnimationEndCallback;

    private final PipSurfaceTransactionHelper.SurfaceControlTransactionFactory
            mSurfaceControlTransactionFactory;

    // Internal state representing initial transform - cached to avoid recalculation.
    private final PointF mInitScale = new PointF();
    private final PointF mInitPos = new PointF();
    private final Rect mInitCrop = new Rect();

    public PipEnterAnimator(Context context,
            @NonNull SurfaceControl leash,
            SurfaceControl.Transaction startTransaction,
            SurfaceControl.Transaction finishTransaction,
            @NonNull Rect endBounds,
            @Nullable Rect sourceRectHint,
            @Surface.Rotation int rotation) {
        mLeash = leash;
        mStartTransaction = startTransaction;
        mFinishTransaction = finishTransaction;
        mRectEvaluator = new RectEvaluator(mAnimatedRect);
        mEndBounds.set(endBounds);
        mSourceRectHint = sourceRectHint != null ? new Rect(sourceRectHint) : null;
        mRotation = rotation;
        mSurfaceControlTransactionFactory =
                new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();

        final int enterAnimationDuration = context.getResources()
                .getInteger(R.integer.config_pipEnterAnimationDuration);
        setDuration(enterAnimationDuration);
        setFloatValues(0f, 1f);
        setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
        addListener(this);
        addUpdateListener(this);
    }

    public void setAnimationStartCallback(@NonNull Runnable runnable) {
        mAnimationStartCallback = runnable;
    }

    public void setAnimationEndCallback(@NonNull Runnable runnable) {
        mAnimationEndCallback = runnable;
    }

    @Override
    public void onAnimationStart(@NonNull Animator animation) {
        if (mAnimationStartCallback != null) {
            mAnimationStartCallback.run();
        }
        if (mStartTransaction != null) {
            onEnterAnimationUpdate(mInitScale, mInitPos, mInitCrop,
                    0f /* fraction */, mStartTransaction);
            mStartTransaction.apply();
        }
    }

    @Override
    public void onAnimationEnd(@NonNull Animator animation) {
        if (mAnimationEndCallback != null) {
            mAnimationEndCallback.run();
        }
    }

    @Override
    public void onAnimationUpdate(@NonNull ValueAnimator animation) {
        final SurfaceControl.Transaction tx = mSurfaceControlTransactionFactory.getTransaction();
        final float fraction = getAnimatedFraction();
        onEnterAnimationUpdate(mInitScale, mInitPos, mInitCrop, fraction, tx);
        tx.apply();
    }

    private void onEnterAnimationUpdate(PointF initScale, PointF initPos, Rect initCrop,
            float fraction, SurfaceControl.Transaction tx) {
        float scaleX = 1 + (initScale.x - 1) * (1 - fraction);
        float scaleY = 1 + (initScale.y - 1) * (1 - fraction);
        tx.setScale(mLeash, scaleX, scaleY);

        float posX = initPos.x + (mEndBounds.left - initPos.x) * fraction;
        float posY = initPos.y + (mEndBounds.top - initPos.y) * fraction;
        tx.setPosition(mLeash, posX, posY);

        Rect endCrop = new Rect(mEndBounds);
        endCrop.offsetTo(0, 0);
        mRectEvaluator.evaluate(fraction, initCrop, endCrop);
        tx.setCrop(mLeash, mAnimatedRect);
    }

    // no-ops

    @Override
    public void onAnimationCancel(@NonNull Animator animation) {}

    @Override
    public void onAnimationRepeat(@NonNull Animator animation) {}

    /**
     * Caches the initial transform relevant values for the bounds enter animation.
     *
     * Since enter PiP makes use of a config-at-end transition, initial transform needs to be
     * calculated differently from generic transitions.
     * @param pipChange PiP change received as a transition target.
     */
    public void setEnterStartState(@NonNull TransitionInfo.Change pipChange) {
        PipUtils.calcStartTransform(pipChange, mInitScale, mInitPos, mInitCrop);
    }
}
+22 −45
Original line number Diff line number Diff line
@@ -19,7 +19,6 @@ package com.android.wm.shell.pip2.animation;
import android.animation.Animator;
import android.animation.RectEvaluator;
import android.animation.ValueAnimator;
import android.annotation.IntDef;
import android.content.Context;
import android.graphics.Rect;
import android.view.Surface;
@@ -30,35 +29,22 @@ import androidx.annotation.Nullable;

import com.android.wm.shell.R;
import com.android.wm.shell.pip2.PipSurfaceTransactionHelper;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import com.android.wm.shell.shared.animation.Interpolators;

/**
 * Animator that handles bounds animations for entering / exiting PIP.
 * Animator that handles bounds animations for exit-via-expanding PIP.
 */
public class PipEnterExitAnimator extends ValueAnimator
public class PipExpandAnimator extends ValueAnimator
        implements ValueAnimator.AnimatorUpdateListener, ValueAnimator.AnimatorListener {
    @IntDef(prefix = {"BOUNDS_"}, value = {
            BOUNDS_ENTER,
            BOUNDS_EXIT
    })

    @Retention(RetentionPolicy.SOURCE)
    public @interface BOUNDS {}

    public static final int BOUNDS_ENTER = 0;
    public static final int BOUNDS_EXIT = 1;

    @NonNull private final SurfaceControl mLeash;
    @NonNull
    private final SurfaceControl mLeash;
    private final SurfaceControl.Transaction mStartTransaction;
    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;
    @Nullable
    private Runnable mAnimationStartCallback;
    @Nullable private Runnable mAnimationEndCallback;

    private final Rect mBaseBounds = new Rect();
@@ -78,7 +64,7 @@ public class PipEnterExitAnimator extends ValueAnimator
    private final RectEvaluator mInsetEvaluator;
    private final PipSurfaceTransactionHelper mPipSurfaceTransactionHelper;

    public PipEnterExitAnimator(Context context,
    public PipExpandAnimator(Context context,
            @NonNull SurfaceControl leash,
            SurfaceControl.Transaction startTransaction,
            SurfaceControl.Transaction finishTransaction,
@@ -86,7 +72,6 @@ public class PipEnterExitAnimator extends ValueAnimator
            @NonNull Rect startBounds,
            @NonNull Rect endBounds,
            @Nullable Rect sourceRectHint,
            @BOUNDS int direction,
            @Surface.Rotation int rotation) {
        mLeash = leash;
        mStartTransaction = startTransaction;
@@ -98,7 +83,6 @@ public class PipEnterExitAnimator extends ValueAnimator
        mRectEvaluator = new RectEvaluator(mAnimatedRect);
        mInsetEvaluator = new RectEvaluator(new Rect());
        mPipSurfaceTransactionHelper = new PipSurfaceTransactionHelper(context);
        mDirection = direction;
        mRotation = rotation;

        mSourceRectHint = sourceRectHint != null ? new Rect(sourceRectHint) : null;
@@ -113,12 +97,14 @@ public class PipEnterExitAnimator extends ValueAnimator

        mSurfaceControlTransactionFactory =
                new PipSurfaceTransactionHelper.VsyncSurfaceControlTransactionFactory();
        mEnterExitAnimationDuration = context.getResources()

        final int enterAnimationDuration = context.getResources()
                .getInteger(R.integer.config_pipEnterAnimationDuration);
        setDuration(enterAnimationDuration);

        setObjectValues(startBounds, endBounds);
        setDuration(mEnterExitAnimationDuration);
        setEvaluator(mRectEvaluator);
        setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
        addListener(this);
        addUpdateListener(this);
    }
@@ -147,9 +133,10 @@ public class PipEnterExitAnimator extends ValueAnimator
            // 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());
                            mBaseBounds, mAnimatedRect, getInsets(1f),
                            false /* isInPipDirection */, 1f)
                    .round(mFinishTransaction, mLeash, false /* applyCornerRadius */)
                    .shadow(mFinishTransaction, mLeash, false /* applyCornerRadius */);
        }
        if (mAnimationEndCallback != null) {
            mAnimationEndCallback.run();
@@ -160,32 +147,22 @@ 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

        Rect insets = getInsets(fraction);
        mPipSurfaceTransactionHelper.scaleAndCrop(tx, mLeash, mSourceRectHint,
                mBaseBounds, mAnimatedRect, insets, isInPipDirection(), fraction)
                .round(tx, mLeash, isInPipDirection())
                .shadow(tx, mLeash, isInPipDirection());
                        mBaseBounds, mAnimatedRect, insets, false /* isInPipDirection */, fraction)
                .round(tx, mLeash, false /* applyCornerRadius */)
                .shadow(tx, mLeash, false /* applyCornerRadius */);
        tx.apply();
    }

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

        final Rect startInsets = mSourceRectHintInsets;
        final Rect endInsets = mZeroInsets;
        return mInsetEvaluator.evaluate(fraction, startInsets, endInsets);
    }

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

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

    // no-ops

    @Override
+16 −31
Original line number Diff line number Diff line
@@ -56,7 +56,8 @@ import com.android.wm.shell.common.pip.PipMenuController;
import com.android.wm.shell.common.pip.PipUtils;
import com.android.wm.shell.pip.PipTransitionController;
import com.android.wm.shell.pip2.animation.PipAlphaAnimator;
import com.android.wm.shell.pip2.animation.PipEnterExitAnimator;
import com.android.wm.shell.pip2.animation.PipEnterAnimator;
import com.android.wm.shell.pip2.animation.PipExpandAnimator;
import com.android.wm.shell.shared.TransitionUtil;
import com.android.wm.shell.shared.pip.PipContentOverlay;
import com.android.wm.shell.sysui.ShellInit;
@@ -218,6 +219,7 @@ public class PipTransition extends PipTransitionController implements
            @NonNull SurfaceControl.Transaction startTransaction,
            @NonNull SurfaceControl.Transaction finishTransaction,
            @NonNull Transitions.TransitionFinishCallback finishCallback) {
        mFinishCallback = finishCallback;
        if (transition == mEnterTransition || info.getType() == TRANSIT_PIP) {
            mEnterTransition = null;
            // If we are in swipe PiP to Home transition we are ENTERING_PIP as a jumpcut transition
@@ -258,6 +260,7 @@ public class PipTransition extends PipTransitionController implements
        if (isRemovePipTransition(info)) {
            return removePipImmediately(info, startTransaction, finishTransaction, finishCallback);
        }
        mFinishCallback = null;
        return false;
    }

@@ -297,7 +300,6 @@ public class PipTransition extends PipTransitionController implements
            mBoundsChangeDuration = BOUNDS_CHANGE_JUMPCUT_DURATION;
        }

        mFinishCallback = finishCallback;
        mPipTransitionState.setState(PipTransitionState.CHANGING_PIP_BOUNDS, extra);
        return true;
    }
@@ -349,7 +351,6 @@ public class PipTransition extends PipTransitionController implements
            startTransaction.setMatrix(pipLeash, transformTensor, matrixTmp);
        }
        startTransaction.apply();
        finishCallback.onTransitionFinished(null /* finishWct */);
        finishInner();
        return true;
    }
@@ -386,14 +387,6 @@ public class PipTransition extends PipTransitionController implements
            return false;
        }

        WindowContainerToken pipTaskToken = pipChange.getContainer();
        if (pipTaskToken == null) {
            return false;
        }

        WindowContainerTransaction finishWct = new WindowContainerTransaction();
        SurfaceControl.Transaction tx = new SurfaceControl.Transaction();

        Rect startBounds = pipChange.getStartAbsBounds();
        Rect endBounds = pipChange.getEndAbsBounds();
        SurfaceControl pipLeash = mPipTransitionState.mPinnedTaskLeash;
@@ -405,29 +398,22 @@ public class PipTransition extends PipTransitionController implements
            sourceRectHint = pipChange.getTaskInfo().pictureInPictureParams.getSourceRectHint();
        }

        // For opening type transitions, if there is a non-pip change of mode TO_FRONT/OPEN,
        // For opening type transitions, if there is a change of mode TO_FRONT/OPEN,
        // make sure that change has alpha of 1f, since it's init state might be set to alpha=0f
        // by the Transitions framework to simplify Task opening transitions.
        if (TransitionUtil.isOpeningType(info.getType())) {
            for (TransitionInfo.Change change : info.getChanges()) {
                if (change.getLeash() == null || change == pipChange) continue;
                if (change.getLeash() == null) continue;
                if (change.getMode() == TRANSIT_OPEN || change.getMode() == TRANSIT_TO_FRONT) {
                    startTransaction.setAlpha(change.getLeash(), 1f);
                }
            }
        }

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

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

        animator.setAnimationEndCallback(() ->
                finishCallback.onTransitionFinished(finishWct));

        PipEnterAnimator animator = new PipEnterAnimator(mContext, pipLeash,
                startTransaction, finishTransaction, endBounds, sourceRectHint, Surface.ROTATION_0);
        animator.setAnimationStartCallback(() -> animator.setEnterStartState(pipChange));
        animator.setAnimationEndCallback(this::finishInner);
        animator.start();
        return true;
    }
@@ -452,11 +438,8 @@ public class PipTransition extends PipTransitionController implements

        PipAlphaAnimator animator = new PipAlphaAnimator(mContext, pipLeash, startTransaction,
                PipAlphaAnimator.FADE_IN);
        animator.setAnimationEndCallback(() -> {
            finishCallback.onTransitionFinished(null);
        // This should update the pip transition state accordingly after we stop playing.
            finishInner();
        });
        animator.setAnimationEndCallback(this::finishInner);

        animator.start();
        return true;
@@ -510,9 +493,9 @@ public class PipTransition extends PipTransitionController implements
            sourceRectHint = mPipTaskListener.getPictureInPictureParams().getSourceRectHint();
        }

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

        animator.setAnimationEndCallback(() -> {
            mPipTransitionState.setState(PipTransitionState.EXITED_PIP);
@@ -631,6 +614,7 @@ public class PipTransition extends PipTransitionController implements
    //

    private void finishInner() {
        finishTransition(null /* tx */);
        if (mPipTransitionState.getSwipePipToHomeOverlay() != null) {
            startOverlayFadeoutAnimation();
        } else if (mPipTransitionState.getState() == PipTransitionState.ENTERING_PIP) {
@@ -652,6 +636,7 @@ public class PipTransition extends PipTransitionController implements
        }
        if (mFinishCallback != null) {
            mFinishCallback.onTransitionFinished(wct);
            mFinishCallback = null;
        }
    }