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

Commit 3cfe087e authored by Riddle Hsu's avatar Riddle Hsu
Browse files

Revert^2 "Use a color container surface to animate rotation with wallpaper"

This reverts commit 09b5254d.
Reason for revert: reland

By default, WallpaperService has a 0.05f dim. And SystemUI's
DefaultDeviceEffectsApplier may set 0.6f for battery saver mode.

If the wallpaper surface is not opaque, it may be blending with
the surface behind. E.g.

Before animation starts:
 z=1 Wallpaper 0.6 alpha
 z=0 No other layer (black)

Animation starts:
 z=2 Wallpaper 0.6 alpha <--- looks brighter
 z=1 Bright (assume the content is light color) background layer

Animation ends: (flickering when removing the background layer)
 z=2 Wallpaper 0.6 alpha
 z=0 No other layer (black)

So wrap the surface which contains the wallpaper into a surface
with color that will animate from background color to black, then
the translucent wallpaper can have a smoother transition.

Bug: 326331384
Flag: com.android.window.flags.common_surface_animator
Test: Enable home rotation. Set a white color wallpaper.
      adb shell cmd battery unplug \
        && adb shell settings put global low_power 1
      (or "adb shell cmd wallpaper set-dim-amount 0.5")
      Rotate device.
      The end frame should not flickering from light to dark.

Change-Id: Ic4fcecf9dbe1dafc76c2356c13aa153a01d411a5
parent 340a1b19
Loading
Loading
Loading
Loading
+8 −5
Original line number Diff line number Diff line
@@ -361,8 +361,11 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                    final int anim = getRotationAnimationHint(change, info, mDisplayController);
                    isSeamlessDisplayChange = anim == ROTATION_ANIMATION_SEAMLESS;
                    if (!(isSeamlessDisplayChange || anim == ROTATION_ANIMATION_JUMPCUT)) {
                        startRotationAnimation(startTransaction, change, info, anim, animations,
                                onAnimFinish);
                        final int flags = wallpaperTransit != WALLPAPER_TRANSITION_NONE
                                && Flags.commonSurfaceAnimator()
                                ? ScreenRotationAnimation.FLAG_HAS_WALLPAPER : 0;
                        startRotationAnimation(startTransaction, change, info, anim, flags,
                                animations, onAnimFinish);
                        isDisplayRotationAnimationStarted = true;
                        continue;
                    }
@@ -414,7 +417,7 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
                if (change.getParent() == null && !change.hasFlags(FLAG_IS_DISPLAY)
                        && change.getStartRotation() != change.getEndRotation()) {
                    startRotationAnimation(startTransaction, change, info,
                            ROTATION_ANIMATION_ROTATE, animations, onAnimFinish);
                            ROTATION_ANIMATION_ROTATE, 0 /* flags */, animations, onAnimFinish);
                    continue;
                }
            }
@@ -699,12 +702,12 @@ public class DefaultTransitionHandler implements Transitions.TransitionHandler {
    }

    private void startRotationAnimation(SurfaceControl.Transaction startTransaction,
            TransitionInfo.Change change, TransitionInfo info, int animHint,
            TransitionInfo.Change change, TransitionInfo info, int animHint, int flags,
            ArrayList<Animator> animations, Runnable onAnimFinish) {
        final int rootIdx = TransitionUtil.rootIndexFor(change, info);
        final ScreenRotationAnimation anim = new ScreenRotationAnimation(mContext,
                mTransactionPool, startTransaction, change, info.getRoot(rootIdx).getLeash(),
                animHint);
                animHint, flags);
        // The rotation animation may consist of 3 animations: fade-out screenshot, fade-in real
        // content, and background color. The item of "animGroup" will be removed if the sub
        // animation is finished. Then if the list becomes empty, the rotation animation is done.
+79 −53
Original line number Diff line number Diff line
@@ -25,12 +25,9 @@ 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;
@@ -38,6 +35,7 @@ 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;
@@ -74,6 +72,7 @@ import java.util.ArrayList;
 */
class ScreenRotationAnimation {
    static final int MAX_ANIMATION_DURATION = 10 * 1000;
    static final int FLAG_HAS_WALLPAPER = 1;

    private final Context mContext;
    private final TransactionPool mTransactionPool;
@@ -98,6 +97,12 @@ 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
@@ -111,8 +116,8 @@ class ScreenRotationAnimation {
    /** Intensity of light/whiteness of the layout after rotation occurs. */
    private float mEndLuma;

    ScreenRotationAnimation(Context context, TransactionPool pool,
            Transaction t, TransitionInfo.Change change, SurfaceControl rootLeash, int animHint) {
    ScreenRotationAnimation(Context context, TransactionPool pool, Transaction t,
            TransitionInfo.Change change, SurfaceControl rootLeash, int animHint, int flags) {
        mContext = context;
        mTransactionPool = pool;
        mAnimHint = animHint;
@@ -170,11 +175,20 @@ class ScreenRotationAnimation {
                }
                hardwareBuffer.close();
            }
            if ((flags & FLAG_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(mSurfaceControl, new Rect(0, 0, mEndWidth, mEndHeight));
            t.setCrop(getEnterSurface(), new Rect(0, 0, mEndWidth, mEndHeight));

            if (!isCustomRotate()) {
                mBackColorSurface = new SurfaceControl.Builder()
@@ -202,6 +216,11 @@ class ScreenRotationAnimation {
        return mAnimHint == ROTATION_ANIMATION_CROSSFADE || mAnimHint == ROTATION_ANIMATION_JUMPCUT;
    }

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

    private void setScreenshotTransform(SurfaceControl.Transaction t) {
        if (mScreenshotLayer == null) {
            return;
@@ -314,7 +333,11 @@ class ScreenRotationAnimation {
        } else {
            startDisplayRotation(animations, finishCallback, mainExecutor);
            startScreenshotRotationAnimation(animations, finishCallback, mainExecutor);
            //startColorAnimation(mTransaction, animationScale);
            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);
            }
        }

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

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

    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);
    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);
        DefaultSurfaceAnimator.buildSurfaceAnimation(animations, animation, finishCallback,
                mTransactionPool, mainExecutor, adapter);
    }

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

    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);
    /** A no-op wrapper to provide animation duration. */
    private static class LumaAnimation extends Animation {
        LumaAnimation(long durationMillis) {
            setDuration(durationMillis);
        }
    }

    private static class LumaAnimationAdapter extends DefaultSurfaceAnimator.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, long currentPlayTime) {
            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);
        }
        t.apply();
    }
}