6

When my app hits the "Too Many Attempts...", authentication error 0x7, FINGERPRINT_ERROR_LOCKOUT, how can I tell without calling FingerprintManager.authenticate() in a loop and getting the error that the lockout condition is cleared?

neuman8
  • 324
  • 4
  • 15
  • Among the many things I tried was calling `hasEnrolledFingerprints()` and `isHardwareDetected()` during the lockout period in order to see if it would return or throw some sort of exception. No luck there, those calls work as expected. – neuman8 May 18 '16 at 16:13
  • Did you find a solution for this? I would also like to know the lockout time remaining and if the device is locked before calling authenticate(). – Niels Sep 01 '16 at 15:35
  • @Niels I have not pursued this anymore but a quick look through the latest version of the FingerprintManager.java source code shows me something like this: `public static abstract class LockoutResetCallback { //Called when lockout period expired and clients are allowed to listen for fingerprint again. public void onLockoutReset() { } }` – neuman8 Sep 01 '16 at 23:00
  • I bet the onLockoutReset() tells you asynchronously when the lockout period ended... However, I have not tested this. – neuman8 Sep 01 '16 at 23:06
  • Thanks, I will have a look. – Niels Sep 03 '16 at 06:08

1 Answers1

2

Looking at the AOSP implementation of the system FingerprintService, there is actually a broadcast intent that gets sent out after the lockout period has expired. The intent action to look for is com.android.server.fingerprint.ACTION_LOCKOUT_RESET.

In your Activity, you can register a broadcast receiver and wait for this intent, like so:

public class MyActivity extends Activity {
    ...
    private static final String ACTION_LOCKOUT_RESET =
        "com.android.server.fingerprint.ACTION_LOCKOUT_RESET";

    private final BroadcastReceiver mLockoutReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
                doWhateverYouNeedToDoAfterLockoutHasBeenReset();
            }
        }
    };

    private void registerLockoutResetReceiver() {
        Intent ret = getContext().registerReceiver(mLockoutReceiver, new IntentFilter(ACTION_LOCKOUT_RESET),
                null, null);
    }


    public void onCreate(Bundle savedInstanceState) {
        registerLockoutResetReceiver();
        ...
    }

    ...
}

WARNING: this is not part of the public API and so, this behavior may change with any later OS update. But I did try it on Nougat and it works quite well for me.

Reference:

The relevant AOSP code is ./frameworks/base/services/core/java/com/android/server/fingerprint/FingerprintService.java. In this file, we can find a PendingIntent with an ACTION_LOCKOUT_RESET intent being created:

private PendingIntent getLockoutResetIntent() {
    return PendingIntent.getBroadcast(mContext, 0,
            new Intent(ACTION_LOCKOUT_RESET), PendingIntent.FLAG_UPDATE_CURRENT);
}

This PendingIntent is registered to be set off after some elapsed time by the AlarmManager:

private void scheduleLockoutReset() {
    mAlarmManager.set(AlarmManager.ELAPSED_REALTIME_WAKEUP,
            SystemClock.elapsedRealtime() + FAIL_LOCKOUT_TIMEOUT_MS, getLockoutResetIntent());
}
hopia
  • 4,880
  • 7
  • 32
  • 54
  • I tried this, but after I receive the broadcast, the fingerprint device would not react to any fingerprint scanning. I had to restart activity to rescan. Anyone seeing similar issue? – Jeffrey Liu Sep 07 '17 at 18:13
  • @JeffreyLiu After the lockout, you have to restart your Fingerprint Device manager. – hopia Sep 28 '17 at 16:58
  • How do you restart?@hopia – Jeffrey Liu Sep 28 '17 at 22:06
  • 1
    You call cancel() on the CancellationSignal object you registered when you started the fingerprint manager: mCancellationSignal.cancel(); And then you call mFingerPrintManager.authenticate() again. – hopia Sep 28 '17 at 23:03