Merge "Add new line disappearing animation to LockPatternView."
This commit is contained in:
committed by
Android (Google) Code Review
commit
a2d487e3f8
@@ -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;
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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" />
|
||||
|
||||
Reference in New Issue
Block a user