Add Android Auto read-only QSO status display#431
Merged
Conversation
A CarAppService (IOT category) projects the running FT8 sequence onto the car head unit: headline (Calling CQ / QSOing with X / Waiting for X), current TX message, sequence step, TX/RX slot countdown, band/freq/mode, plus a Recent Decodes list screen. Read-only by design — no radio control from the car. The screens observe the existing MainViewModel/FT8TransmitSignal LiveData in-process via a new nullable MainViewModel.peekInstance(); the car UI never boots the engine, showing "Open FT8AF on your phone" until the phone activity has created the singleton. All display decisions live in pure mappers (buildCarQsoStatus, buildCarDecodeRows) with plain-JVM unit tests; a Robolectric test pins the manifest wiring the AA host discovers us by. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014B1egpdNWafvAksJCn1tMA
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #431 +/- ##
============================================
+ Coverage 21.47% 21.57% +0.09%
- Complexity 133 140 +7
============================================
Files 150 154 +4
Lines 19755 19945 +190
Branches 2909 2947 +38
============================================
+ Hits 4243 4303 +60
- Misses 15344 15474 +130
Partials 168 168
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
There was a problem hiding this comment.
Pull request overview
Adds Android Auto (phone projection) support by introducing a read-only car UI that mirrors the live FT8 QSO state (status pane + recent decodes list), plus manifest/resources and tests to ensure the app is discoverable by Android Auto hosts.
Changes:
- Introduces
CarAppService/Sessionand two AA screens (QsoStatusScreen,RecentDecodesScreen) backed by pure mapping helpers (CarQsoStatus.kt). - Wires Android Auto discovery via manifest meta-data and
automotive_app_desc.xml, and adds new UI strings for car templates. - Adds JVM and Robolectric tests to pin mapper logic and manifest wiring.
Reviewed changes
Copilot reviewed 11 out of 11 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/FT8AFCarAppService.kt | Adds the Android Auto entry service and host validation. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/QsoStatusScreen.kt | Main AA status pane screen observing engine LiveData and rendering a PaneTemplate. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/RecentDecodesScreen.kt | AA “Recent decodes” list screen rendering decoded messages in a ListTemplate. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarQsoStatus.kt | Pure mappers for headline/rows/labels + decode row mapping and tick guard. |
| ft8af/app/src/main/java/com/k1af/ft8af/MainViewModel.java | Adds peekInstance() to allow AA UI to observe without booting the engine. |
| ft8af/app/src/main/AndroidManifest.xml | Declares CarAppService + required Android Auto meta-data. |
| ft8af/app/src/main/res/xml/automotive_app_desc.xml | Declares template-based AA support for host discovery. |
| ft8af/app/src/main/res/values/strings_compose.xml | Adds AA screen strings (title, messages, row labels). |
| ft8af/app/build.gradle | Adds androidx.car.app:app:1.4.0 dependency. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarQsoStatusTest.kt | Plain-JVM tests for mapper/formatting/tick guard. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarAppManifestWiringTest.kt | Robolectric test ensuring service + meta-data wiring is present. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
- RecentDecodesScreen: attach the mutableFt8MessageList observer lazily from onGetTemplate instead of init, so a screen rendered before the engine singleton exists still hooks the list on a later render. - Drop the redundant toList() and the false "same mutated ArrayList" comment — publishFt8MessageList() already posts a defensive copy that is never mutated after posting. - Fix KDoc SNR examples to the ASCII hyphen the formatter actually emits. - Note why hosts_allowlist_sample is intentional for release builds (the library-maintained official-host list, per the Android for Cars docs). Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014B1egpdNWafvAksJCn1tMA
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Implements #209 (read-only first pass).
Adds Android Auto (phone projection) support: a read-only status display for the running FT8 QSO sequence on the car head unit.
QsoStatusScreen, PaneTemplate): headline (Calling CQ / QSOing with W1XYZ / Waiting for W1XYZ / Monitoring — TX off, with target SNR), the message currently being transmitted, sequence step (Step RR73 (4/6)), TX/RX slot countdown, and band · frequency · mode.RecentDecodesScreen, ListTemplate): most recent decoded messages, newest first, with UTC time and SNR. Reached from the action strip; rows are not clickable.How it works
MutableLiveDataon the process-scopedMainViewModel/FT8TransmitSignalsingletons (kept alive in the background byRxForegroundService), so theCarAppServiceruns in the same process and observes it directly — no IPC, no engine changes.MainViewModel.peekInstance(): the car UI never boots the engine. UntilComposeMainActivityhas created the singleton, the car shows "Open FT8AF on your phone" and re-checks on its 1 Hz tick.buildCarQsoStatus,buildCarDecodeRows,txFunctionLabel,carBandLine, …) inCarQsoStatus.kt; the Screens only observe and render. ReusesslotTimerState,formatMhz, and the localizedqsopanel_*headline strings.invalidate()is an unquoted refresh on AA hosts, and the tick only fires when the visible second changes (shouldInvalidateForTick).androidx.car.app.category.IOT(status-style app; not nav/media/messaging).minCarApiLevel1;ConstraintManagerrow limits used when the host supports them (API ≥ 2).Testing
CarQsoStatusTest(plain JVM): headline selection incl. no-target/"CQ" rule, TX message gating, seq-step labels 1–6 + fallback, slot TX/RX parity, band line formatting, decode rows ordering/truncation/SNR, tick guard, UTC secondary line.CarAppManifestWiringTest(Robolectric): CarAppService declared+exported with the IOT category;automotive_app_desc+minCarApiLevelmeta-data present — a dropped entry only manifests as "app missing from the car launcher", which nothing else catches.peekInstance()is deliberately not unit-tested in isolation: the process-lifetime static would leak across tests in the same JVM (order-dependent flakes); its null branch is exercised by the Screens' open-phone template.testDebugUnitTestandassembleDebugpass. detekt/ktlint report no findings in the new files (existing findings are pre-baseline / unformatted legacy code; CI runs both warn-only).Trying it without a car
Desktop Head Unit: install "Android Auto Desktop Head Unit Emulator" from SDK Manager, enable AA developer mode + Unknown sources on the phone (required for sideloaded car apps),
adb forward tcp:5277 tcp:5277, rundesktop-head-unit.exe. Launch FT8AF on the phone to start the engine; the car screen goes live and keeps updating while the phone app is backgrounded.Play-distribution note: shipping this on Play later requires opting into the Android Auto form in Play Console + car-quality review for IOT apps. Sideloaded builds work now with the developer setting above.
🤖 Generated with Claude Code
https://claude.ai/code/session_014B1egpdNWafvAksJCn1tMA