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