blob: 6a8bd9e20e53c002cfd5a2b2ad9d78e159ed3507 [file] [log] [blame]
// Copyright 2017 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
package io.flutter.plugins.localauth;
import android.app.Activity;
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;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry.Registrar;
import io.flutter.plugins.localauth.AuthenticationHelper.AuthCompletionHandler;
import java.util.ArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
/** LocalAuthPlugin */
@SuppressWarnings("deprecation")
public class LocalAuthPlugin implements MethodCallHandler {
private final Registrar registrar;
private final AtomicBoolean authInProgress = new AtomicBoolean(false);
private AuthenticationHelper authenticationHelper;
/** Plugin registration. */
public static void registerWith(Registrar registrar) {
final MethodChannel channel =
new MethodChannel(registrar.messenger(), "plugins.flutter.io/local_auth");
channel.setMethodCallHandler(new LocalAuthPlugin(registrar));
}
private LocalAuthPlugin(Registrar registrar) {
this.registrar = registrar;
}
@Override
public void onMethodCall(MethodCall call, final Result result) {
if (call.method.equals("authenticateWithBiometrics")) {
if (authInProgress.get()) {
// Apps should not invoke another authentication request while one is in progress,
// so we classify this as an error condition. If we ever find a legitimate use case for
// this, we can try to cancel the ongoing auth and start a new one but for now, not worth
// the complexity.
result.error("auth_in_progress", "Authentication in progress", null);
return;
}
Activity activity = registrar.activity();
if (activity == null || activity.isFinishing()) {
result.error("no_activity", "local_auth plugin requires a foreground activity", null);
return;
}
if (!(activity instanceof FragmentActivity)) {
result.error(
"no_fragment_activity",
"local_auth plugin requires activity to be a FragmentActivity.",
null);
return;
}
authInProgress.set(true);
authenticationHelper =
new AuthenticationHelper(
(FragmentActivity) activity,
call,
new AuthCompletionHandler() {
@Override
public void onSuccess() {
if (authInProgress.compareAndSet(true, false)) {
result.success(true);
}
}
@Override
public void onFailure() {
if (authInProgress.compareAndSet(true, false)) {
result.success(false);
}
}
@Override
public void onError(String code, String error) {
if (authInProgress.compareAndSet(true, false)) {
result.error(code, error, null);
}
}
});
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<String> biometrics = new ArrayList<String>();
PackageManager packageManager = activity.getPackageManager();
if (Build.VERSION.SDK_INT >= 23) {
if (packageManager.hasSystemFeature(PackageManager.FEATURE_FINGERPRINT)) {
biometrics.add("fingerprint");
}
}
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 if (call.method.equals(("stopAuthentication"))) {
stopAuthentication(result);
} else {
result.notImplemented();
}
}
/*
Stops the authentication if in progress.
*/
private void stopAuthentication(Result result) {
try {
if (authenticationHelper != null && authInProgress.get()) {
authenticationHelper.stopAuthentication();
authenticationHelper = null;
result.success(true);
return;
}
result.success(false);
} catch (Exception e) {
result.success(false);
}
}
}