# CarDash implementation plan _Last updated: 2026-10-29_ ## 1. What we are building CarDash is a Flutter/Dart Android **home-screen launcher** for a landscape car tablet. It deliberately trades the reference head-unit chrome for maximum compatibility: - One home page. No top bar, no bottom dock, no pages. - Clock/date, battery/charging and Wi-Fi on the page. - A prominent media-volume card (ring, slider, −/+, mute). - Five shortcuts: Navigation, Music, Radio, Settings, All apps. - Navigation/Music/Radio are **app slots**. They can be assigned, changed and cleared. Dashboard icons stay generic. - Every external app opens full-screen through a normal Android `Intent`. - Settings: light/dark/automatic theme, fixed night window, slot assignment, HOME-role setup, four-digit PIN. - PIN is requested **only on a cold start**, never on resume or screen-off. - Landscape-only; tablet-first 1280×800; Android 10 minimum. - Package: `com.wasp.cardash_launcher`. Display name: **CarDash**. ## 2. Decisions and why | Decision | Choice | Rationale | |---|---|---| | Central app content | Launcher-native; apps open full-screen | Android cannot embed another app; overlay chrome was rejected as fragile and app-obstructing. | | UI chrome | None (no bars) | Removes the mismatch between launcher chrome and full-screen apps; cleaner, more compatible. | | Home layout | Single page, info + volume + five shortcuts | Matches the refined brief: one configurable home screen. | | App slots | Navigation, Music, Radio | Kept from the original brief; Settings and All apps are fixed. | | Icons | Generic for dashboard; real icons in pickers/All Apps | Keeps the car interface consistent while making app identification possible. | | Theme | Light / Dark / Automatic with fixed 19:00–07:00 window | No location permission or network; time pickers make the window adjustable. | | PIN | Four digits, salted PBKDF2 hash, cold start only | Matches the explicit instruction; no re-lock while running. | | Min Android | API 29 (Android 10) | Requested minimum; no in-scope API requires newer. | | Target/compile | 36 | Current Flutter toolchain defaults; runs on API 29. | | Orientation | `sensorLandscape` + Dart orientation lock | Car/tablet form factor; portrait is intentionally unsupported. | | AVD | 10.1" WXGA tablet, 1280×800, 160 dpi, API 35 and API 29 | Matches a dashboard tablet and the reference resolution class. | | HOME role | Standard `RoleManager` request + Settings row | A launcher must be chosen as the system home app; never silently forced. | | Overlay/kiosk/root | Out of scope | Rejected for compatibility. | ## 3. Architecture ``` Flutter HomeScreen ClockBlock / StatusCluster / VolumeCard / ShortcutGrid LauncherController -> apps, slots, default-home state SystemController -> battery/Wi-Fi/volume polling AllAppsScreen / AppPickerSheet SettingsScreen -> General / Security PinSetupScreen / LockScreen -> LockController -> PinService Android (Kotlin) MainActivity -> LauncherBridge (apps, launch, role) -> SystemBridge (battery, Wi-Fi, volume) ``` - `SettingsRepository` is the only persistence path for theme, night window and slots. `flutter_secure_storage` holds the salted PIN hash. - Package enumeration and icon rendering happen on a worker thread in Kotlin and are returned as PNG bytes. - Timers for volume/status are stopped when the app leaves the foreground. - The PIN check is awaited before `runApp`, so there is no dashboard flash on a locked cold start. - No INTERNET permission, no weather, no telemetry. ## 4. Milestones | # | Milestone | State | |---|---|---| | M0 | Local git repo, Flutter scaffold, launcher config, package ID, icons, docs | Done | | M1 | x86_64 API 35/API 29 images, 1280×800 landscape tablet AVDs, emulator/install scripts | Done | | M2 | Theme system, single home layout, clock/status, volume card, shortcut grid | Done (initial visual pass) | | M3 | Kotlin bridges: app list/icons/launch, HOME role, volume, battery/Wi-Fi | Done | | M4 | App picker, All Apps, slot persistence, long-press flows, launch errors | Done | | M5 | Settings, theme auto window, PIN setup/change/remove, cold-start lock | Done | | M6 | Interaction testing, light/dark screenshots, layout polish, API 29 verification | Done | | M7 | Release build, final docs, screenshots, last commits | Done | ## 5. Verification checklist - [x] `flutter analyze` clean. - [x] Unit/widget tests pass (PIN, repository, theme, shortcut tile). - [x] Debug APK builds with JDK 21. - [x] Installs on API 35 1280×800 tablet. - [x] HOME role granted; Home opens CarDash. - [x] Immersive full-screen; no Android bars. - [x] Real app list and icons in All Apps. - [x] App picker assign / long-press change / clear, with persistence across restart. - [x] Launch Navigation/Music/Radio full-screen and return Home (verified with Maps and YouTube Music). - [x] Volume slider, mute and hardware-key synchronization (keys are routed to `STREAM_MUSIC` while the dashboard is foreground). - [x] Light theme, dark theme and automatic switch. - [x] PIN set/change/remove; cold start shows lock; wrong PIN; no re-lock after returning from an app. - [x] Verify 1024×600 compact layout (`adb shell wm size 1024x600`). - [x] Boot and verify on Android 10 (API 29) AVD, including PIN and release APK. - [x] Release APK on both AVDs (54 MB universal APK). - [x] Screenshots in `docs/screenshots/`; README/AGENTS/plan updated. ## 6. Known risks and mitigations 1. **Media-volume polling** is every 900 ms while foreground. It is cheap and handles hardware keys, but a future native `ContentObserver` would remove the polling. No global play/pause is in scope. 2. **`QUERY_ALL_PACKAGES`** is required for a launcher app list. It is documented and acceptable for sideloading; a Play distribution needs policy work. 3. **PIN security scope**: cold-start only by design; it does not replace the Android keyguard or protect against adb/data extraction. README explains it. 4. **Emulator stability**: software-rendered headless emulator can be killed by the host; scripts use managed background boot and `swiftshader_indirect`. 5. **Flutter 3.47 / AGP 9.1 / JDK 21**: works on this machine; Java 27 is not the validated toolchain. 6. **Uninstall/reinstall** may drop the HOME role; Settings and the installer script can restore it. ## 7. Out of scope (for now) - Embedded third-party apps, overlay bars, split screen, kiosk/device-owner. - Global play/pause or now-playing metadata. - Weather, Bluetooth, calls, climate, reverse camera. - An app drawer with folders/pages; a single searchable All Apps page is enough. - Play Store packaging/signing, remote git, CI. ## 8. Change log - 2026-10-29: Pivoted from an overlay/head-unit chrome design to a launcher-native single home page, no top/bottom bars, full-screen external apps. Implemented core UI, Kotlin bridges, settings, PIN and documentation. Verified initial home, app picker, All Apps, volume, themes and cold-start PIN on the API 35 AVD; then verified the release build and PIN flows on the API 29 AVD. Added hardware volume-key routing and PIN verification progress. Screenshots captured at 1280×800 and 1024×600.