1 /*
2  * Copyright (C) 2020 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 com.android.server.biometrics.sensors.fingerprint;
18 
19 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_GOOD;
20 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_IMAGER_DIRTY;
21 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_IMMOBILE;
22 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_INSUFFICIENT;
23 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_PARTIAL;
24 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_START;
25 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_TOO_BRIGHT;
26 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_TOO_FAST;
27 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_TOO_SLOW;
28 import static android.hardware.biometrics.BiometricFingerprintConstants.FINGERPRINT_ACQUIRED_VENDOR;
29 
30 import android.annotation.Nullable;
31 import android.content.Context;
32 import android.hardware.biometrics.fingerprint.V2_1.FingerprintError;
33 import android.hardware.fingerprint.Fingerprint;
34 import android.text.TextUtils;
35 import android.util.SparseArray;
36 
37 import com.android.internal.annotations.GuardedBy;
38 import com.android.server.biometrics.sensors.BiometricUtils;
39 
40 import java.util.List;
41 
42 /**
43  * Utility class for dealing with fingerprints and fingerprint settings.
44  */
45 public class FingerprintUtils implements BiometricUtils<Fingerprint> {
46 
47     private static final Object sInstanceLock = new Object();
48     // Map<SensorId, FingerprintUtils>
49     private static SparseArray<FingerprintUtils> sInstances;
50     private static final String LEGACY_FINGERPRINT_FILE = "settings_fingerprint.xml";
51 
52     @GuardedBy("this")
53     private final SparseArray<FingerprintUserState> mUserStates;
54     private final String mFileName;
55 
56     /**
57      * Retrieves an instance for the specified sensorId.
58      */
getInstance(int sensorId)59     public static FingerprintUtils getInstance(int sensorId) {
60         // Specify a null fileName to use an auto-generated sensorId-specific filename.
61         return getInstance(sensorId, null /* fileName */);
62     }
63 
64     /**
65      * Retrieves an instance for the specified sensorId. If the fileName is null, a default
66      * filename (e.g. settings_fingerprint_<sensorId>.xml will be generated.
67      *
68      * Specifying an explicit fileName allows for backward compatibility with legacy devices,
69      * where everything is stored in settings_fingerprint.xml.
70      */
getInstance(int sensorId, @Nullable String fileName)71     private static FingerprintUtils getInstance(int sensorId, @Nullable String fileName) {
72         final FingerprintUtils utils;
73         synchronized (sInstanceLock) {
74             if (sInstances == null) {
75                 sInstances = new SparseArray<>();
76             }
77             if (sInstances.get(sensorId) == null) {
78                 if (fileName == null) {
79                     fileName = "settings_fingerprint_" + sensorId + ".xml";
80                 }
81                 sInstances.put(sensorId, new FingerprintUtils(fileName));
82             }
83             utils = sInstances.get(sensorId);
84         }
85         return utils;
86     }
87 
88     /**
89      * Legacy getter for {@link android.hardware.biometrics.fingerprint.V2_1} ands its extended
90      * subclasses. Framework-side cache is always stored in the same file, regardless of sensorId.
91      */
getLegacyInstance(int sensorId)92     public static FingerprintUtils getLegacyInstance(int sensorId) {
93         // Note that sensorId for legacy services can be hard-coded to 0 since it's only used
94         // to index into the sensor states map.
95         return getInstance(sensorId, LEGACY_FINGERPRINT_FILE);
96     }
97 
FingerprintUtils(String fileName)98     private FingerprintUtils(String fileName) {
99         mUserStates = new SparseArray<>();
100         mFileName = fileName;
101     }
102 
103     @Override
getBiometricsForUser(Context ctx, int userId)104     public List<Fingerprint> getBiometricsForUser(Context ctx, int userId) {
105         return getStateForUser(ctx, userId).getBiometrics();
106     }
107 
108     @Override
addBiometricForUser(Context context, int userId, Fingerprint fingerprint)109     public void addBiometricForUser(Context context, int userId, Fingerprint fingerprint) {
110         getStateForUser(context, userId).addBiometric(fingerprint);
111     }
112 
113     @Override
removeBiometricForUser(Context context, int userId, int fingerId)114     public void removeBiometricForUser(Context context, int userId, int fingerId) {
115         getStateForUser(context, userId).removeBiometric(fingerId);
116     }
117 
118     @Override
renameBiometricForUser(Context context, int userId, int fingerId, CharSequence name)119     public void renameBiometricForUser(Context context, int userId, int fingerId,
120             CharSequence name) {
121         if (TextUtils.isEmpty(name)) {
122             // Don't do the rename if it's empty
123             return;
124         }
125         getStateForUser(context, userId).renameBiometric(fingerId, name);
126     }
127 
128     @Override
getUniqueName(Context context, int userId)129     public CharSequence getUniqueName(Context context, int userId) {
130         return getStateForUser(context, userId).getUniqueName();
131     }
132 
133     @Override
setInvalidationInProgress(Context context, int userId, boolean inProgress)134     public void setInvalidationInProgress(Context context, int userId, boolean inProgress) {
135         getStateForUser(context, userId).setInvalidationInProgress(inProgress);
136     }
137 
138     @Override
isInvalidationInProgress(Context context, int userId)139     public boolean isInvalidationInProgress(Context context, int userId) {
140         return getStateForUser(context, userId).isInvalidationInProgress();
141     }
142 
getStateForUser(Context ctx, int userId)143     private FingerprintUserState getStateForUser(Context ctx, int userId) {
144         synchronized (this) {
145             FingerprintUserState state = mUserStates.get(userId);
146             if (state == null) {
147                 state = new FingerprintUserState(ctx, userId, mFileName);
148                 mUserStates.put(userId, state);
149             }
150             return state;
151         }
152     }
153 
154     /**
155      * Checks if the given error code corresponds to a known fingerprint error.
156      *
157      * @param errorCode The error code to be checked.
158      * @return Whether the error code corresponds to a known error.
159      */
isKnownErrorCode(int errorCode)160     public static boolean isKnownErrorCode(int errorCode) {
161         switch (errorCode) {
162             case FingerprintError.ERROR_HW_UNAVAILABLE:
163             case FingerprintError.ERROR_UNABLE_TO_PROCESS:
164             case FingerprintError.ERROR_TIMEOUT:
165             case FingerprintError.ERROR_NO_SPACE:
166             case FingerprintError.ERROR_CANCELED:
167             case FingerprintError.ERROR_UNABLE_TO_REMOVE:
168             case FingerprintError.ERROR_LOCKOUT:
169             case FingerprintError.ERROR_VENDOR:
170                 return true;
171 
172             default:
173                 return false;
174         }
175     }
176 
177     /**
178      * Checks if the given acquired code corresponds to a known fingerprint error.
179      *
180      * @param acquiredCode The acquired code to be checked.
181      * @return Whether the acquired code corresponds to a known error.
182      */
isKnownAcquiredCode(int acquiredCode)183     public static boolean isKnownAcquiredCode(int acquiredCode) {
184         switch (acquiredCode) {
185             case FINGERPRINT_ACQUIRED_GOOD:
186             case FINGERPRINT_ACQUIRED_PARTIAL:
187             case FINGERPRINT_ACQUIRED_INSUFFICIENT:
188             case FINGERPRINT_ACQUIRED_IMAGER_DIRTY:
189             case FINGERPRINT_ACQUIRED_TOO_SLOW:
190             case FINGERPRINT_ACQUIRED_TOO_FAST:
191             case FINGERPRINT_ACQUIRED_VENDOR:
192             case FINGERPRINT_ACQUIRED_START:
193             case FINGERPRINT_ACQUIRED_TOO_BRIGHT:
194             case FINGERPRINT_ACQUIRED_IMMOBILE:
195                 return true;
196 
197             default:
198                 return false;
199         }
200     }
201 }
202 
203