Skip to content

Commit

Permalink
Merge pull request NiklasMerz#8 from exxbrain/2.0.0-biometricpromt-an…
Browse files Browse the repository at this point in the history
…d-consistent-callbacks

2.0.0 biometricpromt and consistent callbacks
  • Loading branch information
greaterking authored Oct 16, 2019
2 parents 177d04a + 9c0ba00 commit 7e5ff42
Show file tree
Hide file tree
Showing 10 changed files with 371 additions and 178 deletions.
6 changes: 4 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@
"test-travis": "npm run test-ios",
"test-appveyor": "npm run test-browser",
"test-local": "npm run test-browser && npm run test-android && npm run test-ios",
"test-android": "npx cordova-paramedic --platform android --plugin $(pwd)",
"test-android": "npx cordova-paramedic --platform android@8.1.0 --plugin $(pwd)",
"test-ios": "npx cordova-paramedic --platform ios --plugin $(pwd) --verbose",
"test-windows": "npx cordova-paramedic --platform windows --plugin $(pwd)",
"test-browser": "npx cordova-paramedic --platform browser --plugin $(pwd)",
Expand All @@ -56,7 +56,9 @@
},
"engines": {
"cordovaDependencies": {
">=3.0.0": { "cordova-android": ">=8.0.0" }
">=3.0.0": {
"cordova-android": ">=8.0.0"
}
}
}
}
12 changes: 12 additions & 0 deletions plugin.xml
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,20 @@
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.USE_FINGERPRINT"/>
</config-file>

<config-file target="AndroidManifest.xml" parent="/manifest/application">
<activity
android:name="de.niklasmerz.cordova.biometric.BiometricActivity"
android:theme="@style/TransparentTheme"
android:exported="true" />
</config-file>

<framework src="src/android/build.gradle" custom="true" type="gradleReference"/>
<resource-file src="src/android/res/biometric_activity.xml" target="res/layout/biometric_activity.xml" />
<resource-file src="src/android/res/styles.xml" target="res/values/biometric-styles.xml" />
<resource-file src="src/android/android-biometric.aar" target="libs/android-biometric.aar" />
<source-file src="src/android/PromptInfo.java" target-dir="src/de/niklasmerz/cordova/biometric"/>
<source-file src="src/android/BiometricActivity.java" target-dir="src/de/niklasmerz/cordova/biometric"/>
<source-file src="src/android/Fingerprint.java" target-dir="src/de/niklasmerz/cordova/biometric"/>
<source-file src="src/android/PluginError.java" target-dir="src/de/niklasmerz/cordova/biometric"/>
</platform>
Expand Down
158 changes: 158 additions & 0 deletions src/android/BiometricActivity.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,158 @@
package de.niklasmerz.cordova.biometric;

import android.app.Activity;
import android.app.KeyguardManager;
import android.content.Intent;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;

import com.exxbrain.android.biometric.BiometricPrompt;

import java.util.concurrent.Executor;

public class BiometricActivity extends AppCompatActivity {

private static final int REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS = 2;
private PromptInfo mPromptInfo;

@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);

setTitle(null);
int layout = getResources()
.getIdentifier("biometric_activity", "layout", getPackageName());
setContentView(layout);

if (savedInstanceState != null) {
return;
}

mPromptInfo = new PromptInfo.Builder(getIntent().getExtras()).build();
authenticate();

}

private void authenticate() {
final Handler handler = new Handler(Looper.getMainLooper());
Executor executor = handler::post;

BiometricPrompt biometricPrompt =
new BiometricPrompt(this, executor, mAuthenticationCallback);

BiometricPrompt.PromptInfo.Builder promptInfoBuilder = new BiometricPrompt.PromptInfo.Builder()
.setTitle(mPromptInfo.getTitle())
.setSubtitle(mPromptInfo.getSubtitle())
.setDescription(mPromptInfo.getDescription());

if (mPromptInfo.isDeviceCredentialAllowed()
&& Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) { // TODO: remove after fix https://issuetracker.google.com/issues/142740104
promptInfoBuilder.setDeviceCredentialAllowed(true);
} else {
promptInfoBuilder.setNegativeButtonText(mPromptInfo.getFallbackButtonTitle());
}

biometricPrompt.authenticate(promptInfoBuilder.build());
}

private BiometricPrompt.AuthenticationCallback mAuthenticationCallback =
new BiometricPrompt.AuthenticationCallback() {

@Override
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
onError(errorCode, errString);
}

@Override
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
finishWithSuccess();
}

@Override
public void onAuthenticationFailed() {
super.onAuthenticationFailed();
}
};


// TODO: remove after fix https://issuetracker.google.com/issues/142740104
private void showAuthenticationScreen() {
KeyguardManager keyguardManager = ContextCompat
.getSystemService(this, KeyguardManager.class);
if (keyguardManager == null
|| android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.LOLLIPOP) {
return;
}
if (keyguardManager.isKeyguardSecure()) {
Intent intent = keyguardManager
.createConfirmDeviceCredentialIntent(mPromptInfo.getTitle(), mPromptInfo.getDescription());
this.startActivityForResult(intent, REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS);
} else {
// Show a message that the user hasn't set up a lock screen.
finishWithError(PluginError.BIOMETRIC_SCREEN_GUARD_UNSECURED);
}
}

// TODO: remove after fix https://issuetracker.google.com/issues/142740104
@Override
public void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == REQUEST_CODE_CONFIRM_DEVICE_CREDENTIALS) {
if (resultCode == Activity.RESULT_OK) {
finishWithSuccess();
} else {
finishWithError(PluginError.BIOMETRIC_PIN_OR_PATTERN_DISMISSED);
}
}
}

private void onError(int errorCode, @NonNull CharSequence errString) {

switch (errorCode)
{
case BiometricPrompt.ERROR_CANCELED:
finishWithError(PluginError.BIOMETRIC_FINGERPRINT_DISMISSED);
return;
case BiometricPrompt.ERROR_NEGATIVE_BUTTON:
// TODO: remove after fix https://issuetracker.google.com/issues/142740104
if (Build.VERSION.SDK_INT > Build.VERSION_CODES.P && mPromptInfo.isDeviceCredentialAllowed()) {
showAuthenticationScreen();
return;
}
finishWithError(PluginError.BIOMETRIC_FINGERPRINT_DISMISSED);
break;
case BiometricPrompt.ERROR_LOCKOUT:
finishWithError(PluginError.BIOMETRIC_LOCKED_OUT.getValue(), errString.toString());
break;
case BiometricPrompt.ERROR_LOCKOUT_PERMANENT:
finishWithError(PluginError.BIOMETRIC_LOCKED_OUT_PERMANENT.getValue(), errString.toString());
break;
default:
finishWithError(errorCode, errString.toString());
}
}

private void finishWithSuccess() {
setResult(RESULT_OK);
finish();
}

private void finishWithError(PluginError error) {
finishWithError(error.getValue(), error.getMessage());
}

private void finishWithError(int code, String message) {
Intent data = new Intent();
data.putExtra("code", code);
data.putExtra("message", message);
setResult(RESULT_CANCELED, data);
finish();
}
}
Loading

0 comments on commit 7e5ff42

Please sign in to comment.