A clean, minimal Android home-screen launcher for car head units — the cheap
aftermarket "Android radio" double-DIN units, not Android Auto.
Kotlin, classic Views, landscape-first, no Google Play Services required,
and it runs all the way back to Android 4.4 (KitKat) so it works on old units too.
Clock, date, current conditions and a three-day forecast on the left; media and phone on the right; quick-launch favourites along the top.
Search, a frequently-used strip, and the full app grid.
| Settings | Colour themes |
|---|---|
![]() |
![]() |
Dashboard
- Large clock and date, current weather, and a 3-day forecast
- Live media widget: album art, title/artist, play-pause, next/previous, and a scrubbable seek bar with elapsed/total times
- Quick-launch dock of 5 favourite apps in the top bar
- Wi-Fi indicator (only shown when connected)
- Six tabs: Audio · Radio · Phone · Nav · Apps · Settings
App drawer
- Live search
- "Frequently used" strip based on your own launch history
- Long-press any app to hide it from the drawer
- Refreshes automatically when apps are installed or removed
Appearance
- 7 colour schemes — Midnight, Ocean, Sunset, Forest, Violet, Crimson, Graphite — each applying a gradient and matching accent across the whole UI
- Light and dark palettes; dark by default, with Auto (by time of day), Light, and Follow-system options
- Runs fullscreen with the system bars hidden, using its own in-app Back/Home navigation on every screen
Setup and settings
- Guided first-run setup: language, default apps, permissions, and a prompt to become the default launcher
- Everything re-configurable later in Settings
- 10 languages: English, Turkish, Spanish, German, French, Italian, Portuguese, Russian, Simplified Chinese, Arabic (with RTL support)
| Min Android | 4.4 KitKat (API 19) sideloaded · 5.0 (API 21) via Play |
| Target Android | 16 (API 36) |
| Orientation | Landscape |
| Google Play Services | Not required |
| API keys | None |
Designed for common head-unit resolutions — 1024×600 and 800×480 both work.
Grab the APK from the latest release and sideload it:
adb install -r dashline-v0.1.4.apkOr copy the APK to a USB stick, plug it into the head unit, and open it with the unit's file manager.
Open the project in Android Studio (Giraffe or newer). It will fetch the right Gradle and SDK versions and generate the Gradle wrapper on first sync.
Then, from the command line:
./gradlew assembleDebug./gradlew installDebugGoogle Play's installer refuses anything below API 21, but many cheap head units still run Android 4.4. The project therefore ships two flavours of the same app:
| Flavour | minSdk | Where it goes |
|---|---|---|
legacy |
19 | The sideloadable APK on GitHub Releases — works on KitKat |
play |
21 | The App Bundle uploaded to the Play Store |
./gradlew assembleLegacyRelease # APK for sideloading
./gradlew bundlePlayRelease # AAB for the Play ConsoleBoth share the same applicationId, so any given device only ever sees one of
them as "the app".
Release builds are minified with R8 and must be signed. Create a key once — choose your own passwords when prompted:
keytool -genkey -v -keystore release.jks -alias release -keyalg RSA -keysize 2048 -validity 10000Copy keystore.properties.example to keystore.properties and fill in your
values, then:
./gradlew assembleReleasekeystore.properties and *.jks are gitignored — never commit them. Losing
the key means you can't publish updates that upgrade an existing install, so back
it up somewhere safe.
Tagging a version builds and publishes a signed APK automatically:
git tag v0.1.4 && git push origin v0.1.4This needs four repository secrets under Settings → Secrets and variables →
Actions: KEYSTORE_BASE64 (base64 -i release.jks), KEYSTORE_PASSWORD,
KEY_ALIAS and KEY_PASSWORD.
After installing, press the unit's Home button and choose this launcher, then select "Always". To reset the default while developing:
adb shell cmd package set-home-activity com.dashline.launcher/.HomeActivityAll optional — the launcher degrades gracefully without them.
| Permission | Used for | Without it |
|---|---|---|
| Location | Local weather | Weather panel hides, clock still works |
| Notification access | Reading now-playing media | Media widget becomes a launch button |
| Query all packages | Listing installed apps | Required for the app drawer |
Notification access can't be granted by a normal permission dialog — Android requires the user to enable it in system settings. Setup links straight there, and you can revisit it at Settings → Media info access.
Weather comes from Open-Meteo, which is free and needs
no API key or account. Location is read through the platform
LocationManager, so no Play Services dependency. It refreshes every 15 minutes,
and you can switch between °C and °F in Settings.
app/src/main/
├── AndroidManifest.xml # HOME intent-filter, notification listener
├── java/com/dashline/launcher/
│ ├── App.kt # applies saved language + theme at startup
│ ├── BaseActivity.kt # locale, fullscreen, gradient, in-app nav
│ ├── HomeActivity.kt # the dashboard
│ ├── AppDrawerActivity.kt # app grid: search, frequent, hide
│ ├── AppPickerActivity.kt # "choose an app for this role"
│ ├── SetupActivity.kt # first-run onboarding
│ ├── SettingsActivity.kt # settings
│ ├── GradientPickerActivity.kt # colour scheme picker
│ ├── GradientThemes.kt # the 7 colour schemes
│ ├── ThemeManager.kt # light / dark / auto
│ ├── LocaleManager.kt # in-app language override
│ ├── MediaMonitor.kt # reads the active MediaSession
│ ├── WeatherRepository.kt # Open-Meteo client
│ ├── AppRepository.kt # query + launch installed apps
│ ├── Prefs.kt # all persisted settings
│ ├── Permissions.kt # runtime permission helpers
│ └── Usage.kt # launch-count tracking
└── res/
├── values/ # strings, light palette, styles
├── values-night/ # dark palette
├── values-v21/ # API 21+ theme attributes
└── values-{ar,de,es,fr,it,pt,ru,tr,zh}/ # translations
Supporting old head units shapes a few decisions worth knowing before you change things:
- Dependencies are pinned to the last KitKat-compatible releases
(appcompat 1.4.2, core-ktx 1.9.0, recyclerview 1.2.1). Bumping to appcompat
1.6+ or core-ktx 1.10+ raises
minSdkto 21 and breaks the build. - Launcher icons ship as PNG mipmaps, because vector and adaptive icons don't
render as app icons before Android 5.0. Adaptive icons in
mipmap-anydpi-v26are used only on API 26+. - API 21+ theme attributes live in
values-v21/so they don't affect KitKat. - Fullscreen uses the legacy
systemUiVisibilityflags rather thanWindowInsetsController, which doesn't exist below API 30. - The language override wraps each activity's context instead of using
AppCompatDelegate.setApplicationLocales, which needs appcompat 1.6+. - The media widget requires Android 5.0+ (
MediaSessionManager). On KitKat it falls back to acting as a launch button.
Screenshots in this README are captured from a real unit. To refresh them after a UI change, connect the head unit (or an emulator) with USB debugging on and run:
./tools/capture-screenshots.shRead the Compatibility notes above before upgrading any dependency — several are pinned deliberately to keep Android 4.4 support.
- Reorderable favourites dock (drag and drop)
- Hourly forecast in the weather panel
- Signed release builds with R8 shrinking
- Optional analog clock face
MIT — see LICENSE.




