import android.content.res.Resources;
import android.content.res.TypedArray;
import android.graphics.Canvas;
+import android.graphics.CanvasProperty;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.Rect;
-import android.graphics.RectF;
import android.media.AudioManager;
import android.os.Bundle;
import android.os.Debug;
import android.util.AttributeSet;
import android.util.IntArray;
import android.util.Log;
+import android.view.DisplayListCanvas;
import android.view.HapticFeedbackConstants;
import android.view.MotionEvent;
+import android.view.RenderNodeAnimator;
import android.view.View;
import android.view.accessibility.AccessibilityEvent;
import android.view.accessibility.AccessibilityManager;
}
public static class CellState {
- public float scale = 1.0f;
- public float translateY = 0.0f;
- public float alpha = 1.0f;
- public float size;
+ int row;
+ int col;
+ boolean hwAnimating;
+ CanvasProperty<Float> hwRadius;
+ CanvasProperty<Float> hwCenterX;
+ CanvasProperty<Float> hwCenterY;
+ CanvasProperty<Paint> hwPaint;
+ float radius;
+ float translationY;
+ float alpha = 1f;
public float lineEndX = Float.MIN_VALUE;
public float lineEndY = Float.MIN_VALUE;
public ValueAnimator lineAnimator;
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
mCellStates[i][j] = new CellState();
- mCellStates[i][j].size = mDotSize;
+ mCellStates[i][j].radius = mDotSize/2;
+ mCellStates[i][j].row = i;
+ mCellStates[i][j].col = j;
}
}
invalidate();
}
+ public void startCellStateAnimation(CellState cellState, float startAlpha, float endAlpha,
+ float startTranslationY, float endTranslationY, float startScale, float endScale,
+ long delay, long duration,
+ Interpolator interpolator, Runnable finishRunnable) {
+ if (isHardwareAccelerated()) {
+ startCellStateAnimationHw(cellState, startAlpha, endAlpha, startTranslationY,
+ endTranslationY, startScale, endScale, delay, duration, interpolator,
+ finishRunnable);
+ } else {
+ startCellStateAnimationSw(cellState, startAlpha, endAlpha, startTranslationY,
+ endTranslationY, startScale, endScale, delay, duration, interpolator,
+ finishRunnable);
+ }
+ }
+
+ private void startCellStateAnimationSw(final CellState cellState,
+ final float startAlpha, final float endAlpha,
+ final float startTranslationY, final float endTranslationY,
+ final float startScale, final float endScale,
+ long delay, long duration, Interpolator interpolator, final Runnable finishRunnable) {
+ cellState.alpha = startAlpha;
+ cellState.translationY = startTranslationY;
+ cellState.radius = mDotSize/2 * startScale;
+ ValueAnimator animator = ValueAnimator.ofFloat(0f, 1f);
+ animator.setDuration(duration);
+ animator.setStartDelay(delay);
+ animator.setInterpolator(interpolator);
+ animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ float t = (float) animation.getAnimatedValue();
+ cellState.alpha = (1 - t) * startAlpha + t * endAlpha;
+ cellState.translationY = (1 - t) * startTranslationY + t * endTranslationY;
+ cellState.radius = mDotSize/2 * ((1 - t) * startScale + t * endScale);
+ invalidate();
+ }
+ });
+ animator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ if (finishRunnable != null) {
+ finishRunnable.run();
+ }
+ }
+ });
+ animator.start();
+ }
+
+ private void startCellStateAnimationHw(final CellState cellState,
+ float startAlpha, float endAlpha,
+ float startTranslationY, float endTranslationY,
+ float startScale, float endScale,
+ long delay, long duration, Interpolator interpolator, final Runnable finishRunnable) {
+ cellState.alpha = endAlpha;
+ cellState.translationY = endTranslationY;
+ cellState.radius = mDotSize/2 * endScale;
+ cellState.hwAnimating = true;
+ cellState.hwCenterY = CanvasProperty.createFloat(
+ getCenterYForRow(cellState.row) + startTranslationY);
+ cellState.hwCenterX = CanvasProperty.createFloat(getCenterXForColumn(cellState.col));
+ cellState.hwRadius = CanvasProperty.createFloat(mDotSize/2 * startScale);
+ mPaint.setColor(getCurrentColor(false));
+ mPaint.setAlpha((int) (startAlpha * 255));
+ cellState.hwPaint = CanvasProperty.createPaint(new Paint(mPaint));
+
+ startRtFloatAnimation(cellState.hwCenterY,
+ getCenterYForRow(cellState.row) + endTranslationY, delay, duration, interpolator);
+ startRtFloatAnimation(cellState.hwRadius, mDotSize/2 * endScale, delay, duration,
+ interpolator);
+ startRtAlphaAnimation(cellState, endAlpha, delay, duration, interpolator,
+ new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ cellState.hwAnimating = false;
+ if (finishRunnable != null) {
+ finishRunnable.run();
+ }
+ }
+ });
+
+ invalidate();
+ }
+
+ private void startRtAlphaAnimation(CellState cellState, float endAlpha,
+ long delay, long duration, Interpolator interpolator,
+ Animator.AnimatorListener listener) {
+ RenderNodeAnimator animator = new RenderNodeAnimator(cellState.hwPaint,
+ RenderNodeAnimator.PAINT_ALPHA, (int) (endAlpha * 255));
+ animator.setDuration(duration);
+ animator.setStartDelay(delay);
+ animator.setInterpolator(interpolator);
+ animator.setTarget(this);
+ animator.addListener(listener);
+ animator.start();
+ }
+
+ private void startRtFloatAnimation(CanvasProperty<Float> property, float endValue,
+ long delay, long duration, Interpolator interpolator) {
+ RenderNodeAnimator animator = new RenderNodeAnimator(property, endValue);
+ animator.setDuration(duration);
+ animator.setStartDelay(delay);
+ animator.setInterpolator(interpolator);
+ animator.setTarget(this);
+ animator.start();
+ }
+
private void notifyCellAdded() {
// sendAccessEvent(R.string.lockscreen_access_pattern_cell_added);
if (mOnPatternListener != null) {
private void startCellActivatedAnimation(Cell cell) {
final CellState cellState = mCellStates[cell.row][cell.column];
- startSizeAnimation(mDotSize, mDotSizeActivated, 96, mLinearOutSlowInInterpolator,
+ startRadiusAnimation(mDotSize/2, mDotSizeActivated/2, 96, mLinearOutSlowInInterpolator,
cellState, new Runnable() {
- @Override
- public void run() {
- startSizeAnimation(mDotSizeActivated, mDotSize, 192, mFastOutSlowInInterpolator,
- cellState, null);
- }
- });
+ @Override
+ public void run() {
+ startRadiusAnimation(mDotSizeActivated/2, mDotSize/2, 192,
+ mFastOutSlowInInterpolator,
+ cellState, null);
+ }
+ });
startLineEndAnimation(cellState, mInProgressX, mInProgressY,
getCenterXForColumn(cell.column), getCenterYForRow(cell.row));
}
state.lineAnimator = valueAnimator;
}
- private void startSizeAnimation(float start, float end, long duration, Interpolator interpolator,
- final CellState state, final Runnable endRunnable) {
+ 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.size = (float) animation.getAnimatedValue();
+ state.radius = (float) animation.getAnimatedValue();
invalidate();
}
});
for (int j = 0; j < 3; j++) {
CellState cellState = mCellStates[i][j];
float centerX = getCenterXForColumn(j);
- float size = cellState.size * cellState.scale;
- float translationY = cellState.translateY;
- drawCircle(canvas, (int) centerX, (int) centerY + translationY,
- size, drawLookup[i][j], cellState.alpha);
+ float translationY = cellState.translationY;
+ if (isHardwareAccelerated() && cellState.hwAnimating) {
+ DisplayListCanvas displayListCanvas = (DisplayListCanvas) canvas;
+ displayListCanvas.drawCircle(cellState.hwCenterX, cellState.hwCenterY,
+ cellState.hwRadius, cellState.hwPaint);
+ } else {
+ drawCircle(canvas, (int) centerX, (int) centerY + translationY,
+ cellState.radius, drawLookup[i][j], cellState.alpha);
+
+ }
}
}
/**
* @param partOfPattern Whether this circle is part of the pattern.
*/
- private void drawCircle(Canvas canvas, float centerX, float centerY, float size,
+ private void drawCircle(Canvas canvas, float centerX, float centerY, float radius,
boolean partOfPattern, float alpha) {
mPaint.setColor(getCurrentColor(partOfPattern));
mPaint.setAlpha((int) (alpha * 255));
- canvas.drawCircle(centerX, centerY, size/2, mPaint);
+ canvas.drawCircle(centerX, centerY, radius, mPaint);
}
@Override
float centerY = getCenterYForRow(row);
float cellheight = mSquareHeight * mHitFactor * 0.5f;
float cellwidth = mSquareWidth * mHitFactor * 0.5f;
- float translationY = cell.translateY;
bounds.left = (int) (centerX - cellwidth);
bounds.right = (int) (centerX + cellwidth);
bounds.top = (int) (centerY - cellheight);
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
+import android.view.RenderNodeAnimator;
import android.view.View;
import android.view.ViewGroup;
import android.view.animation.AnimationUtils;
enableClipping(false);
setAlpha(1f);
setTranslationY(mAppearAnimationUtils.getStartTranslation());
- animate()
- .setDuration(500)
- .setInterpolator(mAppearAnimationUtils.getInterpolator())
- .translationY(0);
+ AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 500 /* duration */,
+ 0, mAppearAnimationUtils.getInterpolator());
mAppearAnimationUtils.startAnimation2d(
mLockPatternView.getCellStates(),
new Runnable() {
mLockPatternView.clearPattern();
enableClipping(false);
setTranslationY(0);
- animate()
- .setDuration(300)
- .setInterpolator(mDisappearAnimationUtils.getInterpolator())
- .translationY(-mDisappearAnimationUtils.getStartTranslation());
+ AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 300 /* duration */,
+ -mDisappearAnimationUtils.getStartTranslation(),
+ mDisappearAnimationUtils.getInterpolator());
mDisappearAnimationUtils.startAnimation2d(mLockPatternView.getCellStates(),
new Runnable() {
@Override
long duration, float translationY, final boolean appearing,
Interpolator interpolator,
final Runnable finishListener) {
- if (appearing) {
- animatedCell.scale = 0.0f;
- animatedCell.alpha = 1.0f;
- }
- animatedCell.translateY = appearing ? translationY : 0;
- ValueAnimator animator = ValueAnimator.ofFloat(animatedCell.translateY,
- appearing ? 0 : translationY);
- animator.setInterpolator(interpolator);
- animator.setDuration(duration);
- animator.setStartDelay(delay);
- animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- float animatedFraction = animation.getAnimatedFraction();
- if (appearing) {
- animatedCell.scale = animatedFraction;
- } else {
- animatedCell.alpha = 1 - animatedFraction;
- }
- animatedCell.translateY = (float) animation.getAnimatedValue();
- mLockPatternView.invalidate();
- }
- });
+ mLockPatternView.startCellStateAnimation(animatedCell,
+ 1f, appearing ? 1f : 0f, /* alpha */
+ appearing ? translationY : 0f, appearing ? 0f : translationY, /* translation */
+ appearing ? 0f : 1f, 1f /* scale */,
+ delay, duration, interpolator, finishListener);
if (finishListener != null) {
- animator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- finishListener.run();
- }
- });
-
// Also animate the Emergency call
mAppearAnimationUtils.createAnimation(mEcaView, delay, duration, translationY,
appearing, interpolator, null);
}
- animator.start();
- mLockPatternView.invalidate();
}
@Override
package com.android.settingslib.animation;
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.ValueAnimator;
import android.content.Context;
+import android.view.RenderNodeAnimator;
import android.view.View;
+import android.view.ViewPropertyAnimator;
import android.view.animation.AnimationUtils;
import android.view.animation.Interpolator;
+import com.android.internal.widget.LockPatternView;
import com.android.settingslib.R;
/**
}
@Override
- public void createAnimation(View view, long delay, long duration, float translationY,
- boolean appearing, Interpolator interpolator, Runnable endRunnable) {
+ public void createAnimation(final View view, long delay, long duration, float translationY,
+ boolean appearing, Interpolator interpolator, final Runnable endRunnable) {
if (view != null) {
view.setAlpha(appearing ? 0f : 1.0f);
view.setTranslationY(appearing ? translationY : 0);
- view.animate()
- .alpha(appearing ? 1f : 0f)
- .translationY(appearing ? 0 : translationY)
- .setInterpolator(interpolator)
- .setDuration(duration)
- .setStartDelay(delay);
+ Animator alphaAnim;
+ float targetAlpha = appearing ? 1f : 0f;
+ if (view.isHardwareAccelerated()) {
+ RenderNodeAnimator alphaAnimRt = new RenderNodeAnimator(RenderNodeAnimator.ALPHA,
+ targetAlpha);
+ alphaAnimRt.setTarget(view);
+ alphaAnim = alphaAnimRt;
+ } else {
+ alphaAnim = ObjectAnimator.ofFloat(view, View.ALPHA, view.getAlpha(), targetAlpha);
+ }
+ alphaAnim.setInterpolator(interpolator);
+ alphaAnim.setDuration(duration);
+ alphaAnim.setStartDelay(delay);
if (view.hasOverlappingRendering()) {
- view.animate().withLayer();
+ view.setLayerType(View.LAYER_TYPE_HARDWARE, null);
+ alphaAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ view.setLayerType(View.LAYER_TYPE_NONE, null);
+ }
+ });
}
if (endRunnable != null) {
- view.animate().withEndAction(endRunnable);
+ alphaAnim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ endRunnable.run();
+ }
+ });
}
+ alphaAnim.start();
+ startTranslationYAnimation(view, delay, duration, appearing ? 0 : translationY,
+ interpolator);
+ }
+ }
+
+ public static void startTranslationYAnimation(View view, long delay, long duration,
+ float endTranslationY, Interpolator interpolator) {
+ Animator translationAnim;
+ if (view.isHardwareAccelerated()) {
+ RenderNodeAnimator translationAnimRt = new RenderNodeAnimator(
+ RenderNodeAnimator.TRANSLATION_Y, endTranslationY);
+ translationAnimRt.setTarget(view);
+ translationAnim = translationAnimRt;
+ } else {
+ translationAnim = ObjectAnimator.ofFloat(view, View.TRANSLATION_Y,
+ view.getTranslationY(), endTranslationY);
}
+ translationAnim.setInterpolator(interpolator);
+ translationAnim.setDuration(duration);
+ translationAnim.setStartDelay(delay);
+ translationAnim.start();
}
public class AppearAnimationProperties {