diff --git a/res/drawable-nodpi/fingerprint_sensor_location.png b/res/drawable-nodpi/fingerprint_sensor_location.png index b95816fb393..587c911baab 100644 Binary files a/res/drawable-nodpi/fingerprint_sensor_location.png and b/res/drawable-nodpi/fingerprint_sensor_location.png differ diff --git a/res/layout-land/fingerprint_enroll_find_sensor.xml b/res/layout-land/fingerprint_enroll_find_sensor.xml index 1eaa815dc41..b3401934916 100644 --- a/res/layout-land/fingerprint_enroll_find_sensor.xml +++ b/res/layout-land/fingerprint_enroll_find_sensor.xml @@ -58,17 +58,13 @@ + android:layout_height="match_parent"> - + diff --git a/res/layout/fingerprint_enroll_find_sensor_base.xml b/res/layout/fingerprint_enroll_find_sensor_base.xml index 89b45945bd8..9f1eb4be77a 100644 --- a/res/layout/fingerprint_enroll_find_sensor_base.xml +++ b/res/layout/fingerprint_enroll_find_sensor_base.xml @@ -37,15 +37,12 @@ android:layout_marginTop="@dimen/suw_description_margin_top" android:text="@string/security_settings_fingerprint_enroll_find_sensor_message"/> - + android:layout_width="@dimen/fingerprint_find_sensor_graphic_size" + android:layout_height="@dimen/fingerprint_find_sensor_graphic_size" + android:layout_gravity="center_horizontal"/> + + + + + + + + + diff --git a/res/values/colors.xml b/res/values/colors.xml index 858af0e602d..25a7341765e 100644 --- a/res/values/colors.xml +++ b/res/values/colors.xml @@ -64,6 +64,7 @@ #de000000 #ff009688 #20000000 + #ff009688 #ff384248 #ff009587 diff --git a/res/values/dimens.xml b/res/values/dimens.xml index c2d192d9881..30be6e867b1 100755 --- a/res/values/dimens.xml +++ b/res/values/dimens.xml @@ -219,6 +219,11 @@ 92dip 4dip + 8dp + 50dp + 50% + 30% + 200dp 2.6 0dp diff --git a/res/values/themes.xml b/res/values/themes.xml index edba85f42fe..466c6c9738d 100644 --- a/res/values/themes.xml +++ b/res/values/themes.xml @@ -221,6 +221,7 @@ diff --git a/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java b/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java index d49fdb621f8..b3a5d2298b4 100644 --- a/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java +++ b/src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java @@ -31,6 +31,8 @@ public class FingerprintEnrollFindSensor extends FingerprintEnrollBase { private static final int CONFIRM_REQUEST = 1; private static final int ENROLLING = 2; + private FingerprintLocationAnimationView mAnimation; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); @@ -39,6 +41,20 @@ public class FingerprintEnrollFindSensor extends FingerprintEnrollBase { if (mToken == null) { launchConfirmLock(); } + mAnimation = (FingerprintLocationAnimationView) findViewById( + R.id.fingerprint_sensor_location_animation); + } + + @Override + protected void onStart() { + super.onStart(); + mAnimation.startAnimation(); + } + + @Override + protected void onStop() { + super.onStop(); + mAnimation.stopAnimation(); } @Override diff --git a/src/com/android/settings/fingerprint/FingerprintLocationAnimationView.java b/src/com/android/settings/fingerprint/FingerprintLocationAnimationView.java new file mode 100644 index 00000000000..b52fed31052 --- /dev/null +++ b/src/com/android/settings/fingerprint/FingerprintLocationAnimationView.java @@ -0,0 +1,175 @@ +/* + * 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.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; + +/** + * View which plays an animation to indicate where the sensor is on the device. + */ +public class FingerprintLocationAnimationView extends View { + + 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); + int color = getResources().getColor(R.color.fingerprint_dot_color, null); + mDotPaint.setAntiAlias(true); + mPulsePaint.setAntiAlias(true); + mDotPaint.setColor(color); + mPulsePaint.setColor(color); + 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; + } + + public void startAnimation() { + startPhase(); + } + + public void stopAnimation() { + removeCallbacks(mStartPhaseRunnable); + if (mRadiusAnimator != null) { + mRadiusAnimator.cancel(); + } + if (mAlphaAnimator != null) { + mAlphaAnimator.cancel(); + } + } + + 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(); + } + }; +}