Merge changes Ieac0bb3f,I13fa478f
* changes: LockPatternView: Combine all cell activation animations. LockPatternView dot activation animation.
This commit is contained in:
committed by
Android (Google) Code Review
commit
e88edfdd4d
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user