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

Commit dc129f11 authored by Android Build Coastguard Worker's avatar Android Build Coastguard Worker
Browse files

Merge cherrypicks of ['googleplex-android-review.googlesource.com/29549970',...

Merge cherrypicks of ['googleplex-android-review.googlesource.com/29549970', 'googleplex-android-review.googlesource.com/29550179'] into sparse-12399983-L32400030006611955.
SPARSE_CHANGE: I5b88dcfcbde2ae8966f08ca9776d7332940c0451
SPARSE_CHANGE: Idb487735888381bc4ed2f46ce48d540be8e83528

Change-Id: I3f0f3af07591ea311adeea01f41d37993c15b0c3
parents 41d98c44 1b673d00
Loading
Loading
Loading
Loading
+37 −93
Original line number Diff line number Diff line
@@ -358,12 +358,9 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {

            if (mode == TRANSIT_CHANGE && change.hasFlags(FLAG_IS_DISPLAY)) {
                if (info.getType() == TRANSIT_CHANGE) {
                    int anim = getRotationAnimationHint(change, info, mDisplayController);
                    final int anim = getRotationAnimationHint(change, info, mDisplayController);
                    isSeamlessDisplayChange = anim == ROTATION_ANIMATION_SEAMLESS;
                    if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) {
                        if (wallpaperTransit != WALLPAPER_TRANSITION_NONE) {
                            anim |= ScreenRotationAnimation.ANIMATION_HINT_HAS_WALLPAPER;
                        }
                        startRotationAnimation(startTransaction, change, info, anim, animations,
                                onAnimFinish);
                        isDisplayRotationAnimationStarted = true;
@@ -829,26 +826,24 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
            @NonNull Runnable finishCallback, @NonNull TransactionPool pool,
            @NonNull ShellExecutor mainExecutor, @Nullable Point position, float cornerRadius,
            @Nullable Rect clipRect, boolean isActivity) {
        final DefaultAnimationAdapter adapter = new DefaultAnimationAdapter(anim, leash,
                position, clipRect, cornerRadius, isActivity);
        buildSurfaceAnimation(animations, anim, finishCallback, pool, mainExecutor, adapter);
    }

    /** Builds an animator for the surface and adds it to the `animations` list. */
    static void buildSurfaceAnimation(@NonNull ArrayList<Animator> animations,
            @NonNull Animation anim, @NonNull Runnable finishCallback,
            @NonNull TransactionPool pool, @NonNull ShellExecutor mainExecutor,
            @NonNull AnimationAdapter updateListener) {
        final SurfaceControl.Transaction transaction = pool.acquire();
        updateListener.setTransaction(transaction);
        final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
        final Transformation transformation = new Transformation();
        final float[] matrix = new float[9];
        // Animation length is already expected to be scaled.
        va.overrideDurationScale(1.0f);
        va.setDuration(anim.computeDurationHint());
        final ValueAnimator.AnimatorUpdateListener updateListener = animation -> {
            final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime());

            applyTransformation(currentPlayTime, transaction, leash, anim, transformation, matrix,
                    position, cornerRadius, clipRect, isActivity);
        };
        va.addUpdateListener(updateListener);

        final Runnable finisher = () -> {
            updateListener.onAnimationUpdate(va);
            applyTransformation(va.getDuration(), transaction, leash, anim, transformation, matrix,
                    position, cornerRadius, clipRect, isActivity);

            pool.release(transaction);
            mainExecutor.execute(() -> {
@@ -1012,88 +1007,37 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                || animType == ANIM_FROM_STYLE;
    }

    /** The animation adapter for buildSurfaceAnimation. */
    abstract static class AnimationAdapter implements ValueAnimator.AnimatorUpdateListener {
        @NonNull final SurfaceControl mLeash;
        @NonNull SurfaceControl.Transaction mTransaction;
        private Choreographer mChoreographer;

        AnimationAdapter(@NonNull SurfaceControl leash) {
            mLeash = leash;
        }

        void setTransaction(@NonNull SurfaceControl.Transaction transaction) {
            mTransaction = transaction;
        }

        @Override
        public void onAnimationUpdate(@NonNull ValueAnimator animator) {
            applyTransformation(animator);
            if (mChoreographer == null) {
                mChoreographer = Choreographer.getInstance();
            }
            mTransaction.setFrameTimelineVsync(mChoreographer.getVsyncId());
            mTransaction.apply();
        }

        abstract void applyTransformation(@NonNull ValueAnimator animator);
    }

    private static class DefaultAnimationAdapter extends AnimationAdapter {
        final Transformation mTransformation = new Transformation();
        final float[] mMatrix = new float[9];
        @NonNull final Animation mAnim;
        @Nullable final Point mPosition;
        @Nullable final Rect mClipRect;
        final float mCornerRadius;
        final boolean mIsActivity;

        DefaultAnimationAdapter(@NonNull Animation anim, @NonNull SurfaceControl leash,
                @Nullable Point position, @Nullable Rect clipRect, float cornerRadius,
    private static void applyTransformation(long time, SurfaceControl.Transaction t,
            SurfaceControl leash, Animation anim, Transformation tmpTransformation, float[] matrix,
            Point position, float cornerRadius, @Nullable Rect immutableClipRect,
            boolean isActivity) {
            super(leash);
            mAnim = anim;
            mPosition = (position != null && (position.x != 0 || position.y != 0))
                    ? position : null;
            mClipRect = (clipRect != null && !clipRect.isEmpty()) ? clipRect : null;
            mCornerRadius = cornerRadius;
            mIsActivity = isActivity;
        }

        @Override
        void applyTransformation(@NonNull ValueAnimator animator) {
            final long currentPlayTime = Math.min(animator.getDuration(),
                    animator.getCurrentPlayTime());
            final Transformation transformation = mTransformation;
            final SurfaceControl.Transaction t = mTransaction;
            final SurfaceControl leash = mLeash;
            transformation.clear();
            mAnim.getTransformation(currentPlayTime, transformation);
        tmpTransformation.clear();
        anim.getTransformation(time, tmpTransformation);
        if (com.android.graphics.libgui.flags.Flags.edgeExtensionShader()
                    && mIsActivity && mAnim.getExtensionEdges() != 0) {
                t.setEdgeExtensionEffect(leash, mAnim.getExtensionEdges());
                && anim.getExtensionEdges() != 0x0 && isActivity) {
            t.setEdgeExtensionEffect(leash, anim.getExtensionEdges());
        }
            if (mPosition != null) {
                transformation.getMatrix().postTranslate(mPosition.x, mPosition.y);
        if (position != null) {
            tmpTransformation.getMatrix().postTranslate(position.x, position.y);
        }
            t.setMatrix(leash, transformation.getMatrix(), mMatrix);
            t.setAlpha(leash, transformation.getAlpha());
        t.setMatrix(leash, tmpTransformation.getMatrix(), matrix);
        t.setAlpha(leash, tmpTransformation.getAlpha());

            if (mClipRect != null) {
                Rect clipRect = mClipRect;
                final Insets extensionInsets = Insets.min(transformation.getInsets(), Insets.NONE);
                if (!extensionInsets.equals(Insets.NONE)) {
                    // Clip out any overflowing edge extension.
                    clipRect = new Rect(mClipRect);
        final Rect clipRect = immutableClipRect == null ? null : new Rect(immutableClipRect);
        Insets extensionInsets = Insets.min(tmpTransformation.getInsets(), Insets.NONE);
        if (!extensionInsets.equals(Insets.NONE) && clipRect != null && !clipRect.isEmpty()) {
            // Clip out any overflowing edge extension
            clipRect.inset(extensionInsets);
            t.setCrop(leash, clipRect);
        }
                if (mCornerRadius > 0 && mAnim.hasRoundedCorners()) {
                    // Rounded corner can only be applied if a crop is set.

        if (anim.hasRoundedCorners() && cornerRadius > 0 && clipRect != null) {
            // We can only apply rounded corner if a crop is set
            t.setCrop(leash, clipRect);
                    t.setCornerRadius(leash, mCornerRadius);
                }
            }
            t.setCornerRadius(leash, cornerRadius);
        }

        t.setFrameTimelineVsync(Choreographer.getInstance().getVsyncId());
        t.apply();
    }
}
+55 −83
Original line number Diff line number Diff line
@@ -25,9 +25,12 @@ import static com.android.wm.shell.transition.DefaultTransitionHandler.buildSurf
import static com.android.wm.shell.transition.Transitions.TAG;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ArgbEvaluator;
import android.animation.ValueAnimator;
import android.annotation.NonNull;
import android.content.Context;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.hardware.HardwareBuffer;
@@ -35,7 +38,6 @@ import android.util.Slog;
import android.view.Surface;
import android.view.SurfaceControl;
import android.view.SurfaceControl.Transaction;
import android.view.animation.AccelerateInterpolator;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.window.ScreenCapture;
@@ -72,9 +74,6 @@ import java.util.ArrayList;
 */
class ScreenRotationAnimation {
    static final int MAX_ANIMATION_DURATION = 10 * 1000;
    static final int ANIMATION_HINT_HAS_WALLPAPER = 1 << 8;
    /** It must cover all WindowManager#ROTATION_ANIMATION_*. */
    private static final int ANIMATION_TYPE_MASK = 0xff;

    private final Context mContext;
    private final TransactionPool mTransactionPool;
@@ -82,7 +81,7 @@ class ScreenRotationAnimation {
    /** The leash of the changing window container. */
    private final SurfaceControl mSurfaceControl;

    private final int mAnimType;
    private final int mAnimHint;
    private final int mStartWidth;
    private final int mStartHeight;
    private final int mEndWidth;
@@ -99,12 +98,6 @@ class ScreenRotationAnimation {
    private SurfaceControl mBackColorSurface;
    /** The leash using to animate screenshot layer. */
    private final SurfaceControl mAnimLeash;
    /**
     * The container with background color for {@link #mSurfaceControl}. It is only created if
     * {@link #mSurfaceControl} may be translucent. E.g. visible wallpaper with alpha < 1 (dimmed).
     * That prevents flickering of alpha blending.
     */
    private SurfaceControl mBackEffectSurface;

    // The current active animation to move from the old to the new rotated
    // state.  Which animation is run here will depend on the old and new
@@ -122,7 +115,7 @@ class ScreenRotationAnimation {
            Transaction t, TransitionInfo.Change change, SurfaceControl rootLeash, int animHint) {
        mContext = context;
        mTransactionPool = pool;
        mAnimType = animHint & ANIMATION_TYPE_MASK;
        mAnimHint = animHint;

        mSurfaceControl = change.getLeash();
        mStartWidth = change.getStartAbsBounds().width();
@@ -177,20 +170,11 @@ class ScreenRotationAnimation {
                }
                hardwareBuffer.close();
            }
            if ((animHint & ANIMATION_HINT_HAS_WALLPAPER) != 0) {
                mBackEffectSurface = new SurfaceControl.Builder()
                        .setCallsite("ShellRotationAnimation").setParent(rootLeash)
                        .setEffectLayer().setOpaque(true).setName("BackEffect").build();
                t.reparent(mSurfaceControl, mBackEffectSurface)
                        .setColor(mBackEffectSurface,
                                new float[] {mStartLuma, mStartLuma, mStartLuma})
                        .show(mBackEffectSurface);
            }

            t.setLayer(mAnimLeash, SCREEN_FREEZE_LAYER_BASE);
            t.show(mAnimLeash);
            // Crop the real content in case it contains a larger child layer, e.g. wallpaper.
            t.setCrop(getEnterSurface(), new Rect(0, 0, mEndWidth, mEndHeight));
            t.setCrop(mSurfaceControl, new Rect(0, 0, mEndWidth, mEndHeight));

            if (!isCustomRotate()) {
                mBackColorSurface = new SurfaceControl.Builder()
@@ -215,12 +199,7 @@ class ScreenRotationAnimation {
    }

    private boolean isCustomRotate() {
        return mAnimType == ROTATION_ANIMATION_CROSSFADE || mAnimType == ROTATION_ANIMATION_JUMPCUT;
    }

    /** Returns the surface which contains the real content to animate enter. */
    private SurfaceControl getEnterSurface() {
        return mBackEffectSurface != null ? mBackEffectSurface : mSurfaceControl;
        return mAnimHint == ROTATION_ANIMATION_CROSSFADE || mAnimHint == ROTATION_ANIMATION_JUMPCUT;
    }

    private void setScreenshotTransform(SurfaceControl.Transaction t) {
@@ -281,7 +260,7 @@ class ScreenRotationAnimation {
        final boolean customRotate = isCustomRotate();
        if (customRotate) {
            mRotateExitAnimation = AnimationUtils.loadAnimation(mContext,
                    mAnimType == ROTATION_ANIMATION_JUMPCUT ? R.anim.rotation_animation_jump_exit
                    mAnimHint == ROTATION_ANIMATION_JUMPCUT ? R.anim.rotation_animation_jump_exit
                            : R.anim.rotation_animation_xfade_exit);
            mRotateEnterAnimation = AnimationUtils.loadAnimation(mContext,
                    R.anim.rotation_animation_enter);
@@ -335,11 +314,7 @@ class ScreenRotationAnimation {
        } else {
            startDisplayRotation(animations, finishCallback, mainExecutor);
            startScreenshotRotationAnimation(animations, finishCallback, mainExecutor);
            if (mBackEffectSurface != null && mStartLuma > 0.1f) {
                // Animate from the color of background to black for smooth alpha blending.
                buildLumaAnimation(animations, mStartLuma, 0f /* endLuma */, mBackEffectSurface,
                        animationScale, finishCallback, mainExecutor);
            }
            //startColorAnimation(mTransaction, animationScale);
        }

        return true;
@@ -347,7 +322,7 @@ class ScreenRotationAnimation {

    private void startDisplayRotation(@NonNull ArrayList<Animator> animations,
            @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
        buildSurfaceAnimation(animations, mRotateEnterAnimation, getEnterSurface(), finishCallback,
        buildSurfaceAnimation(animations, mRotateEnterAnimation, mSurfaceControl, finishCallback,
                mTransactionPool, mainExecutor, null /* position */, 0 /* cornerRadius */,
                null /* clipRect */, false /* isActivity */);
    }
@@ -366,17 +341,40 @@ class ScreenRotationAnimation {
                null /* clipRect */, false /* isActivity */);
    }

    private void buildLumaAnimation(@NonNull ArrayList<Animator> animations,
            float startLuma, float endLuma, SurfaceControl surface, float animationScale,
            @NonNull Runnable finishCallback, @NonNull ShellExecutor mainExecutor) {
        final long durationMillis = (long) (mContext.getResources().getInteger(
                R.integer.config_screen_rotation_color_transition) * animationScale);
        final LumaAnimation animation = new LumaAnimation(durationMillis);
        // Align the end with the enter animation.
        animation.setStartOffset(mRotateEnterAnimation.getDuration() - durationMillis);
        final LumaAnimationAdapter adapter = new LumaAnimationAdapter(surface, startLuma, endLuma);
        buildSurfaceAnimation(animations, animation, finishCallback, mTransactionPool,
                mainExecutor, adapter);
    private void startColorAnimation(float animationScale, @NonNull ShellExecutor animExecutor) {
        int colorTransitionMs = mContext.getResources().getInteger(
                R.integer.config_screen_rotation_color_transition);
        final float[] rgbTmpFloat = new float[3];
        final int startColor = Color.rgb(mStartLuma, mStartLuma, mStartLuma);
        final int endColor = Color.rgb(mEndLuma, mEndLuma, mEndLuma);
        final long duration = colorTransitionMs * (long) animationScale;
        final Transaction t = mTransactionPool.acquire();

        final ValueAnimator va = ValueAnimator.ofFloat(0f, 1f);
        // Animation length is already expected to be scaled.
        va.overrideDurationScale(1.0f);
        va.setDuration(duration);
        va.addUpdateListener(animation -> {
            final long currentPlayTime = Math.min(va.getDuration(), va.getCurrentPlayTime());
            final float fraction = currentPlayTime / va.getDuration();
            applyColor(startColor, endColor, rgbTmpFloat, fraction, mBackColorSurface, t);
        });
        va.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationCancel(Animator animation) {
                applyColor(startColor, endColor, rgbTmpFloat, 1f /* fraction */, mBackColorSurface,
                        t);
                mTransactionPool.release(t);
            }

            @Override
            public void onAnimationEnd(Animator animation) {
                applyColor(startColor, endColor, rgbTmpFloat, 1f /* fraction */, mBackColorSurface,
                        t);
                mTransactionPool.release(t);
            }
        });
        animExecutor.execute(va::start);
    }

    public void kill() {
@@ -391,47 +389,21 @@ class ScreenRotationAnimation {
        if (mBackColorSurface != null && mBackColorSurface.isValid()) {
            t.remove(mBackColorSurface);
        }
        if (mBackEffectSurface != null && mBackEffectSurface.isValid()) {
            t.remove(mBackEffectSurface);
        }
        t.apply();
        mTransactionPool.release(t);
    }

    /** A no-op wrapper to provide animation duration. */
    private static class LumaAnimation extends Animation {
        LumaAnimation(long durationMillis) {
            setDuration(durationMillis);
        }
    }

    private static class LumaAnimationAdapter extends DefaultTransitionHandler.AnimationAdapter {
        final float[] mColorArray = new float[3];
        final float mStartLuma;
        final float mEndLuma;
        final AccelerateInterpolator mInterpolation;

        LumaAnimationAdapter(@NonNull SurfaceControl leash, float startLuma, float endLuma) {
            super(leash);
            mStartLuma = startLuma;
            mEndLuma = endLuma;
            // Make the initial progress color lighter if the background is light. That avoids
            // darker content when fading into the entering surface.
            final float factor = Math.min(3f, (Math.max(0.5f, mStartLuma) - 0.5f) * 10);
            Slog.d(TAG, "Luma=" + mStartLuma + " factor=" + factor);
            mInterpolation = factor > 0.5f ? new AccelerateInterpolator(factor) : null;
        }

        @Override
        void applyTransformation(ValueAnimator animator) {
            final float fraction = mInterpolation != null
                    ? mInterpolation.getInterpolation(animator.getAnimatedFraction())
                    : animator.getAnimatedFraction();
            final float luma = mStartLuma + fraction * (mEndLuma - mStartLuma);
            mColorArray[0] = luma;
            mColorArray[1] = luma;
            mColorArray[2] = luma;
            mTransaction.setColor(mLeash, mColorArray);
    private static void applyColor(int startColor, int endColor, float[] rgbFloat,
            float fraction, SurfaceControl surface, SurfaceControl.Transaction t) {
        final int color = (Integer) ArgbEvaluator.getInstance().evaluate(fraction, startColor,
                endColor);
        Color middleColor = Color.valueOf(color);
        rgbFloat[0] = middleColor.red();
        rgbFloat[1] = middleColor.green();
        rgbFloat[2] = middleColor.blue();
        if (surface.isValid()) {
            t.setColor(surface, rgbFloat);
        }
        t.apply();
    }
}