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.hidl; 18 19 import android.annotation.NonNull; 20 import android.annotation.Nullable; 21 import android.app.trust.TrustManager; 22 import android.content.ContentResolver; 23 import android.content.Context; 24 import android.hardware.fingerprint.FingerprintManager; 25 import android.hardware.fingerprint.FingerprintManager.AuthenticationCallback; 26 import android.hardware.fingerprint.FingerprintManager.AuthenticationResult; 27 import android.hardware.fingerprint.FingerprintSensorProperties; 28 import android.hardware.fingerprint.FingerprintSensorPropertiesInternal; 29 import android.hardware.fingerprint.IUdfpsOverlayController; 30 import android.os.Handler; 31 import android.os.IBinder; 32 import android.os.Looper; 33 import android.os.RemoteException; 34 import android.os.UserHandle; 35 import android.provider.Settings; 36 import android.util.Slog; 37 import android.util.SparseBooleanArray; 38 39 import com.android.internal.R; 40 import com.android.server.biometrics.sensors.AuthenticationConsumer; 41 import com.android.server.biometrics.sensors.BaseClientMonitor; 42 import com.android.server.biometrics.sensors.BiometricScheduler; 43 import com.android.server.biometrics.sensors.ClientMonitorCallbackConverter; 44 import com.android.server.biometrics.sensors.LockoutResetDispatcher; 45 import com.android.server.biometrics.sensors.fingerprint.FingerprintStateCallback; 46 import com.android.server.biometrics.sensors.fingerprint.GestureAvailabilityDispatcher; 47 48 import java.util.ArrayList; 49 import java.util.List; 50 import java.util.Random; 51 52 /** 53 * A mockable/testable provider of the {@link android.hardware.biometrics.fingerprint.V2_3} HIDL 54 * interface. This class is intended simulate UDFPS logic for devices that do not have an actual 55 * fingerprint@2.3 HAL (where UDFPS starts to become supported) 56 * 57 * UDFPS "accept" can only happen within a set amount of time after a sensor authentication. This is 58 * specified by {@link MockHalResultController#AUTH_VALIDITY_MS}. Touches after this duration will 59 * be treated as "reject". 60 * 61 * This class provides framework logic to emulate, for testing only, the UDFPS functionalies below: 62 * 63 * 1) IF either A) the caller is keyguard, and the device is not in a trusted state (authenticated 64 * via biometric sensor or unlocked with a trust agent {@see android.app.trust.TrustManager}, OR 65 * B) the caller is not keyguard, and regardless of trusted state, AND (following applies to both 66 * (A) and (B) above) {@link FingerprintManager#onFingerDown(int, int, float, float)} is 67 * received, this class will respond with {@link AuthenticationCallback#onAuthenticationFailed()} 68 * after a tunable flat_time + variance_time. 69 * 70 * In the case above (1), callers must not receive a successful authentication event here because 71 * the sensor has not actually been authenticated. 72 * 73 * 2) IF A) the caller is keyguard and the device is not in a trusted state, OR B) the caller is not 74 * keyguard and regardless of trusted state, AND (following applies to both (A) and (B)) the 75 * sensor is touched and the fingerprint is accepted by the HAL, and then 76 * {@link FingerprintManager#onFingerDown(int, int, float, float)} is received, this class will 77 * respond with {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} 78 * after a tunable flat_time + variance_time. Note that the authentication callback from the 79 * sensor is held until {@link FingerprintManager#onFingerDown(int, int, float, float)} is 80 * invoked. 81 * 82 * In the case above (2), callers can receive a successful authentication callback because the 83 * real sensor was authenticated. Note that even though the real sensor was touched, keyguard 84 * fingerprint authentication does not put keyguard into a trusted state because the 85 * authentication callback is held until onFingerDown was invoked. This allows callers such as 86 * keyguard to simulate a realistic path. 87 * 88 * 3) IF the caller is keyguard AND the device in a trusted state and then 89 * {@link FingerprintManager#onFingerDown(int, int, float, float)} is received, this class will 90 * respond with {@link AuthenticationCallback#onAuthenticationSucceeded(AuthenticationResult)} 91 * after a tunable flat_time + variance time. 92 * 93 * In the case above (3), since the device is already unlockable via trust agent, it's fine to 94 * simulate the successful auth path. Non-keyguard clients will fall into either (1) or (2) 95 * above. 96 * 97 * This class currently does not simulate false rejection. Conversely, this class relies on the 98 * real hardware sensor so does not affect false acceptance. 99 */ 100 @SuppressWarnings("deprecation") 101 public class Fingerprint21UdfpsMock extends Fingerprint21 implements TrustManager.TrustListener { 102 103 private static final String TAG = "Fingerprint21UdfpsMock"; 104 105 // Secure setting integer. If true, the system will load this class to enable udfps testing. 106 public static final String CONFIG_ENABLE_TEST_UDFPS = 107 "com.android.server.biometrics.sensors.fingerprint.test_udfps.enable"; 108 // Secure setting integer. A fixed duration intended to simulate something like the duration 109 // required for image capture. 110 private static final String CONFIG_AUTH_DELAY_PT1 = 111 "com.android.server.biometrics.sensors.fingerprint.test_udfps.auth_delay_pt1"; 112 // Secure setting integer. A fixed duration intended to simulate something like the duration 113 // required for template matching to complete. 114 private static final String CONFIG_AUTH_DELAY_PT2 = 115 "com.android.server.biometrics.sensors.fingerprint.test_udfps.auth_delay_pt2"; 116 // Secure setting integer. A random value between [-randomness, randomness] will be added to the 117 // capture delay above for each accept/reject. 118 private static final String CONFIG_AUTH_DELAY_RANDOMNESS = 119 "com.android.server.biometrics.sensors.fingerprint.test_udfps.auth_delay_randomness"; 120 121 private static final int DEFAULT_AUTH_DELAY_PT1_MS = 300; 122 private static final int DEFAULT_AUTH_DELAY_PT2_MS = 400; 123 private static final int DEFAULT_AUTH_DELAY_RANDOMNESS_MS = 100; 124 125 @NonNull private final TestableBiometricScheduler mScheduler; 126 @NonNull private final Handler mHandler; 127 @NonNull private final FingerprintSensorPropertiesInternal mSensorProperties; 128 @NonNull private final MockHalResultController mMockHalResultController; 129 @NonNull private final TrustManager mTrustManager; 130 @NonNull private final SparseBooleanArray mUserHasTrust; 131 @NonNull private final Random mRandom; 132 @NonNull private final FakeRejectRunnable mFakeRejectRunnable; 133 @NonNull private final FakeAcceptRunnable mFakeAcceptRunnable; 134 @NonNull private final RestartAuthRunnable mRestartAuthRunnable; 135 136 private static class TestableBiometricScheduler extends BiometricScheduler { 137 @NonNull private Fingerprint21UdfpsMock mFingerprint21; 138 TestableBiometricScheduler(@onNull String tag, @NonNull Handler handler, @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher)139 TestableBiometricScheduler(@NonNull String tag, @NonNull Handler handler, 140 @Nullable GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { 141 super(tag, BiometricScheduler.SENSOR_TYPE_FP_OTHER, gestureAvailabilityDispatcher); 142 } 143 init(@onNull Fingerprint21UdfpsMock fingerprint21)144 void init(@NonNull Fingerprint21UdfpsMock fingerprint21) { 145 mFingerprint21 = fingerprint21; 146 } 147 } 148 149 /** 150 * All of the mocking/testing should happen in here. This way we don't need to modify the 151 * {@link BaseClientMonitor} implementations and can run the 152 * real path there. 153 */ 154 private static class MockHalResultController extends HalResultController { 155 156 // Duration for which a sensor authentication can be treated as UDFPS success. 157 private static final int AUTH_VALIDITY_MS = 10 * 1000; // 10 seconds 158 159 static class LastAuthArgs { 160 @NonNull final AuthenticationConsumer lastAuthenticatedClient; 161 final long deviceId; 162 final int fingerId; 163 final int groupId; 164 @Nullable final ArrayList<Byte> token; 165 LastAuthArgs(@onNull AuthenticationConsumer authenticationConsumer, long deviceId, int fingerId, int groupId, @Nullable ArrayList<Byte> token)166 LastAuthArgs(@NonNull AuthenticationConsumer authenticationConsumer, long deviceId, 167 int fingerId, int groupId, @Nullable ArrayList<Byte> token) { 168 lastAuthenticatedClient = authenticationConsumer; 169 this.deviceId = deviceId; 170 this.fingerId = fingerId; 171 this.groupId = groupId; 172 if (token == null) { 173 this.token = null; 174 } else { 175 // Store a copy so the owner can be GC'd 176 this.token = new ArrayList<>(token); 177 } 178 } 179 } 180 181 // Initialized after the constructor, but before it's ever used. 182 @NonNull private RestartAuthRunnable mRestartAuthRunnable; 183 @NonNull private Fingerprint21UdfpsMock mFingerprint21; 184 @Nullable private LastAuthArgs mLastAuthArgs; 185 MockHalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler, @NonNull BiometricScheduler scheduler)186 MockHalResultController(int sensorId, @NonNull Context context, @NonNull Handler handler, 187 @NonNull BiometricScheduler scheduler) { 188 super(sensorId, context, handler, scheduler); 189 } 190 init(@onNull RestartAuthRunnable restartAuthRunnable, @NonNull Fingerprint21UdfpsMock fingerprint21)191 void init(@NonNull RestartAuthRunnable restartAuthRunnable, 192 @NonNull Fingerprint21UdfpsMock fingerprint21) { 193 mRestartAuthRunnable = restartAuthRunnable; 194 mFingerprint21 = fingerprint21; 195 } 196 getLastAuthenticatedClient()197 @Nullable AuthenticationConsumer getLastAuthenticatedClient() { 198 return mLastAuthArgs != null ? mLastAuthArgs.lastAuthenticatedClient : null; 199 } 200 201 /** 202 * Intercepts the HAL authentication and holds it until the UDFPS simulation decides 203 * that authentication finished. 204 */ 205 @Override onAuthenticated(long deviceId, int fingerId, int groupId, ArrayList<Byte> token)206 public void onAuthenticated(long deviceId, int fingerId, int groupId, 207 ArrayList<Byte> token) { 208 mHandler.post(() -> { 209 final BaseClientMonitor client = mScheduler.getCurrentClient(); 210 if (!(client instanceof AuthenticationConsumer)) { 211 Slog.e(TAG, "Non authentication consumer: " + client); 212 return; 213 } 214 215 final boolean accepted = fingerId != 0; 216 if (accepted) { 217 mFingerprint21.setDebugMessage("Finger accepted"); 218 } else { 219 mFingerprint21.setDebugMessage("Finger rejected"); 220 } 221 222 final AuthenticationConsumer authenticationConsumer = 223 (AuthenticationConsumer) client; 224 mLastAuthArgs = new LastAuthArgs(authenticationConsumer, deviceId, fingerId, 225 groupId, token); 226 227 // Remove any existing restart runnbables since auth just started, and put a new 228 // one on the queue. 229 mHandler.removeCallbacks(mRestartAuthRunnable); 230 mRestartAuthRunnable.setLastAuthReference(authenticationConsumer); 231 mHandler.postDelayed(mRestartAuthRunnable, AUTH_VALIDITY_MS); 232 }); 233 } 234 235 /** 236 * Calls through to the real interface and notifies clients of accept/reject. 237 */ sendAuthenticated(long deviceId, int fingerId, int groupId, ArrayList<Byte> token)238 void sendAuthenticated(long deviceId, int fingerId, int groupId, 239 ArrayList<Byte> token) { 240 Slog.d(TAG, "sendAuthenticated: " + (fingerId != 0)); 241 mFingerprint21.setDebugMessage("Udfps match: " + (fingerId != 0)); 242 super.onAuthenticated(deviceId, fingerId, groupId, token); 243 } 244 } 245 newInstance(@onNull Context context, @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher)246 public static Fingerprint21UdfpsMock newInstance(@NonNull Context context, 247 @NonNull FingerprintStateCallback fingerprintStateCallback, 248 @NonNull FingerprintSensorPropertiesInternal sensorProps, 249 @NonNull LockoutResetDispatcher lockoutResetDispatcher, 250 @NonNull GestureAvailabilityDispatcher gestureAvailabilityDispatcher) { 251 Slog.d(TAG, "Creating Fingerprint23Mock!"); 252 253 final Handler handler = new Handler(Looper.getMainLooper()); 254 final TestableBiometricScheduler scheduler = 255 new TestableBiometricScheduler(TAG, handler, gestureAvailabilityDispatcher); 256 final MockHalResultController controller = 257 new MockHalResultController(sensorProps.sensorId, context, handler, scheduler); 258 return new Fingerprint21UdfpsMock(context, fingerprintStateCallback, sensorProps, scheduler, 259 handler, lockoutResetDispatcher, controller); 260 } 261 262 private static abstract class FakeFingerRunnable implements Runnable { 263 private long mFingerDownTime; 264 private int mCaptureDuration; 265 266 /** 267 * @param fingerDownTime System time when onFingerDown occurred 268 * @param captureDuration Duration that the finger needs to be down for 269 */ setSimulationTime(long fingerDownTime, int captureDuration)270 void setSimulationTime(long fingerDownTime, int captureDuration) { 271 mFingerDownTime = fingerDownTime; 272 mCaptureDuration = captureDuration; 273 } 274 275 @SuppressWarnings("BooleanMethodIsAlwaysInverted") isImageCaptureComplete()276 boolean isImageCaptureComplete() { 277 return System.currentTimeMillis() - mFingerDownTime > mCaptureDuration; 278 } 279 } 280 281 private final class FakeRejectRunnable extends FakeFingerRunnable { 282 @Override run()283 public void run() { 284 mMockHalResultController.sendAuthenticated(0, 0, 0, null); 285 } 286 } 287 288 private final class FakeAcceptRunnable extends FakeFingerRunnable { 289 @Override run()290 public void run() { 291 if (mMockHalResultController.mLastAuthArgs == null) { 292 // This can happen if the user has trust agents enabled, which make lockscreen 293 // dismissable. Send a fake non-zero (accept) finger. 294 Slog.d(TAG, "Sending fake finger"); 295 mMockHalResultController.sendAuthenticated(1 /* deviceId */, 296 1 /* fingerId */, 1 /* groupId */, null /* token */); 297 } else { 298 mMockHalResultController.sendAuthenticated( 299 mMockHalResultController.mLastAuthArgs.deviceId, 300 mMockHalResultController.mLastAuthArgs.fingerId, 301 mMockHalResultController.mLastAuthArgs.groupId, 302 mMockHalResultController.mLastAuthArgs.token); 303 } 304 } 305 } 306 307 /** 308 * The fingerprint HAL allows multiple (5) fingerprint attempts per HIDL invocation of the 309 * authenticate method. However, valid fingerprint authentications are invalidated after 310 * {@link MockHalResultController#AUTH_VALIDITY_MS}, meaning UDFPS touches will be reported as 311 * rejects if touched after that duration. However, since a valid fingerprint was detected, the 312 * HAL and FingerprintService will not look for subsequent fingerprints. 313 * 314 * In order to keep the FingerprintManager API consistent (that multiple fingerprint attempts 315 * are allowed per auth lifecycle), we internally cancel and restart authentication so that the 316 * sensor is responsive again. 317 */ 318 private static final class RestartAuthRunnable implements Runnable { 319 @NonNull private final Fingerprint21UdfpsMock mFingerprint21; 320 @NonNull private final TestableBiometricScheduler mScheduler; 321 322 // Store a reference to the auth consumer that should be invalidated. 323 private AuthenticationConsumer mLastAuthConsumer; 324 RestartAuthRunnable(@onNull Fingerprint21UdfpsMock fingerprint21, @NonNull TestableBiometricScheduler scheduler)325 RestartAuthRunnable(@NonNull Fingerprint21UdfpsMock fingerprint21, 326 @NonNull TestableBiometricScheduler scheduler) { 327 mFingerprint21 = fingerprint21; 328 mScheduler = scheduler; 329 } 330 setLastAuthReference(AuthenticationConsumer lastAuthConsumer)331 void setLastAuthReference(AuthenticationConsumer lastAuthConsumer) { 332 mLastAuthConsumer = lastAuthConsumer; 333 } 334 335 @Override run()336 public void run() { 337 final BaseClientMonitor client = mScheduler.getCurrentClient(); 338 339 // We don't care about FingerprintDetectClient, since accept/rejects are both OK. UDFPS 340 // rejects will just simulate the path where non-enrolled fingers are presented. 341 if (!(client instanceof FingerprintAuthenticationClient)) { 342 Slog.e(TAG, "Non-FingerprintAuthenticationClient client: " + client); 343 return; 344 } 345 346 // Perhaps the runnable is stale, or the user stopped/started auth manually. Do not 347 // restart auth in this case. 348 if (client != mLastAuthConsumer) { 349 Slog.e(TAG, "Current client: " + client 350 + " does not match mLastAuthConsumer: " + mLastAuthConsumer); 351 return; 352 } 353 354 Slog.d(TAG, "Restarting auth, current: " + client); 355 mFingerprint21.setDebugMessage("Auth timed out"); 356 357 final FingerprintAuthenticationClient authClient = 358 (FingerprintAuthenticationClient) client; 359 // Store the authClient parameters so it can be rescheduled 360 final IBinder token = client.getToken(); 361 final long operationId = authClient.getOperationId(); 362 final int user = client.getTargetUserId(); 363 final int cookie = client.getCookie(); 364 final ClientMonitorCallbackConverter listener = client.getListener(); 365 final String opPackageName = client.getOwnerString(); 366 final boolean restricted = authClient.isRestricted(); 367 final int statsClient = client.getStatsClient(); 368 final boolean isKeyguard = authClient.isKeyguard(); 369 370 // Don't actually send cancel() to the HAL, since successful auth already finishes 371 // HAL authenticate() lifecycle. Just 372 mScheduler.getInternalCallback().onClientFinished(client, true /* success */); 373 374 // Schedule this only after we invoke onClientFinished for the previous client, so that 375 // internal preemption logic is not run. 376 mFingerprint21.scheduleAuthenticate(mFingerprint21.mSensorProperties.sensorId, token, 377 operationId, user, cookie, listener, opPackageName, restricted, statsClient, 378 isKeyguard); 379 } 380 } 381 Fingerprint21UdfpsMock(@onNull Context context, @NonNull FingerprintStateCallback fingerprintStateCallback, @NonNull FingerprintSensorPropertiesInternal sensorProps, @NonNull TestableBiometricScheduler scheduler, @NonNull Handler handler, @NonNull LockoutResetDispatcher lockoutResetDispatcher, @NonNull MockHalResultController controller)382 private Fingerprint21UdfpsMock(@NonNull Context context, 383 @NonNull FingerprintStateCallback fingerprintStateCallback, 384 @NonNull FingerprintSensorPropertiesInternal sensorProps, 385 @NonNull TestableBiometricScheduler scheduler, 386 @NonNull Handler handler, 387 @NonNull LockoutResetDispatcher lockoutResetDispatcher, 388 @NonNull MockHalResultController controller) { 389 super(context, fingerprintStateCallback, sensorProps, scheduler, handler, 390 lockoutResetDispatcher, controller); 391 mScheduler = scheduler; 392 mScheduler.init(this); 393 mHandler = handler; 394 // resetLockout is controlled by the framework, so hardwareAuthToken is not required 395 final boolean resetLockoutRequiresHardwareAuthToken = false; 396 final int maxTemplatesAllowed = mContext.getResources() 397 .getInteger(R.integer.config_fingerprintMaxTemplatesPerUser); 398 mSensorProperties = new FingerprintSensorPropertiesInternal(sensorProps.sensorId, 399 sensorProps.sensorStrength, maxTemplatesAllowed, sensorProps.componentInfo, 400 FingerprintSensorProperties.TYPE_UDFPS_OPTICAL, 401 resetLockoutRequiresHardwareAuthToken, sensorProps.getAllLocations()); 402 mMockHalResultController = controller; 403 mUserHasTrust = new SparseBooleanArray(); 404 mTrustManager = context.getSystemService(TrustManager.class); 405 mTrustManager.registerTrustListener(this); 406 mRandom = new Random(); 407 mFakeRejectRunnable = new FakeRejectRunnable(); 408 mFakeAcceptRunnable = new FakeAcceptRunnable(); 409 mRestartAuthRunnable = new RestartAuthRunnable(this, mScheduler); 410 411 // We can't initialize this during MockHalresultController's constructor due to a circular 412 // dependency. 413 mMockHalResultController.init(mRestartAuthRunnable, this); 414 } 415 416 @Override onTrustChanged(boolean enabled, int userId, int flags)417 public void onTrustChanged(boolean enabled, int userId, int flags) { 418 mUserHasTrust.put(userId, enabled); 419 } 420 421 @Override onTrustManagedChanged(boolean enabled, int userId)422 public void onTrustManagedChanged(boolean enabled, int userId) { 423 424 } 425 426 @Override onTrustError(CharSequence message)427 public void onTrustError(CharSequence message) { 428 429 } 430 431 @Override 432 @NonNull getSensorProperties()433 public List<FingerprintSensorPropertiesInternal> getSensorProperties() { 434 final List<FingerprintSensorPropertiesInternal> properties = new ArrayList<>(); 435 properties.add(mSensorProperties); 436 return properties; 437 } 438 439 @Override onPointerDown(int sensorId, int x, int y, float minor, float major)440 public void onPointerDown(int sensorId, int x, int y, float minor, float major) { 441 mHandler.post(() -> { 442 Slog.d(TAG, "onFingerDown"); 443 final AuthenticationConsumer lastAuthenticatedConsumer = 444 mMockHalResultController.getLastAuthenticatedClient(); 445 final BaseClientMonitor currentScheduledClient = mScheduler.getCurrentClient(); 446 447 if (currentScheduledClient == null) { 448 Slog.d(TAG, "Not authenticating"); 449 return; 450 } 451 452 mHandler.removeCallbacks(mFakeRejectRunnable); 453 mHandler.removeCallbacks(mFakeAcceptRunnable); 454 455 // The sensor was authenticated, is still the currently scheduled client, and the 456 // user touched the UDFPS affordance. Pretend that auth succeeded. 457 final boolean authenticatedClientIsCurrent = lastAuthenticatedConsumer != null 458 && lastAuthenticatedConsumer == currentScheduledClient; 459 // User is unlocked on keyguard via Trust Agent 460 final boolean keyguardAndTrusted; 461 if (currentScheduledClient instanceof FingerprintAuthenticationClient) { 462 keyguardAndTrusted = ((FingerprintAuthenticationClient) currentScheduledClient) 463 .isKeyguard() 464 && mUserHasTrust.get(currentScheduledClient.getTargetUserId(), false); 465 } else { 466 keyguardAndTrusted = false; 467 } 468 469 final int captureDuration = getNewCaptureDuration(); 470 final int matchingDuration = getMatchingDuration(); 471 final int totalDuration = captureDuration + matchingDuration; 472 setDebugMessage("Duration: " + totalDuration 473 + " (" + captureDuration + " + " + matchingDuration + ")"); 474 if (authenticatedClientIsCurrent || keyguardAndTrusted) { 475 mFakeAcceptRunnable.setSimulationTime(System.currentTimeMillis(), captureDuration); 476 mHandler.postDelayed(mFakeAcceptRunnable, totalDuration); 477 } else if (currentScheduledClient instanceof AuthenticationConsumer) { 478 // Something is authenticating but authentication has not succeeded yet. Pretend 479 // that auth rejected. 480 mFakeRejectRunnable.setSimulationTime(System.currentTimeMillis(), captureDuration); 481 mHandler.postDelayed(mFakeRejectRunnable, totalDuration); 482 } 483 }); 484 } 485 486 @Override onPointerUp(int sensorId)487 public void onPointerUp(int sensorId) { 488 mHandler.post(() -> { 489 Slog.d(TAG, "onFingerUp"); 490 491 // Only one of these can be on the handler at any given time (see onFingerDown). If 492 // image capture is not complete, send ACQUIRED_TOO_FAST and remove the runnable from 493 // the handler. Image capture (onFingerDown) needs to happen again. 494 if (mHandler.hasCallbacks(mFakeRejectRunnable) 495 && !mFakeRejectRunnable.isImageCaptureComplete()) { 496 mHandler.removeCallbacks(mFakeRejectRunnable); 497 mMockHalResultController.onAcquired(0 /* deviceId */, 498 FingerprintManager.FINGERPRINT_ACQUIRED_TOO_FAST, 499 0 /* vendorCode */); 500 } else if (mHandler.hasCallbacks(mFakeAcceptRunnable) 501 && !mFakeAcceptRunnable.isImageCaptureComplete()) { 502 mHandler.removeCallbacks(mFakeAcceptRunnable); 503 mMockHalResultController.onAcquired(0 /* deviceId */, 504 FingerprintManager.FINGERPRINT_ACQUIRED_TOO_FAST, 505 0 /* vendorCode */); 506 } 507 }); 508 } 509 getNewCaptureDuration()510 private int getNewCaptureDuration() { 511 final ContentResolver contentResolver = mContext.getContentResolver(); 512 final int captureTime = Settings.Secure.getIntForUser(contentResolver, 513 CONFIG_AUTH_DELAY_PT1, 514 DEFAULT_AUTH_DELAY_PT1_MS, 515 UserHandle.USER_CURRENT); 516 final int randomDelayRange = Settings.Secure.getIntForUser(contentResolver, 517 CONFIG_AUTH_DELAY_RANDOMNESS, 518 DEFAULT_AUTH_DELAY_RANDOMNESS_MS, 519 UserHandle.USER_CURRENT); 520 final int randomDelay = mRandom.nextInt(randomDelayRange * 2) - randomDelayRange; 521 522 // Must be at least 0 523 return Math.max(captureTime + randomDelay, 0); 524 } 525 getMatchingDuration()526 private int getMatchingDuration() { 527 final int matchingTime = Settings.Secure.getIntForUser(mContext.getContentResolver(), 528 CONFIG_AUTH_DELAY_PT2, 529 DEFAULT_AUTH_DELAY_PT2_MS, 530 UserHandle.USER_CURRENT); 531 532 // Must be at least 0 533 return Math.max(matchingTime, 0); 534 } 535 setDebugMessage(String message)536 private void setDebugMessage(String message) { 537 try { 538 final IUdfpsOverlayController controller = getUdfpsOverlayController(); 539 // Things can happen before SysUI loads and sets the controller. 540 if (controller != null) { 541 Slog.d(TAG, "setDebugMessage: " + message); 542 controller.setDebugMessage(mSensorProperties.sensorId, message); 543 } 544 } catch (RemoteException e) { 545 Slog.e(TAG, "Remote exception when sending message: " + message, e); 546 } 547 } 548 } 549