diff --git a/packages/local_auth/CHANGELOG.md b/packages/local_auth/CHANGELOG.md index fbbd49351d62..1988028a1f9d 100644 --- a/packages/local_auth/CHANGELOG.md +++ b/packages/local_auth/CHANGELOG.md @@ -1,3 +1,7 @@ +## 0.5.3 + +* Add face id detection as well by not relying on FingerprintCompat. + ## 0.5.2+4 * Update README to fix syntax error. diff --git a/packages/local_auth/README.md b/packages/local_auth/README.md index 3a429be8feea..9cb56e619b24 100644 --- a/packages/local_auth/README.md +++ b/packages/local_auth/README.md @@ -142,6 +142,12 @@ Update your project's `AndroidManifest.xml` file to include the ``` +On Android, you can check only for existence of fingerprint hardware prior +to API 29 (Android Q). Therefore, if you would like to support other biometrics +types (such as face scanning) and you want to support SDKs lower than Q, +*do not* call `getAvailableBiometrics`. Simply call `authenticateWithBiometrics`. +This will return an error if there was no hardware available. + ## Sticky Auth You can set the `stickyAuth` option on the plugin to true so that plugin does not diff --git a/packages/local_auth/android/build.gradle b/packages/local_auth/android/build.gradle index 4da3597692c1..142b606405c4 100644 --- a/packages/local_auth/android/build.gradle +++ b/packages/local_auth/android/build.gradle @@ -35,7 +35,7 @@ rootProject.allprojects { apply plugin: 'com.android.library' android { - compileSdkVersion 28 + compileSdkVersion 29 defaultConfig { minSdkVersion 16 diff --git a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java index b265dbda1a67..46d7bf3dec9a 100644 --- a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java +++ b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/AuthenticationHelper.java @@ -7,7 +7,6 @@ import android.app.Activity; import android.app.AlertDialog; import android.app.Application; -import android.app.KeyguardManager; import android.content.Context; import android.content.DialogInterface; import android.content.DialogInterface.OnClickListener; @@ -21,7 +20,6 @@ import android.view.View; import android.widget.TextView; import androidx.biometric.BiometricPrompt; -import androidx.core.hardware.fingerprint.FingerprintManagerCompat; import androidx.fragment.app.FragmentActivity; import io.flutter.plugin.common.MethodCall; import java.util.concurrent.Executor; @@ -60,8 +58,6 @@ interface AuthCompletionHandler { private final FragmentActivity activity; private final AuthCompletionHandler completionHandler; - private final KeyguardManager keyguardManager; - private final FingerprintManagerCompat fingerprintManager; private final MethodCall call; private final BiometricPrompt.PromptInfo promptInfo; private final boolean isAuthSticky; @@ -73,8 +69,6 @@ public AuthenticationHelper( this.activity = activity; this.completionHandler = completionHandler; this.call = call; - this.keyguardManager = (KeyguardManager) activity.getSystemService(Context.KEYGUARD_SERVICE); - this.fingerprintManager = FingerprintManagerCompat.from(activity); this.isAuthSticky = call.argument("stickyAuth"); this.uiThreadExecutor = new UiThreadExecutor(); this.promptInfo = @@ -86,28 +80,8 @@ public AuthenticationHelper( .build(); } - public void authenticate() { - if (fingerprintManager.isHardwareDetected()) { - if (keyguardManager.isKeyguardSecure() && fingerprintManager.hasEnrolledFingerprints()) { - start(); - } else { - if (call.argument("useErrorDialogs")) { - showGoToSettingsDialog(); - } else if (!keyguardManager.isKeyguardSecure()) { - completionHandler.onError( - "PasscodeNotSet", - "Phone not secured by PIN, pattern or password, or SIM is currently locked."); - } else { - completionHandler.onError("NotEnrolled", "No fingerprint enrolled on this device."); - } - } - } else { - completionHandler.onError("NotAvailable", "Fingerprint is not available on this device."); - } - } - /** Start the fingerprint listener. */ - private void start() { + public void authenticate() { activity.getApplication().registerActivityLifecycleCallbacks(this); new BiometricPrompt(activity, uiThreadExecutor, this).authenticate(promptInfo); } @@ -121,6 +95,25 @@ private void stop() { @Override public void onAuthenticationError(int errorCode, CharSequence errString) { switch (errorCode) { + // TODO(mehmetf): Re-enable when biometric alpha05 is released. + // https://developer.android.com/jetpack/androidx/releases/biometric + // case BiometricPrompt.ERROR_NO_DEVICE_CREDENTIAL: + // completionHandler.onError( + // "PasscodeNotSet", + // "Phone not secured by PIN, pattern or password, or SIM is currently locked."); + // break; + case BiometricPrompt.ERROR_NO_SPACE: + case BiometricPrompt.ERROR_NO_BIOMETRICS: + if (call.argument("useErrorDialogs")) { + showGoToSettingsDialog(); + return; + } + completionHandler.onError("NotEnrolled", "No Biometrics enrolled on this device."); + break; + case BiometricPrompt.ERROR_HW_UNAVAILABLE: + case BiometricPrompt.ERROR_HW_NOT_PRESENT: + completionHandler.onError("NotAvailable", "Biometrics is not available on this device."); + break; case BiometricPrompt.ERROR_LOCKOUT: completionHandler.onError( "LockedOut", diff --git a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java index 9c5f8bd7d014..ae69942c8229 100644 --- a/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java +++ b/packages/local_auth/android/src/main/java/io/flutter/plugins/localauth/LocalAuthPlugin.java @@ -5,7 +5,8 @@ package io.flutter.plugins.localauth; import android.app.Activity; -import androidx.core.hardware.fingerprint.FingerprintManagerCompat; +import android.content.pm.PackageManager; +import android.os.Build; import androidx.fragment.app.FragmentActivity; import io.flutter.plugin.common.MethodCall; import io.flutter.plugin.common.MethodChannel; @@ -87,21 +88,30 @@ public void onError(String code, String error) { authenticationHelper.authenticate(); } else if (call.method.equals("getAvailableBiometrics")) { try { + Activity activity = registrar.activity(); + if (activity == null || activity.isFinishing()) { + result.error("no_activity", "local_auth plugin requires a foreground activity", null); + return; + } ArrayList biometrics = new ArrayList(); - FingerprintManagerCompat fingerprintMgr = - FingerprintManagerCompat.from(registrar.activity()); - if (fingerprintMgr.isHardwareDetected()) { - if (fingerprintMgr.hasEnrolledFingerprints()) { + PackageManager packageManager = activity.getPackageManager(); + if (Build.VERSION.SDK_INT >= 23) { + if (packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) { biometrics.add("fingerprint"); - } else { - biometrics.add("undefined"); + } + } + if (Build.VERSION.SDK_INT >= 29) { + if (packageManager.hasSystemFeature(PackageManager.FEATURE_FACE)) { + biometrics.add("face"); + } + if (packageManager.hasSystemFeature(PackageManager.FEATURE_IRIS)) { + biometrics.add("iris"); } } result.success(biometrics); } catch (Exception e) { result.error("no_biometrics_available", e.getMessage(), null); } - } else { result.notImplemented(); } diff --git a/packages/local_auth/pubspec.yaml b/packages/local_auth/pubspec.yaml index 7531d03a9e03..286d7aa73871 100644 --- a/packages/local_auth/pubspec.yaml +++ b/packages/local_auth/pubspec.yaml @@ -3,7 +3,7 @@ description: Flutter plugin for Android and iOS device authentication sensors such as Fingerprint Reader and Touch ID. author: Flutter Team homepage: https://github.com/flutter/plugins/tree/master/packages/local_auth -version: 0.5.2+4 +version: 0.5.3 flutter: plugin: