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)
This commit is contained in:
Aleksandr Litovchenko
2021-08-09 19:07:38 +01:00
parent 08e34241c7
commit c3cabe0af9
2 changed files with 59 additions and 12 deletions

View File

@@ -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);
}

View File

@@ -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>