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