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