From c3cabe0af9038794402333bd48ec6ebf2ae17c4c Mon Sep 17 00:00:00 2001 From: Aleksandr Litovchenko Date: Mon, 9 Aug 2021 19:07:38 +0100 Subject: [PATCH] LockPatternView dot activation animation. Animate dot color when it's activated, duration is synchronized with line disappearing animation. Do not animate dot size if it's not needed. Bug: 196067470 Bug: 193417780 Tests: Manually Change-Id: I13fa478f434b2c56a5818a4b639f3e38f7c05c4d (cherry picked from commit 450633259bc6283f25d98d5e056d39e74bcb8cc7) --- .../internal/widget/LockPatternView.java | 69 +++++++++++++++---- core/res/res/values/attrs.xml | 2 + 2 files changed, 59 insertions(+), 12 deletions(-) diff --git a/core/java/com/android/internal/widget/LockPatternView.java b/core/java/com/android/internal/widget/LockPatternView.java index e4385a697c85a..eb0a7258c7331 100644 --- a/core/java/com/android/internal/widget/LockPatternView.java +++ b/core/java/com/android/internal/widget/LockPatternView.java @@ -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,7 @@ 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 final CellState[][] mCellStates; private final int mDotSize; @@ -156,6 +159,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,6 +241,7 @@ 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 @@ -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,20 +804,52 @@ 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() { - @Override - public void run() { - startRadiusAnimation(mDotSizeActivated/2, mDotSize/2, 192, - mFastOutSlowInInterpolator, - cellState, null); - } - }); + if (mDotSize != mDotSizeActivated) { + startRadiusAnimation(mDotSize / 2, mDotSizeActivated / 2, 96, + mLinearOutSlowInInterpolator, + cellState, new Runnable() { + @Override + public void run() { + startRadiusAnimation(mDotSizeActivated / 2, mDotSize / 2, 192, + mFastOutSlowInInterpolator, + cellState, null); + } + }); + } + startDotActivationColorAnimation(cellState); startLineEndAnimation(cellState, mInProgressX, mInProgressY, getCenterXForColumn(cell.column), getCenterYForRow(cell.row)); startLineDisappearingAnimation(cellState); } + private void startDotActivationColorAnimation(CellState cellState) { + ValueAnimator.AnimatorUpdateListener updateListener = + new ValueAnimator.AnimatorUpdateListener() { + @Override + public void onAnimationUpdate(ValueAnimator 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); + set.start(); + } + /** * 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. @@ -1295,7 +1333,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 +1434,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) { - mPaint.setColor(getDotColor()); + 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); } diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index a5f505176d5d1..a56ed147876a2 100644 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -8658,6 +8658,8 @@ + +