| /* |
| * Copyright (C) 2015 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License |
| */ |
| |
| package com.android.settings.fingerprint; |
| |
| import android.animation.Animator; |
| import android.animation.AnimatorListenerAdapter; |
| import android.animation.ValueAnimator; |
| import android.annotation.ColorInt; |
| import android.annotation.Nullable; |
| import android.content.Context; |
| import android.graphics.Canvas; |
| import android.graphics.Paint; |
| import android.util.AttributeSet; |
| import android.view.View; |
| import android.view.animation.AnimationUtils; |
| import android.view.animation.Interpolator; |
| |
| import com.android.settings.R; |
| import com.android.settings.Utils; |
| |
| /** |
| * View which plays an animation to indicate where the sensor is on the device. |
| */ |
| public class FingerprintLocationAnimationView extends View implements |
| FingerprintFindSensorAnimation { |
| |
| private static final float MAX_PULSE_ALPHA = 0.15f; |
| private static final long DELAY_BETWEEN_PHASE = 1000; |
| |
| private final Interpolator mLinearOutSlowInInterpolator; |
| private final Interpolator mFastOutSlowInInterpolator; |
| |
| private final int mDotRadius; |
| private final int mMaxPulseRadius; |
| private final float mFractionCenterX; |
| private final float mFractionCenterY; |
| private final Paint mDotPaint = new Paint(); |
| private final Paint mPulsePaint = new Paint(); |
| private float mPulseRadius; |
| private ValueAnimator mRadiusAnimator; |
| private ValueAnimator mAlphaAnimator; |
| |
| public FingerprintLocationAnimationView(Context context, @Nullable AttributeSet attrs) { |
| super(context, attrs); |
| mDotRadius = getResources().getDimensionPixelSize(R.dimen.fingerprint_dot_radius); |
| mMaxPulseRadius = getResources().getDimensionPixelSize(R.dimen.fingerprint_pulse_radius); |
| mFractionCenterX = getResources().getFraction( |
| R.fraction.fingerprint_sensor_location_fraction_x, 1, 1); |
| mFractionCenterY = getResources().getFraction( |
| R.fraction.fingerprint_sensor_location_fraction_y, 1, 1); |
| @ColorInt int colorAccent = Utils.getColorAccent(context); |
| mDotPaint.setAntiAlias(true); |
| mPulsePaint.setAntiAlias(true); |
| mDotPaint.setColor(colorAccent); |
| mPulsePaint.setColor(colorAccent); |
| mLinearOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, |
| android.R.interpolator.linear_out_slow_in); |
| mFastOutSlowInInterpolator = AnimationUtils.loadInterpolator(context, |
| android.R.interpolator.linear_out_slow_in); |
| } |
| |
| @Override |
| protected void onDraw(Canvas canvas) { |
| drawPulse(canvas); |
| drawDot(canvas); |
| } |
| |
| private void drawDot(Canvas canvas) { |
| canvas.drawCircle(getCenterX(), getCenterY(), mDotRadius, mDotPaint); |
| } |
| |
| private void drawPulse(Canvas canvas) { |
| canvas.drawCircle(getCenterX(), getCenterY(), mPulseRadius, mPulsePaint); |
| } |
| |
| private float getCenterX() { |
| return getWidth() * mFractionCenterX; |
| } |
| |
| private float getCenterY() { |
| return getHeight() * mFractionCenterY; |
| } |
| |
| @Override |
| public void startAnimation() { |
| startPhase(); |
| } |
| |
| @Override |
| public void stopAnimation() { |
| removeCallbacks(mStartPhaseRunnable); |
| if (mRadiusAnimator != null) { |
| mRadiusAnimator.cancel(); |
| } |
| if (mAlphaAnimator != null) { |
| mAlphaAnimator.cancel(); |
| } |
| } |
| |
| @Override |
| public void pauseAnimation() { |
| stopAnimation(); |
| } |
| |
| private void startPhase() { |
| startRadiusAnimation(); |
| startAlphaAnimation(); |
| } |
| |
| private void startRadiusAnimation() { |
| ValueAnimator animator = ValueAnimator.ofFloat(0, mMaxPulseRadius); |
| animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { |
| @Override |
| public void onAnimationUpdate(ValueAnimator animation) { |
| mPulseRadius = (float) animation.getAnimatedValue(); |
| invalidate(); |
| } |
| }); |
| animator.addListener(new AnimatorListenerAdapter() { |
| |
| boolean mCancelled; |
| |
| @Override |
| public void onAnimationCancel(Animator animation) { |
| mCancelled = true; |
| } |
| |
| @Override |
| public void onAnimationEnd(Animator animation) { |
| mRadiusAnimator = null; |
| if (!mCancelled) { |
| postDelayed(mStartPhaseRunnable, DELAY_BETWEEN_PHASE); |
| } |
| } |
| }); |
| animator.setDuration(1000); |
| animator.setInterpolator(mLinearOutSlowInInterpolator); |
| animator.start(); |
| mRadiusAnimator = animator; |
| } |
| |
| private void startAlphaAnimation() { |
| mPulsePaint.setAlpha((int) (255f * MAX_PULSE_ALPHA)); |
| ValueAnimator animator = ValueAnimator.ofFloat(MAX_PULSE_ALPHA, 0f); |
| animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { |
| @Override |
| public void onAnimationUpdate(ValueAnimator animation) { |
| mPulsePaint.setAlpha((int) (255f * (float) animation.getAnimatedValue())); |
| invalidate(); |
| } |
| }); |
| animator.addListener(new AnimatorListenerAdapter() { |
| @Override |
| public void onAnimationEnd(Animator animation) { |
| mAlphaAnimator = null; |
| } |
| }); |
| animator.setDuration(750); |
| animator.setInterpolator(mFastOutSlowInInterpolator); |
| animator.setStartDelay(250); |
| animator.start(); |
| mAlphaAnimator = animator; |
| } |
| |
| private final Runnable mStartPhaseRunnable = new Runnable() { |
| @Override |
| public void run() { |
| startPhase(); |
| } |
| }; |
| } |