Restore Android Auto (Play-approved IOT shape) + POTA/ROTA status rows - #729
Restore Android Auto (Play-approved IOT shape) + POTA/ROTA status rows#729patrickrb wants to merge 4 commits into
Conversation
… removal) Production release 2.0 (versionCode 1327, built from staging at 4aca0dc) shipped with Android Auto enabled and cleared Play production review on Aug 5, 2026. The later NAVIGATION-category map variant (PRs #456/#465) is what Play rejected ("does not load map and user location"), forcing the blanket removal in PR #600. Now that we know the IOT-category template version passes review, bring exactly that shape back: - Re-add the manifest wiring removed in #600: automotive_app_desc descriptor, minCarApiLevel 1, and FT8AFCarAppService exported under the IOT category — byte-for-byte the wiring of the approved release. - Revert QsoStatusScreen, RecentDecodesScreen, and CarQsoStatus to their release-commit versions: read-only PaneTemplate QSO status + ListTemplate recent decodes, no surface rendering. - Delete the rejected map-era code (CarMapProjection, CarMapSurfaceRenderer, CarPanelLayout, CarSurfaceState) and its tests. - Flip CarAppManifestWiringTest from asserting AA-unwired back to asserting AA-wired, and add guards pinning the approved shape: IOT category only (no NAVIGATION/POI) and no androidx.car.app template permissions, so the rejected configuration can't silently return. Debug-only AAOS scaffolding (CarAppActivity overlay, DebugInjectReceiver) is untouched and unaffected. Verified: full testDebugUnitTest, processReleaseMainManifest (merged release manifest carries the service + both meta-data entries), and assembleDebug all pass. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## dev #729 +/- ##
============================================
+ Coverage 35.89% 36.19% +0.30%
- Complexity 289 290 +1
============================================
Files 248 244 -4
Lines 30512 30156 -356
Branches 4031 3954 -77
============================================
- Hits 10952 10916 -36
+ Misses 19208 18889 -319
+ Partials 352 351 -1
Flags with carried forward coverage won't be shown. Click here to find out more.
🚀 New features to boost your workflow:
|
Adds two conditional rows to the Android Auto QSO status pane, still inside the Play-approved IOT/PaneTemplate shape: - "POTA K-1234 · 3 QSOs" while a park activation is running (resurrects the buildCarPotaLine helper from the map-era branch; the car_pota_line string was still in-tree). - "ROTA Route 66 · 12 QSOs · 45.3 mi" while a road trip is running. QSO count is sent+pending so contacts logged out of coverage still show; miles match the trip notification's one-decimal format. Row limits: hosts cap pane rows (3 on car API < 2), so rows now carry priorities and selectCarPaneRows() keeps the most important ones — on a 3-row host an active activation replaces the band line instead of being silently dropped. Freshness fix: pota_activation.qso_count was only re-read into PotaSessionManager's StateFlow when the phone's POTA screen called refreshCounter(), so the car row would have shown a stale count while driving. DatabaseOpr now calls PotaSessionManager.onQsoLogged() right after its SQL bump (mirroring the existing RotaTripManager.onQsoLogged hook), and the bump predicate is extracted as qsoCountsForActivation() so it provably matches the SQL's `park_ref = ? AND ended_at IS NULL` binding. ROTA state was already live (RotaTripManager updates its flow on every QSO/fix). Tests: buildCarPotaLine / buildCarRotaLine formatting and hide-when-idle, selectCarPaneRows priority/tie/limit behavior, onQsoLogged idle no-op, and qsoCountsForActivation vs the DB predicate. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…the park Two debug-harness additions so the new Android Auto POTA/ROTA rows can be exercised on an emulator with no radio, server, or GPS: - `--es rota "Route 66"` starts a genuine offline trip via RotaTripManager.startTrip (pendingCreate — the deferred-create path needs no API key or network), so the car pane's ROTA row, the notification, and the phone's ROTA screen all render real state. Demo QSOs inserted by the same broadcast queue into the trip through the normal onQsoLogged path. - Demo QSOs are now stamped with the active POTA park via the app's real stampQso helper, so they bump the activation counter (DB + StateFlow) exactly like on-air contacts and the car's POTA row shows a live count. Trip names stay free-text (no uppercasing); parse coverage added. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Restores the previously Play-approved Android Auto (IOT-category) manifest wiring and read-only car screens, and adds live POTA/ROTA status rows to the car QSO status pane while removing the previously rejected NAVIGATION-category surface/map implementation.
Changes:
- Re-add Android Auto descriptor +
CarAppServicewiring (IOT category, minCarApiLevel=1) and update manifest guard tests to pin the approved shape. - Revert car UI back to
PaneTemplate/ListTemplateand delete the NAVIGATION map/surface renderer implementation and its unit tests. - Add POTA/ROTA activation rows with row-priority selection, plus a
DatabaseOpr → PotaSessionManager.onQsoLogged()hook to keep the in-memory activation counter fresh.
Reviewed changes
Copilot reviewed 19 out of 19 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| ft8af/app/src/main/AndroidManifest.xml | Restores Android Auto wiring: descriptor meta-data + exported IOT FT8AFCarAppService. |
| ft8af/app/src/main/res/xml/automotive_app_desc.xml | Adds the Android Auto host descriptor XML referenced from the manifest. |
| ft8af/app/src/main/res/values/strings_compose.xml | Adds the car_rota_line string for the ROTA status row. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/QsoStatusScreen.kt | Removes surface/NAVIGATION rendering path; builds a pane with optional POTA/ROTA rows and row-limit prioritization. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarQsoStatus.kt | Adds row-priority selection helper and ROTA line formatter. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/pota/PotaSessionManager.kt | Adds onQsoLogged + extracted bump predicate to keep in-memory activation counter aligned with DB bumps. |
| ft8af/app/src/main/java/com/k1af/ft8af/database/DatabaseOpr.java | Calls PotaSessionManager.onQsoLogged() immediately after bumping pota_activation.qso_count. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/map/WorldOutlines.kt | Updates documentation comment to remove references to deleted car map renderer code paths. |
| ft8af/app/src/debug/kotlin/radio/ks3ckc/ft8af/car/DebugInject.kt | Extends debug injection to start an offline ROTA trip and to stamp POTA fields via the real helper. |
| ft8af/app/src/testDebug/kotlin/radio/ks3ckc/ft8af/car/DebugInjectTest.kt | Adds parsing coverage for the new rota debug extra. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/pota/PotaSessionManagerTest.kt | Adds tests for onQsoLogged (idle no-op) and qsoCountsForActivation predicate equivalence. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarQsoStatusTest.kt | Adds tests for ROTA line formatting and pane-row selection/prioritization. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarAppManifestWiringTest.kt | Flips guard back to asserting Android Auto wiring is present and pins IOT/no-template-permissions shape. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarPanelLayout.kt | Removes NAVIGATION surface banner layout helpers (map-era code). |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarMapSurfaceRenderer.kt | Removes NAVIGATION surface renderer implementation (map-era code). |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarSurfaceState.kt | Removes surface-render snapshot model types (map-era code). |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarMapProjection.kt | Removes surface projection/zoom math (map-era code). |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarPanelLayoutTest.kt | Removes tests for deleted banner layout math. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarMapProjectionTest.kt | Removes tests for deleted map projection math. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- PotaSessionManager.onQsoLogged: add @synchronized so its read-modify-write of _currentActivation can't race end() (which is @synchronized) and resurrect an ended activation or bump the count after it ended. - CarAppManifestWiringTest: assert metaData is non-null before reading keys, so a dropped meta-data block fails with an actionable message not an NPE. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Why
Production release 2.0 (versionCode 1327) — built from
stagingat 4aca0dc — shipped with Android Auto enabled and cleared Play production review (full rollout Aug 5, 2026). The rejection that forced PR #600's blanket removal was against the later NAVIGATION-category map variant (PRs #456/#465), not this one. This restores the approved shape, then adds POTA/ROTA status rows on top — staying strictly inside IOT-category template limits.Commit 1 — restore the approved configuration
automotive_app_descdescriptor,minCarApiLevel 1, andFT8AFCarAppServiceexported under the IOT category (byte-for-byte the approved release's wiring). IOT is not subject to the while-driving lockout.QsoStatusScreen,RecentDecodesScreen, andCarQsoStatusto their release-commit versions — read-only PaneTemplate QSO status + ListTemplate recent decodes.CarMapProjection,CarMapSurfaceRenderer,CarPanelLayout,CarSurfaceState, and their tests.CarAppManifestWiringTestback to asserting AA is wired, plus guards pinning the approved shape — IOT only (no NAVIGATION/POI category) and noandroidx.car.apptemplate permissions.Commit 2 — POTA + ROTA rows when active
selectCarPaneRows()keeps the most important — on a 3-row host an active activation replaces the band line instead of being silently dropped.pota_activation.qso_countwas only re-read when the phone's POTA screen was open, so the car would have shown a stale count while driving.DatabaseOprnow callsPotaSessionManager.onQsoLogged()beside the existingRotaTripManager.onQsoLoggedhook; the bump predicate is extracted (qsoCountsForActivation) so it provably matches the SQL. ROTA state was already live.Verification
testDebugUnitTest(full suite, incl. new POTA/ROTA line, row-priority, and count-bump tests) ✅processReleaseMainManifest— merged release manifest carries the service + both meta-data entries ✅assembleDebug✅🤖 Generated with Claude Code