# 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: 1. **Biometrics** — if enrolled and enabled, `BiometricPrompt` is presented automatically on open 2. **PIN** — numeric keypad 3. **Pattern** — `PatternView` grid 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 `PatternView` widget 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: 1. `app.isUnlocked = true` 2. `LockActivity` finishes 3. `MainActivity` routes to `HomeActivity` 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](01-onboarding.md)     **Next →** [Login](03-login.md)