Merge changes Ieac0bb3f,I13fa478f

* changes:
  LockPatternView: Combine all cell activation animations.
  LockPatternView dot activation animation.
This commit is contained in:
TreeHugger Robot
2021-09-03 15:59:59 +00:00
committed by Android (Google) Code Review
2 changed files with 109 additions and 78 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,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() {
@Override
public void run() {
startRadiusAnimation(mDotSizeActivated/2, mDotSize/2, 192,
mFastOutSlowInInterpolator,
cellState, null);
}
});
startLineEndAnimation(cellState, mInProgressX, mInProgressY,
getCenterXForColumn(cell.column), getCenterYForRow(cell.row));
startLineDisappearingAnimation(cellState);
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 onAnimationEnd(Animator animation) {
cellState.activationAnimator = null;
invalidate();
}
});
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) {
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.addUpdateListener(animation -> {
float t = (float) animation.getAnimatedValue();
state.lineEndX = (1 - t) * startX + t * targetX;
state.lineEndY = (1 - t) * startY + t * targetY;
invalidate();
});
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) {
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();
private Animator createDotRadiusAnimation(CellState state) {
float defaultRadius = mDotSize / 2f;
float activatedRadius = mDotSizeActivated / 2f;
ValueAnimator.AnimatorUpdateListener animatorUpdateListener =
animation -> {
state.radius = (float) animation.getAnimatedValue();
invalidate();
};
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) {
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>