Last updated: 2026-10-29
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:
Intent.com.wasp.cardash_launcher. Display name: CarDash.| 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. |
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.runApp, so there is no dashboard flash on a
locked cold start.| # | 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 |
flutter analyze clean.STREAM_MUSIC while the dashboard is foreground).adb shell wm size 1024x600).docs/screenshots/; README/AGENTS/plan updated.ContentObserver would remove
the polling. No global play/pause is in scope.QUERY_ALL_PACKAGES is required for a launcher app list. It is documented
and acceptable for sideloading; a Play distribution needs policy work.swiftshader_indirect.