First commit, imported from the working folder: Android TV app, loopback guide server, design sources and per-release verification notes. Includes the 0.16 tuning screen, built and tested but not yet confirmed on the box. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
4.3 KiB
Orbit TV 0.14.0 — remembered connection and setup
Scope approved: remember sign-in and saved channel choices, before building out the standard 101 Orbit One / 102 Orbit After Dark / 103 classic-action-animation lineup. Custom user channel presets, recommendation/availability ticks, full indexing/refresh, original multi-channel grid, seasonal rules and adverts remain future increments. Channel 102 is not added here.
The app now stores an access token, provider-scoped user ID and consistent generated device ID, the existing bounded sample metadata, shortlist results/progress, approved versions, episode pages, built 101/103 lineups/source IDs/runtimes and selected guide channel. Password and username text fields are never persisted. A new sign-in is needed once after installing this first persistence build because earlier versions saved nothing.
Storage is AES-256/GCM with fresh provider-generated 96-bit IV per write, 128-bit authentication tag, fixed schema-specific AAD and an AndroidKeyStore key. Only ciphertext is written with AtomicFile in app-private noBackupFilesDir; allowBackup=false remains. No plaintext fallback, additional dependency/device permission or external storage. Schema/origin/IDs/counts/text lengths and channel bounds are validated. Saved plaintext is capped at 512 KiB; decrypted state stays in memory. No hardware-backed-key guarantee is made: actual KeyStore support and reopen behavior require the Xiaomi test.
Writes serialize through a process-wide store, with generation tickets invalidated before Disconnect/new-connection cleanup to prevent an older in-flight save rewriting forgotten state. Disconnect removes the file and key, clears visible choices and attempts normal provider logout. Clear failures produce a Settings/app-data instruction instead of claiming success. Connected UI shows Setup saved on this device after a successful write. Saves are briefly debounced; wait for confirmation before force-stopping or cutting power.
On a fresh launch the app decrypts the saved record and validates its token with GET /Users/{savedId} using the same saved generated DeviceId. It checks the returned user identity before exposing/restoring private setup. No password authentication, full scan, fresh sample import or schedule rebuild occurs during successful restore. Restoring saved source runtimes/lineup order preserves the existing UTC schedule. Source availability/runtime is still rechecked through normal tuning. Network errors retain the saved record and offer Retry saved connection. 401/403 removes the active saved token and asks for sign-in; matching-account sign-in can restore choices. Different-account sign-in cannot apply prior choices. Corrupt ciphertext/unavailable key fails closed, never reads it as plaintext, and requests sign-in.
Home/background stops playback and sends a normal stop report while retaining login/setup. The player progress loop checks foreground state. Owner disposal detaches local session state without revoking the saved provider token. This is remembered-token login, not a promise that provider tokens never expire. A token expiring during a live session still produces the existing sign-in-again error; return to Connect Emby to authenticate. Refreshing catalogue changes is not added in this increment.
Validation: final cached/offline assembleDebug, testDebugUnitTest and lintDebug passed; 79 tests, zero failures/errors. New fake-fixture tests cover encryption round trip and preserved timeline, distinct nonces, tampering/wrong keys, schema/origin/identity/approval bounds, oversized records, token removal with retained choices, validation-only resume with restored episode allowlisting, expired login with no password/logout request, cross-account rejection and stop-without-logout detach. Signature verified. Reviewed at-rest handling, fixed-origin/user binding, generation/forget races, background playback and request limits. No actual credentials/private catalogue/video or device app data/logs were read by tools. Platform Keystore/AtomicFile operations and TV lifecycle/UI are not instrumented tests; actual restoration, Disconnect and process-restart need the hardware test after installation. No VPS/firewall/service changes.
Primary references: https://developer.android.com/privacy-and-security/keystore https://dev.emby.media/reference/RestAPI/UserService/getUsersById.html