• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 android.support.v4.hardware.fingerprint;
18 
19 import android.annotation.TargetApi;
20 import android.content.Context;
21 import android.content.pm.PackageManager;
22 import android.hardware.fingerprint.FingerprintManager;
23 import android.os.Build;
24 import android.os.Handler;
25 import android.support.annotation.NonNull;
26 import android.support.annotation.Nullable;
27 import android.support.annotation.RequiresApi;
28 import android.support.annotation.RequiresPermission;
29 import android.support.v4.os.CancellationSignal;
30 
31 import java.security.Signature;
32 
33 import javax.crypto.Cipher;
34 import javax.crypto.Mac;
35 
36 /**
37  * A class that coordinates access to the fingerprint hardware.
38  * <p>
39  * On platforms before {@link android.os.Build.VERSION_CODES#M}, this class behaves as there would
40  * be no fingerprint hardware available.
41  */
42 public final class FingerprintManagerCompat {
43 
44     private final Context mContext;
45 
46     /** Get a {@link FingerprintManagerCompat} instance for a provided context. */
from(Context context)47     public static FingerprintManagerCompat from(Context context) {
48         return new FingerprintManagerCompat(context);
49     }
50 
FingerprintManagerCompat(Context context)51     private FingerprintManagerCompat(Context context) {
52         mContext = context;
53     }
54 
55     /**
56      * Determine if there is at least one fingerprint enrolled.
57      *
58      * @return true if at least one fingerprint is enrolled, false otherwise
59      */
60     @TargetApi(23)
61     @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT)
hasEnrolledFingerprints()62     public boolean hasEnrolledFingerprints() {
63         if (Build.VERSION.SDK_INT >= 23) {
64             final FingerprintManager fp = getFingerprintManagerOrNull(mContext);
65             return (fp != null) && fp.hasEnrolledFingerprints();
66         } else {
67             return false;
68         }
69     }
70 
71     /**
72      * Determine if fingerprint hardware is present and functional.
73      *
74      * @return true if hardware is present and functional, false otherwise.
75      */
76     @TargetApi(23)
77     @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT)
isHardwareDetected()78     public boolean isHardwareDetected() {
79         if (Build.VERSION.SDK_INT >= 23) {
80             final FingerprintManager fp = getFingerprintManagerOrNull(mContext);
81             return (fp != null) && fp.isHardwareDetected();
82         } else {
83             return false;
84         }
85     }
86 
87     /**
88      * Request authentication of a crypto object. This call warms up the fingerprint hardware
89      * and starts scanning for a fingerprint. It terminates when
90      * {@link AuthenticationCallback#onAuthenticationError(int, CharSequence)} or
91      * {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} is called, at
92      * which point the object is no longer valid. The operation can be canceled by using the
93      * provided cancel object.
94      *
95      * @param crypto object associated with the call or null if none required.
96      * @param flags optional flags; should be 0
97      * @param cancel an object that can be used to cancel authentication
98      * @param callback an object to receive authentication events
99      * @param handler an optional handler for events
100      */
101     @TargetApi(23)
102     @RequiresPermission(android.Manifest.permission.USE_FINGERPRINT)
authenticate(@ullable CryptoObject crypto, int flags, @Nullable CancellationSignal cancel, @NonNull AuthenticationCallback callback, @Nullable Handler handler)103     public void authenticate(@Nullable CryptoObject crypto, int flags,
104             @Nullable CancellationSignal cancel, @NonNull AuthenticationCallback callback,
105             @Nullable Handler handler) {
106         if (Build.VERSION.SDK_INT >= 23) {
107             final FingerprintManager fp = getFingerprintManagerOrNull(mContext);
108             if (fp != null) {
109                 android.os.CancellationSignal cancellationSignal = cancel != null
110                         ? (android.os.CancellationSignal) cancel.getCancellationSignalObject()
111                         : null;
112                 fp.authenticate(
113                         wrapCryptoObject(crypto),
114                         cancellationSignal,
115                         flags,
116                         wrapCallback(callback),
117                         handler);
118             }
119         }
120     }
121 
122     @RequiresApi(23)
getFingerprintManagerOrNull(Context context)123     private static FingerprintManager getFingerprintManagerOrNull(Context context) {
124         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
125             return context.getSystemService(FingerprintManager.class);
126         } else {
127             return null;
128         }
129     }
130 
131     @RequiresApi(23)
wrapCryptoObject(CryptoObject cryptoObject)132     private static FingerprintManager.CryptoObject wrapCryptoObject(CryptoObject cryptoObject) {
133         if (cryptoObject == null) {
134             return null;
135         } else if (cryptoObject.getCipher() != null) {
136             return new FingerprintManager.CryptoObject(cryptoObject.getCipher());
137         } else if (cryptoObject.getSignature() != null) {
138             return new FingerprintManager.CryptoObject(cryptoObject.getSignature());
139         } else if (cryptoObject.getMac() != null) {
140             return new FingerprintManager.CryptoObject(cryptoObject.getMac());
141         } else {
142             return null;
143         }
144     }
145 
146     @RequiresApi(23)
unwrapCryptoObject(FingerprintManager.CryptoObject cryptoObject)147     private static CryptoObject unwrapCryptoObject(FingerprintManager.CryptoObject cryptoObject) {
148         if (cryptoObject == null) {
149             return null;
150         } else if (cryptoObject.getCipher() != null) {
151             return new CryptoObject(cryptoObject.getCipher());
152         } else if (cryptoObject.getSignature() != null) {
153             return new CryptoObject(cryptoObject.getSignature());
154         } else if (cryptoObject.getMac() != null) {
155             return new CryptoObject(cryptoObject.getMac());
156         } else {
157             return null;
158         }
159     }
160 
161     @RequiresApi(23)
wrapCallback( final AuthenticationCallback callback)162     private static FingerprintManager.AuthenticationCallback wrapCallback(
163             final AuthenticationCallback callback) {
164         return new FingerprintManager.AuthenticationCallback() {
165             @Override
166             public void onAuthenticationError(int errMsgId, CharSequence errString) {
167                 callback.onAuthenticationError(errMsgId, errString);
168             }
169 
170             @Override
171             public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) {
172                 callback.onAuthenticationHelp(helpMsgId, helpString);
173             }
174 
175             @Override
176             public void onAuthenticationSucceeded(FingerprintManager.AuthenticationResult result) {
177                 callback.onAuthenticationSucceeded(new AuthenticationResult(
178                         unwrapCryptoObject(result.getCryptoObject())));
179             }
180 
181             @Override
182             public void onAuthenticationFailed() {
183                 callback.onAuthenticationFailed();
184             }
185         };
186     }
187 
188     /**
189      * A wrapper class for the crypto objects supported by FingerprintManager. Currently the
190      * framework supports {@link Signature} and {@link Cipher} objects.
191      */
192     public static class CryptoObject {
193 
194         private final Signature mSignature;
195         private final Cipher mCipher;
196         private final Mac mMac;
197 
198         public CryptoObject(Signature signature) {
199             mSignature = signature;
200             mCipher = null;
201             mMac = null;
202 
203         }
204 
205         public CryptoObject(Cipher cipher) {
206             mCipher = cipher;
207             mSignature = null;
208             mMac = null;
209         }
210 
211         public CryptoObject(Mac mac) {
212             mMac = mac;
213             mCipher = null;
214             mSignature = null;
215         }
216 
217         /**
218          * Get {@link Signature} object.
219          * @return {@link Signature} object or null if this doesn't contain one.
220          */
221         public Signature getSignature() { return mSignature; }
222 
223         /**
224          * Get {@link Cipher} object.
225          * @return {@link Cipher} object or null if this doesn't contain one.
226          */
227         public Cipher getCipher() { return mCipher; }
228 
229         /**
230          * Get {@link Mac} object.
231          * @return {@link Mac} object or null if this doesn't contain one.
232          */
233         public Mac getMac() { return mMac; }
234     }
235 
236     /**
237      * Container for callback data from {@link FingerprintManagerCompat#authenticate(CryptoObject,
238      *     int, CancellationSignal, AuthenticationCallback, Handler)}.
239      */
240     public static final class AuthenticationResult {
241         private final CryptoObject mCryptoObject;
242 
243         public AuthenticationResult(CryptoObject crypto) {
244             mCryptoObject = crypto;
245         }
246 
247         /**
248          * Obtain the crypto object associated with this transaction
249          * @return crypto object provided to {@link FingerprintManagerCompat#authenticate(
250          *         CryptoObject, int, CancellationSignal, AuthenticationCallback, Handler)}.
251          */
252         public CryptoObject getCryptoObject() { return mCryptoObject; }
253     }
254 
255     /**
256      * Callback structure provided to {@link FingerprintManagerCompat#authenticate(CryptoObject,
257      * int, CancellationSignal, AuthenticationCallback, Handler)}. Users of {@link
258      * FingerprintManagerCompat#authenticate(CryptoObject, int, CancellationSignal,
259      * AuthenticationCallback, Handler) } must provide an implementation of this for listening to
260      * fingerprint events.
261      */
262     public static abstract class AuthenticationCallback {
263         /**
264          * Called when an unrecoverable error has been encountered and the operation is complete.
265          * No further callbacks will be made on this object.
266          * @param errMsgId An integer identifying the error message
267          * @param errString A human-readable error string that can be shown in UI
268          */
269         public void onAuthenticationError(int errMsgId, CharSequence errString) { }
270 
271         /**
272          * Called when a recoverable error has been encountered during authentication. The help
273          * string is provided to give the user guidance for what went wrong, such as
274          * "Sensor dirty, please clean it."
275          * @param helpMsgId An integer identifying the error message
276          * @param helpString A human-readable string that can be shown in UI
277          */
278         public void onAuthenticationHelp(int helpMsgId, CharSequence helpString) { }
279 
280         /**
281          * Called when a fingerprint is recognized.
282          * @param result An object containing authentication-related data
283          */
284         public void onAuthenticationSucceeded(AuthenticationResult result) { }
285 
286         /**
287          * Called when a fingerprint is valid but not recognized.
288          */
289         public void onAuthenticationFailed() { }
290     }
291 }
292