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

View file

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