1 /*
2  * Copyright (C) 2018 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.hardware.biometrics;
18 
19 import static android.Manifest.permission.USE_BIOMETRIC;
20 import static android.Manifest.permission.USE_BIOMETRIC_INTERNAL;
21 
22 import android.annotation.IntDef;
23 import android.annotation.RequiresPermission;
24 import android.annotation.SystemService;
25 import android.content.Context;
26 import android.content.pm.PackageManager;
27 import android.os.RemoteException;
28 import android.util.Slog;
29 
30 /**
31  * A class that contains biometric utilities. For authentication, see {@link BiometricPrompt}.
32  */
33 @SystemService(Context.BIOMETRIC_SERVICE)
34 public class BiometricManager {
35 
36     private static final String TAG = "BiometricManager";
37 
38     /**
39      * No error detected.
40      */
41     public static final int BIOMETRIC_SUCCESS =
42             BiometricConstants.BIOMETRIC_SUCCESS;
43 
44     /**
45      * The hardware is unavailable. Try again later.
46      */
47     public static final int BIOMETRIC_ERROR_HW_UNAVAILABLE =
48             BiometricConstants.BIOMETRIC_ERROR_HW_UNAVAILABLE;
49 
50     /**
51      * The user does not have any biometrics enrolled.
52      */
53     public static final int BIOMETRIC_ERROR_NONE_ENROLLED =
54             BiometricConstants.BIOMETRIC_ERROR_NO_BIOMETRICS;
55 
56     /**
57      * There is no biometric hardware.
58      */
59     public static final int BIOMETRIC_ERROR_NO_HARDWARE =
60             BiometricConstants.BIOMETRIC_ERROR_HW_NOT_PRESENT;
61 
62     @IntDef({BIOMETRIC_SUCCESS,
63             BIOMETRIC_ERROR_HW_UNAVAILABLE,
64             BIOMETRIC_ERROR_NONE_ENROLLED,
65             BIOMETRIC_ERROR_NO_HARDWARE})
66     @interface BiometricError {}
67 
68     private final Context mContext;
69     private final IBiometricService mService;
70     private final boolean mHasHardware;
71 
72     /**
73      * @param context
74      * @return
75      * @hide
76      */
hasBiometrics(Context context)77     public static boolean hasBiometrics(Context context) {
78         final PackageManager pm = context.getPackageManager();
79         return pm.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)
80                 || pm.hasSystemFeature(PackageManager.FEATURE_IRIS)
81                 || pm.hasSystemFeature(PackageManager.FEATURE_FACE);
82     }
83 
84     /**
85      * @hide
86      * @param context
87      * @param service
88      */
BiometricManager(Context context, IBiometricService service)89     public BiometricManager(Context context, IBiometricService service) {
90         mContext = context;
91         mService = service;
92 
93         mHasHardware = hasBiometrics(context);
94     }
95 
96     /**
97      * Determine if biometrics can be used. In other words, determine if {@link BiometricPrompt}
98      * can be expected to be shown (hardware available, templates enrolled, user-enabled).
99      *
100      * @return Returns {@link #BIOMETRIC_ERROR_NONE_ENROLLED} if the user does not have any
101      *     enrolled, or {@link #BIOMETRIC_ERROR_HW_UNAVAILABLE} if none are currently
102      *     supported/enabled. Returns {@link #BIOMETRIC_SUCCESS} if a biometric can currently be
103      *     used (enrolled and available).
104      */
105     @RequiresPermission(USE_BIOMETRIC)
canAuthenticate()106     public @BiometricError int canAuthenticate() {
107         return canAuthenticate(mContext.getUserId());
108     }
109 
110     /**
111      * @hide
112      */
113     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
canAuthenticate(int userId)114     public @BiometricError int canAuthenticate(int userId) {
115         if (mService != null) {
116             try {
117                 return mService.canAuthenticate(mContext.getOpPackageName(), userId);
118             } catch (RemoteException e) {
119                 throw e.rethrowFromSystemServer();
120             }
121         } else {
122             if (!mHasHardware) {
123                 return BIOMETRIC_ERROR_NO_HARDWARE;
124             } else {
125                 Slog.w(TAG, "hasEnrolledBiometrics(): Service not connected");
126                 return BIOMETRIC_ERROR_HW_UNAVAILABLE;
127             }
128         }
129     }
130 
131     /**
132      * @hide
133      * @param userId
134      * @return
135      */
136     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
hasEnrolledBiometrics(int userId)137     public boolean hasEnrolledBiometrics(int userId) {
138         if (mService != null) {
139             try {
140                 return mService.hasEnrolledBiometrics(userId);
141             } catch (RemoteException e) {
142                 Slog.w(TAG, "Remote exception in hasEnrolledBiometrics(): " + e);
143                 return false;
144             }
145         } else {
146             return false;
147         }
148     }
149 
150     /**
151      * Listens for changes to biometric eligibility on keyguard from user settings.
152      * @param callback
153      * @hide
154      */
155     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback)156     public void registerEnabledOnKeyguardCallback(IBiometricEnabledOnKeyguardCallback callback) {
157         if (mService != null) {
158             try {
159                 mService.registerEnabledOnKeyguardCallback(callback);
160             } catch (RemoteException e) {
161                 throw e.rethrowFromSystemServer();
162             }
163         } else {
164             Slog.w(TAG, "registerEnabledOnKeyguardCallback(): Service not connected");
165         }
166     }
167 
168     /**
169      * Sets the active user.
170      * @hide
171      */
172     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
setActiveUser(int userId)173     public void setActiveUser(int userId) {
174         if (mService != null) {
175             try {
176                 mService.setActiveUser(userId);
177             } catch (RemoteException e) {
178                 throw e.rethrowFromSystemServer();
179             }
180         } else {
181             Slog.w(TAG, "setActiveUser(): Service not connected");
182         }
183     }
184 
185     /**
186      * Reset the lockout when user authenticates with strong auth (e.g. PIN, pattern or password)
187      *
188      * @param token an opaque token returned by password confirmation.
189      * @hide
190      */
191     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
resetLockout(byte[] token)192     public void resetLockout(byte[] token) {
193         if (mService != null) {
194             try {
195                 mService.resetLockout(token);
196             } catch (RemoteException e) {
197                 throw e.rethrowFromSystemServer();
198             }
199         } else {
200             Slog.w(TAG, "resetLockout(): Service not connected");
201         }
202     }
203 
204     /**
205      * TODO(b/123378871): Remove when moved.
206      * @hide
207      */
208     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
onConfirmDeviceCredentialSuccess()209     public void onConfirmDeviceCredentialSuccess() {
210         if (mService != null) {
211             try {
212                 mService.onConfirmDeviceCredentialSuccess();
213             } catch (RemoteException e) {
214                 throw e.rethrowFromSystemServer();
215             }
216         } else {
217             Slog.w(TAG, "onConfirmDeviceCredentialSuccess(): Service not connected");
218         }
219     }
220 
221     /**
222      * TODO(b/123378871): Remove when moved.
223      * @hide
224      */
225     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
onConfirmDeviceCredentialError(int error, String message)226     public void onConfirmDeviceCredentialError(int error, String message) {
227         if (mService != null) {
228             try {
229                 mService.onConfirmDeviceCredentialError(error, message);
230             } catch (RemoteException e) {
231                 throw e.rethrowFromSystemServer();
232             }
233         } else {
234             Slog.w(TAG, "onConfirmDeviceCredentialError(): Service not connected");
235         }
236     }
237 
238     /**
239      * TODO(b/123378871): Remove when moved.
240      * @hide
241      */
242     @RequiresPermission(USE_BIOMETRIC_INTERNAL)
registerCancellationCallback(IBiometricConfirmDeviceCredentialCallback callback)243     public void registerCancellationCallback(IBiometricConfirmDeviceCredentialCallback callback) {
244         if (mService != null) {
245             try {
246                 mService.registerCancellationCallback(callback);
247             } catch (RemoteException e) {
248                 throw e.rethrowFromSystemServer();
249             }
250         } else {
251             Slog.w(TAG, "registerCancellationCallback(): Service not connected");
252         }
253     }
254 }
255 
256