1 /* 2 * Copyright (C) 2015 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License 15 */ 16 17 package com.android.settings.biometrics.fingerprint; 18 19 import android.animation.Animator; 20 import android.animation.AnimatorListenerAdapter; 21 import android.animation.ValueAnimator; 22 import android.annotation.ColorInt; 23 import android.content.Context; 24 import android.graphics.Canvas; 25 import android.graphics.Paint; 26 import android.util.AttributeSet; 27 import android.view.View; 28 import android.view.animation.AnimationUtils; 29 import android.view.animation.Interpolator; 30 31 import androidx.annotation.Nullable; 32 33 import com.android.settings.R; 34 import com.android.settings.Utils; 35 36 /** 37 * View which plays an animation to indicate where the sensor is on the device. 38 */ 39 public class FingerprintLocationAnimationView extends View implements 40 FingerprintFindSensorAnimation { 41 42 private static final float MAX_PULSE_ALPHA = 0.15f; 43 private static final long DELAY_BETWEEN_PHASE = 1000; 44 45 private final Interpolator mLinearOutSlowInInterpolator; 46 private final Interpolator mFastOutSlowInInterpolator; 47 48 private final int mDotRadius; 49 private final int mMaxPulseRadius; 50 private final float mFractionCenterX; 51 private final float mFractionCenterY; 52 private final Paint mDotPaint = new Paint(); 53 private final Paint mPulsePaint = new Paint(); 54 private float mPulseRadius; 55 private ValueAnimator mRadiusAnimator; 56 private ValueAnimator mAlphaAnimator; 57 FingerprintLocationAnimationView(Context context, @Nullable AttributeSet attrs)58 public FingerprintLocationAnimationView(Context context, @Nullable AttributeSet attrs) { 59 super(context, attrs); 60 mDotRadius = getResources().getDimensionPixelSize(R.dimen.fingerprint_dot_radius); 61 mMaxPulseRadius = getResources().getDimensionPixelSize(R.dimen.fingerprint_pulse_radius); 62 mFractionCenterX = getResources().getFraction( 63 R.fraction.fingerprint_sensor_location_fraction_x, 1, 1); 64 mFractionCenterY = getResources().getFraction( 65 R.fraction.fingerprint_sensor_location_fraction_y, 1, 1); 66 @ColorInt int colorAccent = Utils.getColorAccentDefaultColor(context); 67 mDotPaint.setAntiAlias(true); 68 mPulsePaint.setAntiAlias(true); 69 mDotPaint.setColor(colorAccent); 70 mPulsePaint.setColor(colorAccent); 71 mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, 72 android.R.interpolator.linear_out_slow_in); 73 mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, 74 android.R.interpolator.linear_out_slow_in); 75 } 76 77 @Override onDraw(Canvas canvas)78 protected void onDraw(Canvas canvas) { 79 drawPulse(canvas); 80 drawDot(canvas); 81 } 82 drawDot(Canvas canvas)83 private void drawDot(Canvas canvas) { 84 canvas.drawCircle(getCenterX(), getCenterY(), mDotRadius, mDotPaint); 85 } 86 drawPulse(Canvas canvas)87 private void drawPulse(Canvas canvas) { 88 canvas.drawCircle(getCenterX(), getCenterY(), mPulseRadius, mPulsePaint); 89 } 90 getCenterX()91 private float getCenterX() { 92 return getWidth() * mFractionCenterX; 93 } 94 getCenterY()95 private float getCenterY() { 96 return getHeight() * mFractionCenterY; 97 } 98 99 @Override startAnimation()100 public void startAnimation() { 101 startPhase(); 102 } 103 104 @Override stopAnimation()105 public void stopAnimation() { 106 removeCallbacks(mStartPhaseRunnable); 107 if (mRadiusAnimator != null) { 108 mRadiusAnimator.cancel(); 109 } 110 if (mAlphaAnimator != null) { 111 mAlphaAnimator.cancel(); 112 } 113 } 114 115 @Override pauseAnimation()116 public void pauseAnimation() { 117 stopAnimation(); 118 } 119 startPhase()120 private void startPhase() { 121 startRadiusAnimation(); 122 startAlphaAnimation(); 123 } 124 startRadiusAnimation()125 private void startRadiusAnimation() { 126 ValueAnimator animator = ValueAnimator.ofFloat(0, mMaxPulseRadius); 127 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 128 @Override 129 public void onAnimationUpdate(ValueAnimator animation) { 130 mPulseRadius = (float) animation.getAnimatedValue(); 131 invalidate(); 132 } 133 }); 134 animator.addListener(new AnimatorListenerAdapter() { 135 136 boolean mCancelled; 137 138 @Override 139 public void onAnimationCancel(Animator animation) { 140 mCancelled = true; 141 } 142 143 @Override 144 public void onAnimationEnd(Animator animation) { 145 mRadiusAnimator = null; 146 if (!mCancelled) { 147 postDelayed(mStartPhaseRunnable, DELAY_BETWEEN_PHASE); 148 } 149 } 150 }); 151 animator.setDuration(1000); 152 animator.setInterpolator(mLinearOutSlowInInterpolator); 153 animator.start(); 154 mRadiusAnimator = animator; 155 } 156 startAlphaAnimation()157 private void startAlphaAnimation() { 158 mPulsePaint.setAlpha((int) (255f * MAX_PULSE_ALPHA)); 159 ValueAnimator animator = ValueAnimator.ofFloat(MAX_PULSE_ALPHA, 0f); 160 animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { 161 @Override 162 public void onAnimationUpdate(ValueAnimator animation) { 163 mPulsePaint.setAlpha((int) (255f * (float) animation.getAnimatedValue())); 164 invalidate(); 165 } 166 }); 167 animator.addListener(new AnimatorListenerAdapter() { 168 @Override 169 public void onAnimationEnd(Animator animation) { 170 mAlphaAnimator = null; 171 } 172 }); 173 animator.setDuration(750); 174 animator.setInterpolator(mFastOutSlowInInterpolator); 175 animator.setStartDelay(250); 176 animator.start(); 177 mAlphaAnimator = animator; 178 } 179 180 private final Runnable mStartPhaseRunnable = new Runnable() { 181 @Override 182 public void run() { 183 startPhase(); 184 } 185 }; 186 } 187