OSDN Git Service

Add pulsing animation for find sensor.
authorJorim Jaggi <jjaggi@google.com>
Thu, 23 Apr 2015 20:56:33 +0000 (13:56 -0700)
committerJorim Jaggi <jjaggi@google.com>
Fri, 24 Apr 2015 21:26:32 +0000 (14:26 -0700)
Bug: 20495507
Change-Id: I5fefb2cdb2625885c906fa2a9b69da1141ce66e0

res/drawable-nodpi/fingerprint_sensor_location.png
res/layout-land/fingerprint_enroll_find_sensor.xml
res/layout/fingerprint_enroll_find_sensor_base.xml
res/layout/fingerprint_enroll_find_sensor_graphic.xml [new file with mode: 0644]
res/values/colors.xml
res/values/dimens.xml
res/values/themes.xml
src/com/android/settings/fingerprint/FingerprintEnrollFindSensor.java
src/com/android/settings/fingerprint/FingerprintLocationAnimationView.java [new file with mode: 0644]

index b95816f..587c911 100644 (file)
Binary files a/res/drawable-nodpi/fingerprint_sensor_location.png and b/res/drawable-nodpi/fingerprint_sensor_location.png differ
index 1eaa815..b340193 100644 (file)
         <FrameLayout
             android:layout_width="0dp"
             android:layout_weight="1"
-            android:layout_height="wrap_content"
-            android:layout_gravity="center_vertical">
+            android:layout_height="match_parent">
 
-            <ImageView
-                android:id="@+id/fingerprint_sensor_location"
-                android:layout_width="200dp"
-                android:layout_height="200dp"
-                android:layout_gravity="center"
-                android:contentDescription="@string/security_settings_fingerprint_enroll_find_sensor_content_description"
-                android:src="@drawable/fingerprint_sensor_location"
-                android:scaleType="centerInside"/>
+            <include
+                layout="@layout/fingerprint_enroll_find_sensor_graphic"
+                android:layout_width="@dimen/fingerprint_find_sensor_graphic_size"
+                android:layout_height="@dimen/fingerprint_find_sensor_graphic_size"
+                android:layout_gravity="center"/>
 
         </FrameLayout>
 
index 89b4594..9f1eb4b 100644 (file)
             android:layout_marginTop="@dimen/suw_description_margin_top"
             android:text="@string/security_settings_fingerprint_enroll_find_sensor_message"/>
 
-        <ImageView
-            android:id="@+id/fingerprint_sensor_location"
-            android:layout_width="204dp"
-            android:layout_height="204dp"
+        <include
+            layout="@layout/fingerprint_enroll_find_sensor_graphic"
             android:layout_marginTop="32dp"
-            android:layout_gravity="center_horizontal"
-            android:contentDescription="@string/security_settings_fingerprint_enroll_find_sensor_content_description"
-            android:src="@drawable/fingerprint_sensor_location"
-            android:scaleType="centerInside"/>
+            android:layout_width="@dimen/fingerprint_find_sensor_graphic_size"
+            android:layout_height="@dimen/fingerprint_find_sensor_graphic_size"
+            android:layout_gravity="center_horizontal"/>
 
         <View
             android:layout_height="0dp"
diff --git a/res/layout/fingerprint_enroll_find_sensor_graphic.xml b/res/layout/fingerprint_enroll_find_sensor_graphic.xml
new file mode 100644 (file)
index 0000000..1c6ab80
--- /dev/null
@@ -0,0 +1,36 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ 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
+  -->
+
+<FrameLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:layout_width="@dimen/fingerprint_find_sensor_graphic_size"
+    android:layout_height="@dimen/fingerprint_find_sensor_graphic_size">
+
+    <ImageView
+        android:id="@+id/fingerprint_sensor_location"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"
+        android:contentDescription="@string/security_settings_fingerprint_enroll_find_sensor_content_description"
+        android:src="@drawable/fingerprint_sensor_location"
+        android:scaleType="centerInside"/>
+
+    <com.android.settings.fingerprint.FingerprintLocationAnimationView
+        android:id="@+id/fingerprint_sensor_location_animation"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+
+</FrameLayout>
index 858af0e..25a7341 100644 (file)
@@ -64,6 +64,7 @@
     <color name="fingerprint_message_color">#de000000</color>
     <color name="fingerprint_progress_ring">#ff009688</color>
     <color name="fingerprint_progress_ring_bg">#20000000</color>
+    <color name="fingerprint_dot_color">#ff009688</color>
 
     <color name="running_processes_system_ram">#ff384248</color>
     <color name="running_processes_apps_ram">#ff009587</color>
index c2d192d..30be6e8 100755 (executable)
     <!-- Fingerprint -->
     <dimen name="fingerprint_ring_radius">92dip</dimen>
     <dimen name="fingerprint_ring_thickness">4dip</dimen>
+    <dimen name="fingerprint_dot_radius">8dp</dimen>
+    <dimen name="fingerprint_pulse_radius">50dp</dimen>
+    <item name="fingerprint_sensor_location_fraction_x" type="fraction">50%</item>
+    <item name="fingerprint_sensor_location_fraction_y" type="fraction">30%</item>
+    <dimen name="fingerprint_find_sensor_graphic_size">200dp</dimen>
     <item name="fingerprint_illustration_aspect_ratio" format="float" type="dimen">2.6</item>
     <dimen name="fingerprint_decor_padding_top">0dp</dimen>
 
index edba85f..466c6c9 100644 (file)
     </style>
 
     <style name="Theme.FingerprintEnroll" parent="@android:style/Theme.Material.Light.NoActionBar">
+        <item name="android:windowAnimationStyle">@style/Animation.SuwWindowAnimation</item>
     </style>
 
 </resources>
index d49fdb6..b3a5d22 100644 (file)
@@ -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 (file)
index 0000000..b52fed3
--- /dev/null
@@ -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();
+        }
+    };
+}