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.
We previously stopped/started the biometric prompt every time in
onPause/onResume, but that's apparently not necessary (and discouraged according
to the documentation). This caused issues where the prompt would get stuck on
some devices. While working on this I ran into another issue where AuthActivity
was closed and reopened for no reason after rotation of the device, compounding
the issue. This patch also fixes that.
This patch improves our backup functionality in a number of ways:
- Only backup the vault when important changes are made, not when the order of
entries is changed, for instance.
- Don't bubble up backup errors when saving the vault.
- Instead, show an error bar in the main view if the most recent backup attempt
failed.
<img src="https://alexbakker.me/u/kbhhj2hcgx.png" width="300" />
Clicking on the error bar will take the user to the backup settings.
The main goals of this patch are to:
- Improve the exception handling in Aegis and the way we present errors messages
to the user when they occur.
- Write exception stack traces to the log in more places, so that the ADB logs
we ask for from our users when reporting bugs become more useful.
- Reduce the amount of times we throw a RuntimeException, particularly when an
Android Keystore operation fails.
Achieving the above goals ended up resulting in a very large refactor. The
intro and unlock flow of the app need to be retested entirely.
I noticed a strange crash in the Play Console:
```
android.view.WindowManager$BadTokenException:
at android.view.ViewRootImpl.setView (ViewRootImpl.java:828)
at android.view.WindowManagerGlobal.addView (WindowManagerGlobal.jav>
at android.view.WindowManagerImpl.addView (WindowManagerImpl.java:93)
at android.widget.PopupWindow.invokePopup (PopupWindow.java:1434)
at android.widget.PopupWindow.showAsDropDown (PopupWindow.java:1284)
at android.widget.PopupWindow.showAsDropDown (PopupWindow.java:1240)
at android.widget.PopupWindow.showAsDropDown (PopupWindow.java:1219)
at com.beemdevelopment.aegis.ui.AuthActivity.lambda$showPasswordRemi>
at com.beemdevelopment.aegis.ui.-$$Lambda$AuthActivity$WWHxRKllBPcyH>
at android.os.Handler.handleCallback (Handler.java:873)
at android.os.Handler.dispatchMessage (Handler.java:99)
at android.os.Looper.loop (Looper.java:220)
at android.app.ActivityThread.main (ActivityThread.java:6929)
at java.lang.reflect.Method.invoke (Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (Runt>
at com.android.internal.os.ZygoteInit.main (ZygoteInit.java:870)
```
I can't reproduce this on my device, and we haven't received any reports from
users, but it would be pretty bad if Aegis crashes on some devices when showing
the password reminder popup. This patch is an attempt to fix that (see:
https://stackoverflow.com/a/33809860/12972657).
Instead of showing the reminder after x unlocks, I decided to show the reminder
2 weeks after the vault was last unlocked with the password. Let me know if you
agree with that.

We decided on calling the state file the "vault" a while back. This patch makes
the naming consistent across the codebase. I left "DatabaseImporter" classes
alone, because I'm not sure what a better name for those would be.
This patch replaces the usage of the deprecated FingerprintManager API with
BiometricPrompt. This uses the Android X library, so we get the native biometric
prompt on recent versions of Android and a Google-made one on older versions. By
not working with custom prompts for biometric authentication like we do now, we
can be sure that any issues like #70, #81, #237 are not actually our fault.
Here's what it looks like:

As a nice aside, this also adds support for the new facial recognition as an
authentication method on Pixel 4 phones.
This is still a draft, but early feedback is welcome.
Commit afb9e59711 fixed a bug where the password
encode function would add null bytes to the end of the output. Luckily (I
thought), PBKDF2 produces collisions for inputs with trailing null bytes and
thus scrypt does this as well, so we could safely change that function to remove
the null bytes without any impact. Unfortunately, that doesn't hold up if the
password is over 64 bytes in size. So after that change, the KDF started
producing different keys than before for such passwords and thus some users
could no longer unlock their vault.
This patch addresses the issue by using the old password encode function for
passwords over 64 bytes and repairing the affected password slot.