Android Auto: live surface QSO map (zoom, borders, status banners, partner location) - #456
Merged
Conversation
Switch the car screen from PaneTemplate-only to direct Surface rendering via MapWithContentTemplate (car-app API level 5+). The 1 Hz tick now redraws the Canvas directly instead of calling invalidate(), which eliminates the host dimming/flashing on every countdown update. The surface draws a world map (land outlines from WorldOutlines) with decoded-station markers and an operator dot, covered by a 75% black overlay, then status text (headline, TX message, sequence step, slot countdown, band/mode, POTA activation line) and a TX indicator dot. Hosts below API level 5 fall back to the original PaneTemplate path (minCarApiLevel stays at 1 for backward compat). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The POI category added in the previous commit triggers Android Auto's driving restrictions, blocking the entire screen while in motion. The IOT category has no such restriction. MapWithContentTemplate (surface-based rendering) requires POI or Navigation category, so it can't be used with IOT while driving. Remove the surface rendering code and fix dimming differently: the tick now invalidates only at slot boundaries (every 15s for FT8) instead of every second. LiveData observers still trigger immediate refreshes for real state changes. POTA activation line is kept — added as a 4th PaneTemplate row. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Render a 480x240 equirectangular world map as the PaneTemplate hero image. Shows the operator's position (orange dot) and, during an active QSO, a line to the partner station (cyan dot). The bitmap is built with Canvas from WorldOutlines land data — no map templates, no POI category, works while driving. The image is cached by (opGrid, partnerCall, partnerGrid) so onGetTemplate() skips re-rendering when nothing moved. The partner's grid is looked up from the current decoded message list. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…ners Replaces the static QSO map image with a Surface-rendered, full-bleed map on the Android Auto NavigationTemplate (CarMapSurfaceRenderer), drawn directly each 1 Hz tick so countdown updates never trigger a template refresh (no dimming). Map: - Zoom-to-fit framing of the operator and QSO partner (CarMapProjection): world view when idle, zoomed in around the two stations when in a QSO, so the connection is actually legible. Clamped [1, 12x] with padding. - World land + national borders (new res/raw/world_countries.json) + US state borders, layered under markers; US state abbreviations labelled once zoomed in. Status: - Two full-width status banners (CarPanelLayout) — live QSO state (headline + slot) on top, band + POTA on the bottom — flush against the car's system bars (heights read from framework dimens; safe-area fallback), leaving the map centre clear. - The QSO partner's location rides next to the slot timer: US state (via point-in-polygon over us_states.json, UsStateLocator) or DXCC country (from the callsign database), e.g. "RX slot 7 s - Massachusetts" / "- Reunion Island". Testing: - DEBUG-ONLY DebugInject broadcast receiver (src/debug) + app-automotive host so the car map can be exercised on an Automotive OS emulator without a phone/DHU. - Unit tests for the projection, panel/banner geometry, GeoJSON label + region parsing, and point-in-polygon lookup. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
This PR reworks the Android Auto experience from a template-driven status pane to a Surface-rendered, navigation-category live map screen, adding map projection/zoom framing, richer basemap borders/labels, and partner-location resolution (US state via point-in-polygon or DXCC country via callsign DB). It also adds a debug-only injection path to exercise the car map in an AAOS emulator and introduces unit tests for the new geometry/parsing/lookup utilities.
Changes:
- Switch Android Auto to a
NavigationTemplate+SurfaceCallbackrendering path with a 1 Hz direct redraw loop (fallback toPaneTemplateon older hosts). - Add map rendering infrastructure (projection, renderer, panel layout, surface state) plus GeoJSON parsing for country/state borders, labels, and US state point-in-polygon lookup.
- Add debug-only emulator harness (receiver + AAOS host activity) and expand unit test coverage for the new pure components.
Reviewed changes
Copilot reviewed 20 out of 21 changed files in this pull request and generated 8 comments.
Show a summary per file
| File | Description |
|---|---|
| ft8af/app/src/testDebug/kotlin/radio/ks3ckc/ft8af/car/DebugInjectTest.kt | Unit tests for debug-inject extras parsing. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/ui/map/StateLabelsParseTest.kt | Tests for state label parsing/centroid logic. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/ui/map/NamedRegionLookupTest.kt | Tests for point-in-polygon and named-region lookup. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarQsoStatusTest.kt | Adds coverage for POTA line formatting and PSK spot marker mapping. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarPanelLayoutTest.kt | Tests banner geometry for the surface-rendered status bars. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarMapProjectionTest.kt | Tests for world and fit-to-points projection behavior/clamping. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarAppManifestWiringTest.kt | Updates manifest expectation to NAVIGATION category. |
| ft8af/app/src/main/res/values/strings_compose.xml | Adds a POTA line string resource for car UI. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/map/WorldOutlines.kt | Adds country borders loading, state labels parsing, and US state locator utilities. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/pskreporter/WhoHeardMeCache.kt | Introduces a process-wide PSKReporter “who heard me” spot cache. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/QsoStatusScreen.kt | Implements surface-based navigation screen, PSK fetch loop, and frame building. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarSurfaceState.kt | Defines immutable per-frame state snapshot for the renderer. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarQsoStatus.kt | Adds POTA formatting and PSK spot-to-marker mapping helpers. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarPanelLayout.kt | Adds pure banner rectangle calculation helpers. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarMapSurfaceRenderer.kt | New Surface renderer drawing basemap, borders, labels, markers, and banners. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarMapProjection.kt | New pure projection math for world and fit-to-points views. |
| ft8af/app/src/main/AndroidManifest.xml | Adds car surface permissions and switches car app category to NAVIGATION. |
| ft8af/app/src/debug/kotlin/radio/ks3ckc/ft8af/car/DebugInject.kt | Debug-only broadcast receiver to inject synthetic car-map engine state. |
| ft8af/app/src/debug/AndroidManifest.xml | Debug manifest overlay registering injection receiver and AAOS host activity. |
| ft8af/app/build.gradle | Bumps androidx.car.app dependency and adds debug-only app-automotive. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Fixes eight review findings on the Android Auto surface map path: - Guard checkIsCQ() against a null callsignTo: it dereferences callsignTo unconditionally, so a decode with a null To field would crash the 1 Hz surface tick. buildStationMarkers now gates the call. - Dedupe station markers by the normalized getCallsignFrom() (strips the < > a hashed decode carries) instead of the raw callsignFrom field, so a hashed decode no longer produces a duplicate marker. - Match the current QSO partner on getCallsignFrom() too, so a hashed partner decode still renders its line/location. - Cache the empty fallback when a geo asset fails to load, so a missing/corrupt asset does not re-throw the parse on every frame. - Localize the POTA line: buildCarPotaLine now returns a CarStringSpec resolved against the (previously unused) @string/car_pota_line. - Correct stale KDoc/comments that still referenced MapWithContentTemplate and host-rendered status cards; the screen uses NavigationTemplate and draws the status banners on the surface itself. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_014B1egpdNWafvAksJCn1tMA
This was referenced Jul 7, 2026
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.
Reworks the Android Auto car screen into a live, Surface-rendered QSO map. Supersedes the earlier static-image approach on this branch.
What it does
CarMapSurfaceRenderer) on aNavigationTemplate, drawn each 1 Hz tick directly to theSurface— countdown updates never trigger a template rebuild, so the display no longer dims/flashes. Category is NAVIGATION so the map stays up while driving.CarMapProjection): world view when idle; zooms and re-centres around the operator + QSO partner when in a QSO so the connection is legible. Clamped[1, 12x]with padding.res/raw/world_countries.json) + US state borders, layered under the markers; US state abbreviations label in once zoomed.CarPanelLayout): live QSO state (headline + slot timer) on top, band + POTA on the bottom, flush against the car's system bars (heights from framework dimens, safe-area fallback), leaving the map centre clear.us_states.json,UsStateLocator) when the partner is stateside, otherwise DXCC country (from the callsign database), e.g.RX slot · 7 s · Massachusetts/· Reunion Island.Testing
DebugInjectbroadcast receiver +app-automotivehost so the car map can be exercised on an Automotive OS emulator without a phone/DHU. Never ships in release.testDebugUnitTestpasses.🤖 Generated with Claude Code