Improve the lifecycle handling of BiometricPrompt some more

This is a different take on what db681273e6 was
trying to accomplish, with the additional benefit that the prompt will now no
longer be shown on auto-lock.
This commit is contained in:
Alexander Bakker 2020-06-23 18:35:46 +02:00
parent c73c29d2ec
commit 68d6c39dd4
2 changed files with 38 additions and 10 deletions

View file

@ -59,6 +59,10 @@ public class AuthActivity extends AegisActivity {
private BiometricSlot _bioSlot;
private BiometricPrompt _bioPrompt;
// the first time this activity is resumed after creation, it's possible to inhibit showing the
// biometric prompt by setting 'inhibitBioPrompt' to false through the intent
private boolean _inhibitBioPrompt;
private Preferences _prefs;
private boolean _stateless;
@ -80,6 +84,7 @@ public class AuthActivity extends AegisActivity {
});
Intent intent = getIntent();
_inhibitBioPrompt = savedInstanceState == null ? !intent.getBooleanExtra("_inhibitBioPrompt", true) : savedInstanceState.getBoolean("_inhibitBioPrompt");
_cancelAction = (CancelAction) intent.getSerializableExtra("cancelAction");
_slots = (SlotList) intent.getSerializableExtra("slots");
_stateless = _slots != null;
@ -145,10 +150,12 @@ public class AuthActivity extends AegisActivity {
biometricsButton.setOnClickListener(v -> {
showBiometricPrompt();
});
}
if (_bioKey != null) {
showBiometricPrompt();
}
@Override
protected void onSaveInstanceState(@NonNull Bundle outState) {
super.onSaveInstanceState(outState);
outState.putBoolean("inhibitBioPrompt", _inhibitBioPrompt);
}
@Override
@ -203,6 +210,22 @@ public class AuthActivity extends AegisActivity {
if (_bioKey == null || _prefs.isPasswordReminderNeeded()) {
focusPasswordField();
}
if (_bioKey != null && _bioPrompt == null && !_inhibitBioPrompt) {
_bioPrompt = showBiometricPrompt();
}
_inhibitBioPrompt = false;
}
@Override
public void onPause() {
if (!isChangingConfigurations() && _bioPrompt != null) {
_bioPrompt.cancelAuthentication();
_bioPrompt = null;
}
super.onPause();
}
@Override
@ -229,25 +252,26 @@ public class AuthActivity extends AegisActivity {
_textPassword.postDelayed(popup::dismiss, 5000);
}
public void showBiometricPrompt() {
public BiometricPrompt showBiometricPrompt() {
Cipher cipher;
try {
cipher = _bioSlot.createDecryptCipher(_bioKey);
} catch (SlotException e) {
e.printStackTrace();
Dialogs.showErrorDialog(this, R.string.biometric_init_error, e);
return;
return null;
}
BiometricPrompt.CryptoObject cryptoObj = new BiometricPrompt.CryptoObject(cipher);
_bioPrompt = new BiometricPrompt(this, new UiThreadExecutor(), new BiometricPromptListener());
BiometricPrompt prompt = new BiometricPrompt(this, new UiThreadExecutor(), new BiometricPromptListener());
BiometricPrompt.PromptInfo info = new BiometricPrompt.PromptInfo.Builder()
.setTitle(getString(R.string.authentication))
.setNegativeButtonText(getString(android.R.string.cancel))
.setConfirmationRequired(false)
.build();
_bioPrompt.authenticate(info, cryptoObj);
prompt.authenticate(info, cryptoObj);
return prompt;
}
private void finish(MasterKey key, boolean isSlotRepaired) {
@ -306,6 +330,8 @@ public class AuthActivity extends AegisActivity {
@Override
public void onAuthenticationError(int errorCode, @NonNull CharSequence errString) {
super.onAuthenticationError(errorCode, errString);
_bioPrompt = null;
if (!BiometricsHelper.isCanceled(errorCode)) {
Toast.makeText(AuthActivity.this, errString, Toast.LENGTH_LONG).show();
}
@ -314,6 +340,7 @@ public class AuthActivity extends AegisActivity {
@Override
public void onAuthenticationSucceeded(@NonNull BiometricPrompt.AuthenticationResult result) {
super.onAuthenticationSucceeded(result);
_bioPrompt = null;
MasterKey key;
BiometricSlot slot = _slots.find(BiometricSlot.class);

View file

@ -486,7 +486,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
}
if (_app.isVaultLocked()) {
startAuthActivity();
startAuthActivity(true);
} else if (_loaded) {
// update the list of groups in the filter menu
if (_menu != null) {
@ -647,9 +647,10 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
}
}
private void startAuthActivity() {
private void startAuthActivity(boolean inhibitBioPrompt) {
Intent intent = new Intent(this, AuthActivity.class);
intent.putExtra("cancelAction", CancelAction.KILL);
intent.putExtra("inhibitBioPrompt", inhibitBioPrompt);
startActivityForResult(intent, CODE_DECRYPT);
}
@ -744,7 +745,7 @@ public class MainActivity extends AegisActivity implements EntryListView.Listene
_loaded = false;
if (isOpen()) {
startAuthActivity();
startAuthActivity(false);
}
super.onLocked();