IMPLEMENTATION_PLAN.md 11 KB

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).
  • Up to 16 home buttons: Navigation, Music, Radio, Settings, All apps, plus apps pinned from All Apps.
  • Navigation/Music/Radio are app slots with show/hide switches. They can be assigned, changed and cleared. Settings and All apps are always present.
  • Pinned apps are added by long-pressing an app in All Apps and removed by long-pressing the added button on Home. Settings and All apps are always last. User-installed apps show their own icon; system/unassigned slots keep generic.
  • The grid adapts from 2 to 6 columns and shrinks its tiles as the count grows.
  • Every external app opens full-screen through a normal Android Intent.
  • Settings: light/dark/automatic theme, six accent colors, battery visibility, fixed night window, home-button switches, slot assignment, HOME-role setup, four-digit PIN.
  • The Music tile shows the selected app icon with an animated equalizer while media audio is active.
  • The long-press hint fades away two minutes after app start.
  • PIN is requested only on a cold start, never on resume or screen-off.
  • The screen stays awake while CarDash is the foreground window.
  • 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 + up to 16 buttons Matches the refined brief; tiles scale from 2 to 6 columns.
App slots Navigation, Music, Radio with visibility switches Kept from the original brief; Settings and All apps are fixed.
Pinned apps All Apps long-press adds, Home long-press removes Makes any installed app reachable from Home without editing a separate layout screen.
Home cap 16 buttons total, including Settings and All apps Keeps the single page legible at tablet resolutions; enforced in LauncherController.
Icons User-installed apps use their own icon; system/unassigned slots stay generic Identification without losing the calm fixed-button language.
Accent Six curated choices, persisted in Settings Changes the whole theme without a color picker or arbitrary contrast failures.
Battery visibility One switch hides level and charging bolt One control for both indicators, as requested.
Media feedback Music tile shows the selected app icon + animated bars while media is active Compact visual feedback without adding a media control surface.
Hint lifetime Two minutes from process start, then fade out Avoids permanent onboarding chrome; survives widget rebuilds via AppClock.
Screen FLAG_KEEP_SCREEN_ON while foreground The dashboard is the car display; no wake-lock permission needed.
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, pinned apps, 16-button cap, default-home state
    SystemController    -> battery/Wi-Fi/volume/media polling
  AllAppsScreen / AppPickerSheet
  SettingsScreen -> General / Security
  PinSetupScreen / LockScreen -> LockController -> PinService
Android (Kotlin)
  MainActivity -> keep-screen-on, volume keys
               -> LauncherBridge (packages, icons, system flag, role)
               -> SystemBridge (battery, Wi-Fi, volume, media activity)
  • SettingsRepository is the only persistence path for theme, night window, slot visibility/assignments and pinned apps. 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
M8 Home-button visibility switches, All Apps pinning, 16-button adaptive grid, keep-awake Done
M9 Accent colors, battery toggle, fading hint, user icons, Media equalizer, install rule Done

5. Verification checklist

  • flutter analyze clean.
  • Unit/widget tests pass (21 tests: PIN, repository, theme/accent, battery visibility, slot visibility, pinned apps, cap, dense grid, equalizer).
  • Debug APK builds with JDK 21.
  • Installs on API 35 1280×800 tablet.
  • HOME role granted; Home opens CarDash.
  • Immersive full-screen; no Android bars.
  • Real app list and icons in All Apps.
  • App picker assign / long-press change / clear, with persistence across restart.
  • Launch Navigation/Music/Radio full-screen and return Home (verified with Maps and YouTube Music).
  • Volume slider, mute and hardware-key synchronization (keys are routed to STREAM_MUSIC while the dashboard is foreground).
  • Light theme, dark theme and automatic switch.
  • PIN set/change/remove; cold start shows lock; wrong PIN; no re-lock after returning from an app.
  • Verify 1024×600 compact layout (adb shell wm size 1024x600).
  • Boot and verify on Android 10 (API 29) AVD, including PIN and release APK.
  • Release APK on both AVDs (54 MB universal APK).
  • Navigation/Music/Radio switches hide/show buttons, persist, and preserve assignments.
  • All Apps long-press pins apps; the 16-button cap rejects a 17th button.
  • Long-press on an added app removes it; it can be re-added from All Apps.
  • 16 buttons fit at 1280×800 and 1024×600; the grid uses 2–6 columns.
  • FLAG_KEEP_SCREEN_ON is present on the dashboard window.
  • Six accent choices change the Material theme immediately and persist.
  • Battery switch hides both the battery level and charging bolt.
  • Settings/All apps are the last two Home buttons.
  • A user-installed app (F-Droid) shows its own icon; system apps stay generic.
  • Music equalizer widget animates; native media-active polling is wired.
  • Home hint is gone after two minutes from process start.
  • All Apps search icon is visibly smaller.
  • Release 0.3.0 installed on the emulator and physical Android 17 tablet.
  • 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: headless emulators can be killed by the host; scripts use managed boot and the host GPU. SwiftShader is only a fallback.
  5. Flutter 3.47 / AGP 9.1 / JDK 21: works on this machine; Java 27 is not the validated toolchain. The emulator uses the host GPU; SwiftShader segfaulted on the API 35 image, so the helper script defaults to -gpu host.
  6. 16-button density: small labels and generic system-app icons are the trade-off for a single page. The Settings count and grid scaling make the limit explicit.
  7. Screen-on battery use: the flag applies only while the dashboard is foreground; it is not a background wake lock.
  8. Media attribution: the equalizer follows AudioManager.isMusicActive, not a specific package. Exact attribution would require notification access.
  9. 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.
  • 2026-10-29: Added home-button visibility switches, All Apps long-press pinning, a 16-button cap with an adaptive 2–6 column grid, pinned-app removal, and a foreground keep-screen-on flag. Verified 17 tests, 16-button layouts at 1280×800 and 1024×600, cap/removal/re-add, and 0.2.0 on the physical tablet.
  • 2026-10-29: Added six accent choices, battery/charging visibility, a two-minute fading hint anchored to process start, Settings/All apps last, user-app icons, a media-active equalizer, and a smaller All Apps search icon. Added the two-attempt ADB install rule. Verified 21 tests, accent/battery toggles, a user-app icon (F-Droid), hint expiry, and 0.3.0 on the emulator/tablet.