Merge "Add new line disappearing animation to LockPatternView."

This commit is contained in:
TreeHugger Robot
2021-09-03 15:58:57 +00:00
committed by Android (Google) Code Review
3 changed files with 125 additions and 25 deletions

View File

@@ -19,16 +19,20 @@ package com.android.internal.widget;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.compat.annotation.UnsupportedAppUsage;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.CanvasProperty;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RecordingCanvas;
import android.graphics.Rect;
import android.graphics.Shader;
import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.os.Bundle;
@@ -70,7 +74,9 @@ public class LockPatternView extends View {
private static final int ASPECT_LOCK_HEIGHT = 2; // Fixed height; width will be minimum of (w,h)
private static final boolean PROFILE_DRAWING = false;
private static final float LINE_FADE_ALPHA_MULTIPLIER = 1.5f;
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 final CellState[][] mCellStates;
private final int mDotSize;
@@ -139,6 +145,7 @@ public class LockPatternView extends View {
private float mSquareWidth;
@UnsupportedAppUsage
private float mSquareHeight;
private final LinearGradient mFadeOutGradientShader;
private final Path mCurrentPath = new Path();
private final Rect mInvalidate = new Rect();
@@ -232,7 +239,10 @@ public class LockPatternView extends View {
float alpha = 1f;
public float lineEndX = Float.MIN_VALUE;
public float lineEndY = Float.MIN_VALUE;
public ValueAnimator lineAnimator;
@Nullable
ValueAnimator lineEndAnimator;
@Nullable
ValueAnimator lineDisappearingAnimator;
}
/**
@@ -361,6 +371,14 @@ public class LockPatternView extends View {
mExploreByTouchHelper = new PatternExploreByTouchHelper(this);
setAccessibilityDelegate(mExploreByTouchHelper);
mAudioManager = (AudioManager) mContext.getSystemService(Context.AUDIO_SERVICE);
int fadeAwayGradientWidth = getResources().getDimensionPixelSize(
R.dimen.lock_pattern_fade_away_gradient_width);
// Set up gradient shader with the middle in point (0, 0).
mFadeOutGradientShader = new LinearGradient(/* x0= */ -fadeAwayGradientWidth / 2f,
/* y0= */ 0,/* x1= */ fadeAwayGradientWidth / 2f, /* y1= */ 0,
Color.TRANSPARENT, pathColor, Shader.TileMode.CLAMP);
a.recycle();
}
@@ -791,8 +809,13 @@ public class LockPatternView extends View {
});
startLineEndAnimation(cellState, mInProgressX, mInProgressY,
getCenterXForColumn(cell.column), getCenterYForRow(cell.row));
startLineDisappearingAnimation(cellState);
}
/**
* 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,
final float startX, final float startY, final float targetX, final float targetY) {
ValueAnimator valueAnimator = ValueAnimator.ofFloat(0, 1);
@@ -808,13 +831,37 @@ public class LockPatternView extends View {
valueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
state.lineAnimator = null;
state.lineEndAnimator = null;
}
});
valueAnimator.setInterpolator(mFastOutSlowInInterpolator);
valueAnimator.setDuration(100);
valueAnimator.setDuration(LINE_END_ANIMATION_DURATION_MILLIS);
valueAnimator.start();
state.lineAnimator = valueAnimator;
state.lineEndAnimator = 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) {
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.setStartDelay(LINE_FADE_OUT_DELAY_MILLIS);
valueAnimator.setDuration(LINE_FADE_OUT_DURATION_MILLIS);
valueAnimator.start();
state.lineDisappearingAnimator = valueAnimator;
}
private void startRadiusAnimation(float start, float end, long duration,
@@ -1051,11 +1098,16 @@ 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.lineAnimator != null) {
state.lineAnimator.cancel();
if (state.lineEndAnimator != null) {
state.lineEndAnimator.cancel();
state.lineEndAnimator = null;
state.lineEndX = Float.MIN_VALUE;
state.lineEndY = Float.MIN_VALUE;
}
if (state.lineDisappearingAnimator != null) {
state.lineDisappearingAnimator.cancel();
state.lineDisappearingAnimator = null;
}
}
}
}
@@ -1195,29 +1247,19 @@ public class LockPatternView extends View {
float centerX = getCenterXForColumn(cell.column);
float centerY = getCenterYForRow(cell.row);
if (i != 0) {
// Set this line segment to fade away animated.
int lineFadeVal = (int) Math.min((elapsedRealtime -
mLineFadeStart[i]) * LINE_FADE_ALPHA_MULTIPLIER, 255f);
CellState state = mCellStates[cell.row][cell.column];
currentPath.rewind();
currentPath.moveTo(lastX, lastY);
float endX;
float endY;
if (state.lineEndX != Float.MIN_VALUE && state.lineEndY != Float.MIN_VALUE) {
currentPath.lineTo(state.lineEndX, state.lineEndY);
if (mFadePattern) {
mPathPaint.setAlpha((int) 255 - lineFadeVal );
} else {
mPathPaint.setAlpha(255);
}
endX = state.lineEndX;
endY = state.lineEndY;
} else {
currentPath.lineTo(centerX, centerY);
if (mFadePattern) {
mPathPaint.setAlpha((int) 255 - lineFadeVal );
} else {
mPathPaint.setAlpha(255);
}
endX = centerX;
endY = centerY;
}
canvas.drawPath(currentPath, mPathPaint);
drawLineSegment(canvas, /* startX = */ lastX, /* startY = */ lastY, endX, endY,
mLineFadeStart[i], elapsedRealtime);
}
lastX = centerX;
lastY = centerY;
@@ -1260,6 +1302,61 @@ public class LockPatternView extends View {
}
}
private void drawLineSegment(Canvas canvas, float startX, float startY, float endX, float endY,
long lineFadeStart, long elapsedRealtime) {
float fadeAwayProgress;
if (mFadePattern) {
if (elapsedRealtime - lineFadeStart
>= LINE_FADE_OUT_DELAY_MILLIS + LINE_FADE_OUT_DURATION_MILLIS) {
// Time for this segment animation is out so we don't need to draw it.
return;
}
// Set this line segment to fade away animated.
fadeAwayProgress = Math.max(
((float) (elapsedRealtime - lineFadeStart - LINE_FADE_OUT_DELAY_MILLIS))
/ LINE_FADE_OUT_DURATION_MILLIS, 0f);
drawFadingAwayLineSegment(canvas, startX, startY, endX, endY, fadeAwayProgress);
} else {
mPathPaint.setAlpha(255);
canvas.drawLine(startX, startY, endX, endY, mPathPaint);
}
}
private void drawFadingAwayLineSegment(Canvas canvas, float startX, float startY, float endX,
float endY, float fadeAwayProgress) {
mPathPaint.setAlpha((int) (255 * (1 - fadeAwayProgress)));
// To draw gradient segment we use mFadeOutGradientShader which has immutable coordinates
// thus we will need to translate and rotate the canvas.
mPathPaint.setShader(mFadeOutGradientShader);
canvas.save();
// First translate canvas to gradient middle point.
float gradientMidX = endX * fadeAwayProgress + startX * (1 - fadeAwayProgress);
float gradientMidY = endY * fadeAwayProgress + startY * (1 - fadeAwayProgress);
canvas.translate(gradientMidX, gradientMidY);
// Then rotate it to the direction of the segment.
double segmentAngleRad = Math.atan((endY - startY) / (endX - startX));
float segmentAngleDegrees = (float) Math.toDegrees(segmentAngleRad);
if (endX - startX < 0) {
// Arc tangent gives us angle degrees [-90; 90] thus to cover [90; 270] degrees we
// need this hack.
segmentAngleDegrees += 180f;
}
canvas.rotate(segmentAngleDegrees);
// Pythagoras theorem.
float segmentLength = (float) Math.hypot(endX - startX, endY - startY);
// Draw the segment in coordinates aligned with shader coordinates.
canvas.drawLine(/* startX= */ -segmentLength * fadeAwayProgress, /* startY= */
0,/* stopX= */ segmentLength * (1 - fadeAwayProgress), /* stopY= */ 0, mPathPaint);
canvas.restore();
mPathPaint.setShader(null);
}
private float calculateLastSegmentAlpha(float x, float y, float lastX, float lastY) {
float diffX = x - lastX;
float diffY = y - lastY;

View File

@@ -641,6 +641,8 @@
<dimen name="lock_pattern_dot_line_width">22dp</dimen>
<dimen name="lock_pattern_dot_size">14dp</dimen>
<dimen name="lock_pattern_dot_size_activated">30dp</dimen>
<!-- Width of a gradient applied to a lock pattern line while its disappearing animation. -->
<dimen name="lock_pattern_fade_away_gradient_width">8dp</dimen>
<dimen name="text_handle_min_size">40dp</dimen>

View File

@@ -1318,6 +1318,7 @@
<java-symbol type="dimen" name="lock_pattern_dot_line_width" />
<java-symbol type="dimen" name="lock_pattern_dot_size" />
<java-symbol type="dimen" name="lock_pattern_dot_size_activated" />
<java-symbol type="dimen" name="lock_pattern_fade_away_gradient_width" />
<java-symbol type="drawable" name="clock_dial" />
<java-symbol type="drawable" name="clock_hand_hour" />
<java-symbol type="drawable" name="clock_hand_minute" />