Home | History | Annotate | Download | only in fingerprint
      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.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.annotation.Nullable;
     24 import android.content.Context;
     25 import android.graphics.Canvas;
     26 import android.graphics.Paint;
     27 import android.util.AttributeSet;
     28 import android.view.View;
     29 import android.view.animation.AnimationUtils;
     30 import android.view.animation.Interpolator;
     31 
     32 import com.android.settings.R;
     33 import com.android.settings.Utils;
     34 
     35 /**
     36  * View which plays an animation to indicate where the sensor is on the device.
     37  */
     38 public class FingerprintLocationAnimationView extends View implements
     39         FingerprintFindSensorAnimation {
     40 
     41     private static final float MAX_PULSE_ALPHA = 0.15f;
     42     private static final long DELAY_BETWEEN_PHASE = 1000;
     43 
     44     private final Interpolator mLinearOutSlowInInterpolator;
     45     private final Interpolator mFastOutSlowInInterpolator;
     46 
     47     private final int mDotRadius;
     48     private final int mMaxPulseRadius;
     49     private final float mFractionCenterX;
     50     private final float mFractionCenterY;
     51     private final Paint mDotPaint = new Paint();
     52     private final Paint mPulsePaint = new Paint();
     53     private float mPulseRadius;
     54     private ValueAnimator mRadiusAnimator;
     55     private ValueAnimator mAlphaAnimator;
     56 
     57     public FingerprintLocationAnimationView(Context context, @Nullable AttributeSet attrs) {
     58         super(context, attrs);
     59         mDotRadius = getResources().getDimensionPixelSize(R.dimen.fingerprint_dot_radius);
     60         mMaxPulseRadius = getResources().getDimensionPixelSize(R.dimen.fingerprint_pulse_radius);
     61         mFractionCenterX = getResources().getFraction(
     62                 R.fraction.fingerprint_sensor_location_fraction_x, 1, 1);
     63         mFractionCenterY = getResources().getFraction(
     64                 R.fraction.fingerprint_sensor_location_fraction_y, 1, 1);
     65         @ColorInt int colorAccent = Utils.getColorAccent(context);
     66         mDotPaint.setAntiAlias(true);
     67         mPulsePaint.setAntiAlias(true);
     68         mDotPaint.setColor(colorAccent);
     69         mPulsePaint.setColor(colorAccent);
     70         mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
     71                 android.R.interpolator.linear_out_slow_in);
     72         mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context,
     73                 android.R.interpolator.linear_out_slow_in);
     74     }
     75 
     76     @Override
     77     protected void onDraw(Canvas canvas) {
     78         drawPulse(canvas);
     79         drawDot(canvas);
     80     }
     81 
     82     private void drawDot(Canvas canvas) {
     83         canvas.drawCircle(getCenterX(), getCenterY(), mDotRadius, mDotPaint);
     84     }
     85 
     86     private void drawPulse(Canvas canvas) {
     87         canvas.drawCircle(getCenterX(), getCenterY(), mPulseRadius, mPulsePaint);
     88     }
     89 
     90     private float getCenterX() {
     91         return getWidth() * mFractionCenterX;
     92     }
     93 
     94     private float getCenterY() {
     95         return getHeight() * mFractionCenterY;
     96     }
     97 
     98     @Override
     99     public void startAnimation() {
    100         startPhase();
    101     }
    102 
    103     @Override
    104     public void stopAnimation() {
    105         removeCallbacks(mStartPhaseRunnable);
    106         if (mRadiusAnimator != null) {
    107             mRadiusAnimator.cancel();
    108         }
    109         if (mAlphaAnimator != null) {
    110             mAlphaAnimator.cancel();
    111         }
    112     }
    113 
    114     @Override
    115     public void pauseAnimation() {
    116         stopAnimation();
    117     }
    118 
    119     private void startPhase() {
    120         startRadiusAnimation();
    121         startAlphaAnimation();
    122     }
    123 
    124     private void startRadiusAnimation() {
    125         ValueAnimator animator = ValueAnimator.ofFloat(0, mMaxPulseRadius);
    126         animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    127             @Override
    128             public void onAnimationUpdate(ValueAnimator animation) {
    129                 mPulseRadius = (float) animation.getAnimatedValue();
    130                 invalidate();
    131             }
    132         });
    133         animator.addListener(new AnimatorListenerAdapter() {
    134 
    135             boolean mCancelled;
    136 
    137             @Override
    138             public void onAnimationCancel(Animator animation) {
    139                 mCancelled = true;
    140             }
    141 
    142             @Override
    143             public void onAnimationEnd(Animator animation) {
    144                 mRadiusAnimator = null;
    145                 if (!mCancelled) {
    146                     postDelayed(mStartPhaseRunnable, DELAY_BETWEEN_PHASE);
    147                 }
    148             }
    149         });
    150         animator.setDuration(1000);
    151         animator.setInterpolator(mLinearOutSlowInInterpolator);
    152         animator.start();
    153         mRadiusAnimator = animator;
    154     }
    155 
    156     private void startAlphaAnimation() {
    157         mPulsePaint.setAlpha((int) (255f * MAX_PULSE_ALPHA));
    158         ValueAnimator animator = ValueAnimator.ofFloat(MAX_PULSE_ALPHA, 0f);
    159         animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
    160             @Override
    161             public void onAnimationUpdate(ValueAnimator animation) {
    162                 mPulsePaint.setAlpha((int) (255f * (float) animation.getAnimatedValue()));
    163                 invalidate();
    164             }
    165         });
    166         animator.addListener(new AnimatorListenerAdapter() {
    167             @Override
    168             public void onAnimationEnd(Animator animation) {
    169                 mAlphaAnimator = null;
    170             }
    171         });
    172         animator.setDuration(750);
    173         animator.setInterpolator(mFastOutSlowInInterpolator);
    174         animator.setStartDelay(250);
    175         animator.start();
    176         mAlphaAnimator = animator;
    177     }
    178 
    179     private final Runnable mStartPhaseRunnable = new Runnable() {
    180         @Override
    181         public void run() {
    182             startPhase();
    183         }
    184     };
    185 }
    186