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

Commit e88edfdd authored by TreeHugger Robot's avatar TreeHugger Robot Committed by Android (Google) Code Review
Browse files

Merge changes Ieac0bb3f,I13fa478f

* changes:
  LockPatternView: Combine all cell activation animations.
  LockPatternView dot activation animation.
parents a2d487e3 f5ca9913
Loading
Loading
Loading
Loading
+107 −78
Original line number Diff line number Diff line
@@ -18,6 +18,7 @@ package com.android.internal.widget;

import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
@@ -56,6 +57,7 @@ import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;

import com.android.internal.R;
import com.android.internal.graphics.ColorUtils;

import java.util.ArrayList;
import java.util.List;
@@ -77,6 +79,9 @@ public class LockPatternView extends View {
    private static final int LINE_END_ANIMATION_DURATION_MILLIS = 50;
    private static final int LINE_FADE_OUT_DURATION_MILLIS = 500;
    private static final int LINE_FADE_OUT_DELAY_MILLIS = 150;
    private static final int DOT_ACTIVATION_DURATION_MILLIS = 50;
    private static final int DOT_RADIUS_INCREASE_DURATION_MILLIS = 96;
    private static final int DOT_RADIUS_DECREASE_DURATION_MILLIS = 192;
    private final CellState[][] mCellStates;

    private final int mDotSize;
@@ -156,6 +161,7 @@ public class LockPatternView extends View {
    private int mErrorColor;
    private int mSuccessColor;
    private int mDotColor;
    private int mDotActivatedColor;

    private final Interpolator mFastOutSlowInInterpolator;
    private final Interpolator mLinearOutSlowInInterpolator;
@@ -237,12 +243,11 @@ public class LockPatternView extends View {
        float radius;
        float translationY;
        float alpha = 1f;
        float activationAnimationProgress;
        public float lineEndX = Float.MIN_VALUE;
        public float lineEndY = Float.MIN_VALUE;
        @Nullable
        ValueAnimator lineEndAnimator;
        @Nullable
        ValueAnimator lineDisappearingAnimator;
        Animator activationAnimator;
     }

    /**
@@ -330,6 +335,7 @@ public class LockPatternView extends View {
        mErrorColor = a.getColor(R.styleable.LockPatternView_errorColor, 0);
        mSuccessColor = a.getColor(R.styleable.LockPatternView_successColor, 0);
        mDotColor = a.getColor(R.styleable.LockPatternView_dotColor, mRegularColor);
        mDotActivatedColor = a.getColor(R.styleable.LockPatternView_dotActivatedColor, mDotColor);

        int pathColor = a.getColor(R.styleable.LockPatternView_pathColor, mRegularColor);
        mPathPaint.setColor(pathColor);
@@ -798,93 +804,111 @@ public class LockPatternView extends View {

    private void startCellActivatedAnimation(Cell cell) {
        final CellState cellState = mCellStates[cell.row][cell.column];
        startRadiusAnimation(mDotSize/2, mDotSizeActivated/2, 96, mLinearOutSlowInInterpolator,
                cellState, new Runnable() {

        if (cellState.activationAnimator != null) {
            cellState.activationAnimator.cancel();
        }
        AnimatorSet animatorSet = new AnimatorSet();
        AnimatorSet.Builder animatorSetBuilder = animatorSet
                .play(createLineDisappearingAnimation())
                .with(createLineEndAnimation(cellState, mInProgressX, mInProgressY,
                        getCenterXForColumn(cell.column), getCenterYForRow(cell.row)));
        if (mDotSize != mDotSizeActivated) {
            animatorSetBuilder.with(createDotRadiusAnimation(cellState));
        }
        if (mDotColor != mDotActivatedColor) {
            animatorSetBuilder.with(createDotActivationColorAnimation(cellState));
        }

        animatorSet.addListener(new AnimatorListenerAdapter() {
            @Override
                    public void run() {
                        startRadiusAnimation(mDotSizeActivated/2, mDotSize/2, 192,
                                mFastOutSlowInInterpolator,
                                cellState, null);
            public void onAnimationEnd(Animator animation) {
                cellState.activationAnimator = null;
                invalidate();
            }
        });
        startLineEndAnimation(cellState, mInProgressX, mInProgressY,
                getCenterXForColumn(cell.column), getCenterYForRow(cell.row));
        startLineDisappearingAnimation(cellState);
        cellState.activationAnimator = animatorSet;
        animatorSet.start();
    }

    private Animator createDotActivationColorAnimation(CellState cellState) {
        ValueAnimator.AnimatorUpdateListener updateListener =
                valueAnimator -> {
                    cellState.activationAnimationProgress =
                            (float) valueAnimator.getAnimatedValue();
                    invalidate();
                };
        ValueAnimator activateAnimator = ValueAnimator.ofFloat(0f, 1f);
        ValueAnimator deactivateAnimator = ValueAnimator.ofFloat(1f, 0f);
        activateAnimator.addUpdateListener(updateListener);
        deactivateAnimator.addUpdateListener(updateListener);
        activateAnimator.setInterpolator(mFastOutSlowInInterpolator);
        deactivateAnimator.setInterpolator(mLinearOutSlowInInterpolator);

        // Align dot animation duration with line fade out animation.
        activateAnimator.setDuration(DOT_ACTIVATION_DURATION_MILLIS);
        deactivateAnimator.setDuration(DOT_ACTIVATION_DURATION_MILLIS);
        AnimatorSet set = new AnimatorSet();
        set.play(deactivateAnimator)
                .after(LINE_FADE_OUT_DELAY_MILLIS + LINE_FADE_OUT_DURATION_MILLIS
                        - DOT_ACTIVATION_DURATION_MILLIS * 2)
                .after(activateAnimator);
        return set;
    }

    /**
     * On the last frame before cell activates the end point of in progress line is not aligned
     * with dot center so we execute a short animation moving the end point to exact dot center.
     */
    private void startLineEndAnimation(final CellState state,
    private Animator createLineEndAnimation(final CellState state,
            final float startX, final float startY, final float targetX, final float targetY) {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
        valueAnimator.addUpdateListener(animation -> {
            float t = (float) animation.getAnimatedValue();
            state.lineEndX = (1 - t) * startX + t * targetX;
            state.lineEndY = (1 - t) * startY + t * targetY;
            invalidate();
            }
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                state.lineEndAnimator = null;
            }
        });
        valueAnimator.setInterpolator(mFastOutSlowInInterpolator);
        valueAnimator.setDuration(LINE_END_ANIMATION_DURATION_MILLIS);
        valueAnimator.start();
        state.lineEndAnimator = valueAnimator;
        return valueAnimator;
    }

    /**
     * Starts animator to fade out a line segment. It does only invalidate because all the
     * transitions are applied in {@code onDraw} method.
     */
    private void startLineDisappearingAnimation(final CellState state) {
    private Animator createLineDisappearingAnimation() {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                invalidate();
            }
        });
        valueAnimator.addListener(new AnimatorListenerAdapter() {
            @Override
            public void onAnimationEnd(Animator animation) {
                state.lineDisappearingAnimator = null;
            }
        });
        valueAnimator.addUpdateListener(animation -> invalidate());
        valueAnimator.setStartDelay(LINE_FADE_OUT_DELAY_MILLIS);
        valueAnimator.setDuration(LINE_FADE_OUT_DURATION_MILLIS);
        valueAnimator.start();
        state.lineDisappearingAnimator = valueAnimator;
        return valueAnimator;
    }

    private void startRadiusAnimation(float start, float end, long duration,
            Interpolator interpolator, final CellState state, final Runnable endRunnable) {
        ValueAnimator valueAnimator = ValueAnimator.ofFloat(start, end);
        valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
    private Animator createDotRadiusAnimation(CellState state) {
        float defaultRadius = mDotSize / 2f;
        float activatedRadius = mDotSizeActivated / 2f;

        ValueAnimator.AnimatorUpdateListener animatorUpdateListener =
                animation -> {
                    state.radius = (float) animation.getAnimatedValue();
                    invalidate();
            }
        });
        if (endRunnable != null) {
            valueAnimator.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    endRunnable.run();
                }
            });
        }
        valueAnimator.setInterpolator(interpolator);
        valueAnimator.setDuration(duration);
        valueAnimator.start();
                };

        ValueAnimator activationAnimator = ValueAnimator.ofFloat(defaultRadius, activatedRadius);
        activationAnimator.addUpdateListener(animatorUpdateListener);
        activationAnimator.setInterpolator(mLinearOutSlowInInterpolator);
        activationAnimator.setDuration(DOT_RADIUS_INCREASE_DURATION_MILLIS);

        ValueAnimator deactivationAnimator = ValueAnimator.ofFloat(activatedRadius, defaultRadius);
        deactivationAnimator.addUpdateListener(animatorUpdateListener);
        deactivationAnimator.setInterpolator(mFastOutSlowInInterpolator);
        deactivationAnimator.setDuration(DOT_RADIUS_DECREASE_DURATION_MILLIS);

        AnimatorSet set = new AnimatorSet();
        set.playSequentially(activationAnimator, deactivationAnimator);
        return set;
    }

    // helper method to find which cell a point maps to
