3.2 KiB
Lock Screen
LockActivity is shown whenever the app is locked — on cold start (when credentials exist), after the autolock timer fires, or when the user taps the lock icon in the toolbar.
Authentication Methods
The app attempts authentication in priority order:
- Biometrics — if enrolled and enabled,
BiometricPromptis presented automatically on open - PIN — numeric keypad
- Pattern —
PatternViewgrid
The user can switch between biometric and PIN/pattern manually.
Biometric Authentication
Uses Android BiometricPrompt with BIOMETRIC_WEAK (fingerprint or face depending on device). A successful biometric result sets app.isUnlocked = true and calls MainActivity to route to HomeActivity.
On biometric failure or cancellation the screen falls back to PIN/pattern entry.
PIN Entry
- A custom on-screen numeric keypad (0–9 + backspace + confirm)
- The entered digits are shown as filled/unfilled circles (no digit echo)
- Confirm fires verification immediately when the correct number of digits is entered
Pattern Entry
- The same
PatternViewwidget used in onboarding, in verify-only mode - The drawn pattern is hashed and compared against the stored derived key
Verification
The entered PIN or pattern is run through PBKDF2-HMAC-SHA256 with the stored salt and compared to the stored hash. On match:
app.isUnlocked = trueLockActivityfinishesMainActivityroutes toHomeActivity
On mismatch the attempt counter increments and an error shake animation plays.
Brute-Force Protection
Constants live in LockActivity.kt:44-45: MAX_ATTEMPTS = 5, LOCKOUT_MS = 30_000L.
| Threshold | Behaviour |
|---|---|
| 1–4 wrong attempts | Error label shows remaining attempts |
| 5 wrong attempts | 30-second lockout; further entries are rejected by checkAndShowLockout() until LOCKOUT_MS has elapsed since the last fail |
| After 30 s | Lockout expires (purely time-based, via last_fail_time) — the counter itself does not reset until a successful unlock |
The fail counter resets to zero only inside resetFailures() (LockActivity.kt:313-315), which is called from the success paths of biometric, PIN, and pattern entry. A user who repeatedly fails will hit the 30-second wait again on the very first failure after each lockout window expires.
The attempt counter and last-fail timestamp live in a dedicated lock_attempts SharedPreferences file (LockActivity.kt:41) — plain (not encrypted), which is a known limitation documented in the security audit. The app does not wipe credentials after repeated failures.
app.isUnlocked Guard
app.isUnlocked is an in-memory flag that is false on every process start. Even if an attacker bypasses LockActivity via adb, HomeActivity checks this flag and re-fires LockActivity on resume if it is false. This prevents cold-start bypass.
Screenshot Protection
FLAG_SECURE is set on LockActivity's window, preventing screenshots and screen recording. This is always on for the lock screen regardless of the user's global screenshots setting.
← Onboarding Next → Login