Compose Multiplatform stringResource requires positional specifiers
(%1$s, %1$d) — plain %s/%d renders literal format tokens.
Boot TTL and Hour TTL fields are now shown for both provision and
unlock, matching the original implementation. Confirm passphrase
field remains provisioning-only.
- Add LockdownCoordinator state machine with auto-replay, lock-now,
and error-resilient passphrase store calls
- Add EncryptedSharedPreferences-backed Android passphrase store
with nullable fallback on crypto init failure
- Add LockdownDialog (provision/unlock/backoff) with byte-length
passphrase validation and string resources
- Add LockdownSessionStatus composable for token info display
- Gate region-unset banner on sessionAuthorized in ConnectionsScreen
- Wire Lock Now button in SecurityConfigScreen
- Add LockdownCoordinatorImplTest covering all state transitions,
auto-replay, lock-now, error paths, and uint32 overflow
- Add FakeLockdownCoordinator and update test fakes
- Delete unused LockdownUnlockDialog.kt
- T027/T028: Auto-disconnect on LockNowAcknowledged state in app shell
- T020/T021: Confirm passphrase field in provision mode with mismatch validation
- T035/T036: LockdownSessionStatus composable showing boots remaining and expiry
- Wire session status and Lock Now button enabled state based on sessionAuthorized
- Expose lockdownTokenInfo and sessionAuthorized from RadioConfigViewModel
- Replace java.text.DateFormat/java.util.Date usage in SecurityConfigScreen
(constitution violation: no java.* in commonMain) with simplified Lock Now button
- Replace material.icons imports with MeshtasticIcons in LockdownUnlockDialog
- Proper token info display to be re-implemented in Phase 5 (T025-T026)
- LockdownUnlockDialog: passphrase entry with boots / hours TTL inputs.
Shows lock_reason on LOCKED, a backoff countdown on UNLOCK_FAILED with
backoff_seconds > 0 (Submit disabled while in backoff), and switches
the title to "Set Passphrase" on NEEDS_PROVISION.
- Main: collect lockdownState/lockdownTokenInfo, show the dialog,
auto-clear on LockNowAcknowledged so the connection drops without
a dialog flash.
- ConnectionsScreen: gate the "must set region" banner on
isLockdownAuthorized so an unauthorized client isn't told to fix a
region it can't see.
- SecurityConfigItemList: "Lock Now" button under Administration,
labelled with the active session token's boots remaining and (if set)
the wall-clock expiry.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
- IMeshService: sendLockdownUnlock(passphrase, bootTtl, hourTtl) and
sendLockNow() AIDL methods.
- MeshService: AIDL stubs forwarding to MeshActionHandler.
- AndroidRadioControllerImpl: forward to meshService over AIDL.
- DirectRadioControllerImpl: forward directly to actionHandler (in-process
non-Android targets).
- FakeIMeshService: test stubs.
- UIViewModel: lockdownState/lockdownTokenInfo flows, sendLockdownUnlock,
sendLockNow, clearLockdownState. Routed through radioController so the
commonMain code does not depend on the AIDL service directly.
- ConnectionsViewModel: expose lockdownState.
- RadioConfigViewModel: lockdownTokenInfo + sendLockNow for the Lock Now
button in security settings.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>