:feature:car
Overview
The :feature:car module provides the Android Auto integration built on androidx.car.app. MeshtasticCarAppService is a CarAppService registered in the MESSAGING category (androidx.car.app.category.MESSAGING); each host connection gets a MeshtasticCarSession that wires up state, alerts, and conversation shortcuts.
Target: Android only, google flavor only — the module is added via googleImplementation(projects.feature.car) in :androidApp, and FeatureCarModule is included from the google flavor's FlavorModule.
Templates Gating
Production ships notification-only Android Auto messaging (MessagingStyle notifications + ConversationShortcutManager). The full templated car app is gated:
- Build with
-PenableCarTemplates=trueto enable it (Internal/Closed Play tracks only). - The Gradle property resolves the
carTemplatesEnabledmanifest placeholder — in this module's ownbuild.gradle.kts/AndroidManifest.xml(a library resolves its own placeholders; the app's value does not override it) and again in:androidAppas defense-in-depth. - The decisive host-side gate is
automotive_app_desc's<uses name="template" />; theandroid:enabled="${carTemplatesEnabled}"service flag keeps the templated service unbindable in production.
Key Components
Service layer (service/)
MeshtasticCarAppService—CarAppService; host validation (allowlist in release,ALLOW_ALL_HOSTS_VALIDATORin debug), creates sessions.MeshtasticCarSession— per-connectionSession; startsCarStateCoordinator,EmergencyHandler, andConversationShortcutManager, tags the session in Crashlytics, and returns the firstScreen.CarStateCoordinator— bridges repository flows (nodes, messages, connection state) into car presentation state (MessageSnapshot,NodeUiinmodel/CarUiModels.kt). Created per car session.ConversationShortcutManager— publishes dynamic shortcuts for active DMs/channels so Android Auto surfaces Meshtastic conversations and links notifications to conversations viaLocusIdCompat(the notification/reply plumbing that also serves the notification-only production path).
Screens (screens/)
HomeScreen—TabTemplatedashboard (messages / nodes / status tabs) fed byCarStateCoordinator.NodeDetailScreen—PaneTemplatedetail for one node (signal, battery, last heard) with a message action.
Emergency alerts (alerts/)
EmergencyHandler— observes incomingPortNum.ALERT_APPpackets, maintains the activeEmergencyAlertlist, and triggers audio tones on the car head unit.
Util layer (util/)
MessageFilter— decides which packets are displayable (text, non-blank, not emoji-only) and validates outgoing message byte length.CarScreenDataBuilder— pure functions converting domain models to car UI models; free of Car App Library types so they unit-test without Robolectric.NodeSubtitleFormatter— node subtitle text with signal colouring and responsive variants.PersonIconFactory— circular initial avatars forPersonicons in MessagingStyle notifications and shortcut avatars.CrashlyticsCarTagger— sets thecar_sessionCrashlytics custom key.
Key Dependencies
From feature/car/build.gradle.kts:
core:common,core:data,core:database,core:domain,core:model,core:repositoryandroidx.car.app,androidx.car.app.projected(+androidx.car.app.testingfor tests)koin.android,firebase.crashlytics(via Firebase BoM),kermit
Testing
Screen and flow tests run on the JVM via TestCarContext + mokkery + Robolectric (CarScreensTest) — the Desktop Head Unit cannot drive current Car App API levels. See TESTING.md for the full recipe.