1*90c8c64dSAndroid Build Coastguard Worker /*
2*90c8c64dSAndroid Build Coastguard Worker  * Copyright (C) 2015 The Android Open Source Project
3*90c8c64dSAndroid Build Coastguard Worker  *
4*90c8c64dSAndroid Build Coastguard Worker  * Licensed under the Apache License, Version 2.0 (the "License");
5*90c8c64dSAndroid Build Coastguard Worker  * you may not use this file except in compliance with the License.
6*90c8c64dSAndroid Build Coastguard Worker  * You may obtain a copy of the License at
7*90c8c64dSAndroid Build Coastguard Worker  *
8*90c8c64dSAndroid Build Coastguard Worker  *      http://www.apache.org/licenses/LICENSE-2.0
9*90c8c64dSAndroid Build Coastguard Worker  *
10*90c8c64dSAndroid Build Coastguard Worker  * Unless required by applicable law or agreed to in writing, software
11*90c8c64dSAndroid Build Coastguard Worker  * distributed under the License is distributed on an "AS IS" BASIS,
12*90c8c64dSAndroid Build Coastguard Worker  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13*90c8c64dSAndroid Build Coastguard Worker  * See the License for the specific language governing permissions and
14*90c8c64dSAndroid Build Coastguard Worker  * limitations under the License
15*90c8c64dSAndroid Build Coastguard Worker  */
16*90c8c64dSAndroid Build Coastguard Worker 
17*90c8c64dSAndroid Build Coastguard Worker package com.example.android.fingerprintdialog;
18*90c8c64dSAndroid Build Coastguard Worker 
19*90c8c64dSAndroid Build Coastguard Worker import android.hardware.fingerprint.FingerprintManager;
20*90c8c64dSAndroid Build Coastguard Worker import android.os.CancellationSignal;
21*90c8c64dSAndroid Build Coastguard Worker import android.widget.ImageView;
22*90c8c64dSAndroid Build Coastguard Worker import android.widget.TextView;
23*90c8c64dSAndroid Build Coastguard Worker 
24*90c8c64dSAndroid Build Coastguard Worker /**
25*90c8c64dSAndroid Build Coastguard Worker  * Small helper class to manage text/icon around fingerprint authentication UI.
26*90c8c64dSAndroid Build Coastguard Worker  */
27*90c8c64dSAndroid Build Coastguard Worker public class FingerprintUiHelper extends FingerprintManager.AuthenticationCallback {
28*90c8c64dSAndroid Build Coastguard Worker 
29*90c8c64dSAndroid Build Coastguard Worker     private static final long ERROR_TIMEOUT_MILLIS = 1600;
30*90c8c64dSAndroid Build Coastguard Worker     private static final long SUCCESS_DELAY_MILLIS = 1300;
31*90c8c64dSAndroid Build Coastguard Worker 
32*90c8c64dSAndroid Build Coastguard Worker     private final FingerprintManager mFingerprintManager;
33*90c8c64dSAndroid Build Coastguard Worker     private final ImageView mIcon;
34*90c8c64dSAndroid Build Coastguard Worker     private final TextView mErrorTextView;
35*90c8c64dSAndroid Build Coastguard Worker     private final Callback mCallback;
36*90c8c64dSAndroid Build Coastguard Worker     private CancellationSignal mCancellationSignal;
37*90c8c64dSAndroid Build Coastguard Worker 
38*90c8c64dSAndroid Build Coastguard Worker     private boolean mSelfCancelled;
39*90c8c64dSAndroid Build Coastguard Worker 
40*90c8c64dSAndroid Build Coastguard Worker     /**
41*90c8c64dSAndroid Build Coastguard Worker      * Constructor for {@link FingerprintUiHelper}.
42*90c8c64dSAndroid Build Coastguard Worker      */
FingerprintUiHelper(FingerprintManager fingerprintManager, ImageView icon, TextView errorTextView, Callback callback)43*90c8c64dSAndroid Build Coastguard Worker     FingerprintUiHelper(FingerprintManager fingerprintManager,
44*90c8c64dSAndroid Build Coastguard Worker             ImageView icon, TextView errorTextView, Callback callback) {
45*90c8c64dSAndroid Build Coastguard Worker         mFingerprintManager = fingerprintManager;
46*90c8c64dSAndroid Build Coastguard Worker         mIcon = icon;
47*90c8c64dSAndroid Build Coastguard Worker         mErrorTextView = errorTextView;
48*90c8c64dSAndroid Build Coastguard Worker         mCallback = callback;
49*90c8c64dSAndroid Build Coastguard Worker     }
50*90c8c64dSAndroid Build Coastguard Worker 
isFingerprintAuthAvailable()51*90c8c64dSAndroid Build Coastguard Worker     public boolean isFingerprintAuthAvailable() {
52*90c8c64dSAndroid Build Coastguard Worker         // The line below prevents the false positive inspection from Android Studio
53*90c8c64dSAndroid Build Coastguard Worker         // noinspection ResourceType
54*90c8c64dSAndroid Build Coastguard Worker         return mFingerprintManager.isHardwareDetected()
55*90c8c64dSAndroid Build Coastguard Worker                 && mFingerprintManager.hasEnrolledFingerprints();
56*90c8c64dSAndroid Build Coastguard Worker     }
57*90c8c64dSAndroid Build Coastguard Worker 
startListening(FingerprintManager.CryptoObject cryptoObject)58*90c8c64dSAndroid Build Coastguard Worker     public void startListening(FingerprintManager.CryptoObject cryptoObject) {
59*90c8c64dSAndroid Build Coastguard Worker         if (!isFingerprintAuthAvailable()) {
60*90c8c64dSAndroid Build Coastguard Worker             return;
61*90c8c64dSAndroid Build Coastguard Worker         }
62*90c8c64dSAndroid Build Coastguard Worker         mCancellationSignal = new CancellationSignal();
63*90c8c64dSAndroid Build Coastguard Worker         mSelfCancelled = false;
64*90c8c64dSAndroid Build Coastguard Worker         // The line below prevents the false positive inspection from Android Studio
65*90c8c64dSAndroid Build Coastguard Worker         // noinspection ResourceType
66*90c8c64dSAndroid Build Coastguard Worker         mFingerprintManager
67*90c8c64dSAndroid Build Coastguard Worker                 .authenticate(cryptoObject, mCancellationSignal, 0 /* flags */, this, null);
68*90c8c64dSAndroid Build Coastguard Worker         mIcon.setImageResource(R.drawable.ic_fp_40px);
69*90c8c64dSAndroid Build Coastguard Worker     }
70*90c8c64dSAndroid Build Coastguard Worker 
stopListening()71*90c8c64dSAndroid Build Coastguard Worker     public void stopListening() {
72*90c8c64dSAndroid Build Coastguard Worker         if (mCancellationSignal != null) {
73*90c8c64dSAndroid Build Coastguard Worker             mSelfCancelled = true;
74*90c8c64dSAndroid Build Coastguard Worker             mCancellationSignal.cancel();
75*90c8c64dSAndroid Build Coastguard Worker             mCancellationSignal = null;
76*90c8c64dSAndroid Build Coastguard Worker         }
77*90c8c64dSAndroid Build Coastguard Worker     }
78*90c8c64dSAndroid Build Coastguard Worker 
79*90c8c64dSAndroid Build Coastguard Worker     @Override
onAuthenticationError(int errMsgId, CharSequence errString)80*90c8c64dSAndroid Build Coastguard Worker     public void onAuthenticationError(int errMsgId, CharSequence errString) {
81*90c8c64dSAndroid Build Coastguard Worker         if (!mSelfCancelled) {
82*90c8c64dSAndroid Build Coastguard Worker             showError(errString);
83*90c8c64dSAndroid Build Coastguard Worker             mIcon.postDelayed(new Runnable() {
84*90c8c64dSAndroid Build Coastguard Worker                 @Override
85*90c8c64dSAndroid Build Coastguard Worker                 public void run() {
86*90c8c64dSAndroid Build Coastguard Worker                     mCallback.onError();
87*90c8c64dSAndroid Build Coastguard Worker                 }
88*90c8c64dSAndroid Build Coastguard Worker             }, ERROR_TIMEOUT_MILLIS);
89*90c8c64dSAndroid Build Coastguard Worker         }
90*90c8c64dSAndroid Build Coastguard Worker     }
91*90c8c64dSAndroid Build Coastguard Worker 
92*90c8c64dSAndroid Build Coastguard Worker     @Override
onAuthenticationHelp(int helpMsgId, CharSequence helpString)93*90c8c64dSAndroid Build Coastguard Worker     public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
94*90c8c64dSAndroid Build Coastguard Worker         showError(helpString);
95*90c8c64dSAndroid Build Coastguard Worker     }
96*90c8c64dSAndroid Build Coastguard Worker 
97*90c8c64dSAndroid Build Coastguard Worker     @Override
onAuthenticationFailed()98*90c8c64dSAndroid Build Coastguard Worker     public void onAuthenticationFailed() {
99*90c8c64dSAndroid Build Coastguard Worker         showError(mIcon.getResources().getString(
100*90c8c64dSAndroid Build Coastguard Worker                 R.string.fingerprint_not_recognized));
101*90c8c64dSAndroid Build Coastguard Worker     }
102*90c8c64dSAndroid Build Coastguard Worker 
103*90c8c64dSAndroid Build Coastguard Worker     @Override
onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result)104*90c8c64dSAndroid Build Coastguard Worker     public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
105*90c8c64dSAndroid Build Coastguard Worker         mErrorTextView.removeCallbacks(mResetErrorTextRunnable);
106*90c8c64dSAndroid Build Coastguard Worker         mIcon.setImageResource(R.drawable.ic_fingerprint_success);
107*90c8c64dSAndroid Build Coastguard Worker         mErrorTextView.setTextColor(
108*90c8c64dSAndroid Build Coastguard Worker                 mErrorTextView.getResources().getColor(R.color.success_color, null));
109*90c8c64dSAndroid Build Coastguard Worker         mErrorTextView.setText(
110*90c8c64dSAndroid Build Coastguard Worker                 mErrorTextView.getResources().getString(R.string.fingerprint_success));
111*90c8c64dSAndroid Build Coastguard Worker         mIcon.postDelayed(new Runnable() {
112*90c8c64dSAndroid Build Coastguard Worker             @Override
113*90c8c64dSAndroid Build Coastguard Worker             public void run() {
114*90c8c64dSAndroid Build Coastguard Worker                 mCallback.onAuthenticated();
115*90c8c64dSAndroid Build Coastguard Worker             }
116*90c8c64dSAndroid Build Coastguard Worker         }, SUCCESS_DELAY_MILLIS);
117*90c8c64dSAndroid Build Coastguard Worker     }
118*90c8c64dSAndroid Build Coastguard Worker 
showError(CharSequence error)119*90c8c64dSAndroid Build Coastguard Worker     private void showError(CharSequence error) {
120*90c8c64dSAndroid Build Coastguard Worker         mIcon.setImageResource(R.drawable.ic_fingerprint_error);
121*90c8c64dSAndroid Build Coastguard Worker         mErrorTextView.setText(error);
122*90c8c64dSAndroid Build Coastguard Worker         mErrorTextView.setTextColor(
123*90c8c64dSAndroid Build Coastguard Worker                 mErrorTextView.getResources().getColor(R.color.warning_color, null));
124*90c8c64dSAndroid Build Coastguard Worker         mErrorTextView.removeCallbacks(mResetErrorTextRunnable);
125*90c8c64dSAndroid Build Coastguard Worker         mErrorTextView.postDelayed(mResetErrorTextRunnable, ERROR_TIMEOUT_MILLIS);
126*90c8c64dSAndroid Build Coastguard Worker     }
127*90c8c64dSAndroid Build Coastguard Worker 
128*90c8c64dSAndroid Build Coastguard Worker     private Runnable mResetErrorTextRunnable = new Runnable() {
129*90c8c64dSAndroid Build Coastguard Worker         @Override
130*90c8c64dSAndroid Build Coastguard Worker         public void run() {
131*90c8c64dSAndroid Build Coastguard Worker             mErrorTextView.setTextColor(
132*90c8c64dSAndroid Build Coastguard Worker                     mErrorTextView.getResources().getColor(R.color.hint_color, null));
133*90c8c64dSAndroid Build Coastguard Worker             mErrorTextView.setText(
134*90c8c64dSAndroid Build Coastguard Worker                     mErrorTextView.getResources().getString(R.string.fingerprint_hint));
135*90c8c64dSAndroid Build Coastguard Worker             mIcon.setImageResource(R.drawable.ic_fp_40px);
136*90c8c64dSAndroid Build Coastguard Worker         }
137*90c8c64dSAndroid Build Coastguard Worker     };
138*90c8c64dSAndroid Build Coastguard Worker 
139*90c8c64dSAndroid Build Coastguard Worker     public interface Callback {
140*90c8c64dSAndroid Build Coastguard Worker 
onAuthenticated()141*90c8c64dSAndroid Build Coastguard Worker         void onAuthenticated();
142*90c8c64dSAndroid Build Coastguard Worker 
onError()143*90c8c64dSAndroid Build Coastguard Worker         void onError();
144*90c8c64dSAndroid Build Coastguard Worker     }
145*90c8c64dSAndroid Build Coastguard Worker }
146