@@ -1098,16 +1122,14 @@ public class LockPatternView extends View {
        for (int i = 0; i < 3; i++) {
            for (int j = 0; j < 3; j++) {
                CellState state = mCellStates[i][j];
                if (state.lineEndAnimator != null) {
                    state.lineEndAnimator.cancel();
                    state.lineEndAnimator = null;
                if (state.activationAnimator != null) {
                    state.activationAnimator.cancel();
                    state.activationAnimator = null;
                    state.radius = mDotSize / 2f;
                    state.activationAnimationProgress = 0f;
                    state.lineEndX = Float.MIN_VALUE;
                    state.lineEndY = Float.MIN_VALUE;
                }
                if (state.lineDisappearingAnimator != null) {
                    state.lineDisappearingAnimator.cancel();
                    state.lineDisappearingAnimator = null;
                }
            }
        }
    }
@@ -1295,7 +1317,8 @@ public class LockPatternView extends View {
                                cellState.hwRadius, cellState.hwPaint);
                    } else {
                        drawCircle(canvas, (int) centerX, (int) centerY + translationY,
                                cellState.radius, drawLookup[i][j], cellState.alpha);
                                cellState.radius, drawLookup[i][j], cellState.alpha,
                                cellState.activationAnimationProgress);
                    }
                }
            }
@@ -1395,8 +1418,14 @@ public class LockPatternView extends View {
     * @param partOfPattern Whether this circle is part of the pattern.
     */
    private void drawCircle(Canvas canvas, float centerX, float centerY, float radius,
            boolean partOfPattern, float alpha) {
            boolean partOfPattern, float alpha, float activationAnimationProgress) {
        if (mFadePattern && !mInStealthMode) {
            int resultColor = ColorUtils.blendARGB(mDotColor, mDotActivatedColor,
                    /* ratio= */ activationAnimationProgress);
            mPaint.setColor(resultColor);
        } else {
            mPaint.setColor(getDotColor());
        }
        mPaint.setAlpha((int) (alpha * 255));
        canvas.drawCircle(centerX, centerY, radius, mPaint);
    }
+2 −0
Original line number Diff line number Diff line
@@ -8658,6 +8658,8 @@
        <attr name="successColor" format="color|reference"/>
        <!-- The dot color -->
        <attr name="dotColor" format="color|reference"/>
        <!-- Color of the dot when it's activated -->
        <attr name="dotActivatedColor" format="color|reference"/>
    </declare-styleable>