Skip to content

Restore Android Auto (Play-approved IOT shape) + POTA/ROTA status rows - #729

Open
patrickrb wants to merge 4 commits into
devfrom
feat/restore-android-auto
Open

Restore Android Auto (Play-approved IOT shape) + POTA/ROTA status rows#729
patrickrb wants to merge 4 commits into
devfrom
feat/restore-android-auto

Conversation

@patrickrb

@patrickrb patrickrb commented Aug 7, 2026

Copy link
Copy Markdown
Owner

Why

Production release 2.0 (versionCode 1327) — built from staging at 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

  • Manifest: re-add the wiring removed in Remove Android Auto support to clear Play production rejection #600automotive_app_desc descriptor, minCarApiLevel 1, and FT8AFCarAppService exported under the IOT category (byte-for-byte the approved release's wiring). IOT is not subject to the while-driving lockout.
  • Screens: revert QsoStatusScreen, RecentDecodesScreen, and CarQsoStatus to their release-commit versions — read-only PaneTemplate QSO status + ListTemplate recent decodes.
  • Delete the rejected map-era code: CarMapProjection, CarMapSurfaceRenderer, CarPanelLayout, CarSurfaceState, and their tests.
  • Tests: flip CarAppManifestWiringTest back to asserting AA is wired, plus guards pinning the approved shape — IOT only (no NAVIGATION/POI category) and no androidx.car.app template permissions.

Commit 2 — POTA + ROTA rows when active

  • "POTA K-1234 · 3 QSOs" while a park activation runs; "ROTA Route 66 · 12 QSOs · 45.3 mi" while a road trip runs (QSO count = sent + pending, so out-of-coverage contacts show; miles match the trip notification format). Rows disappear when idle.
  • Row limits: pane rows now carry priorities and selectCarPaneRows() keeps the most important — on a 3-row host an active activation replaces the band line instead of being silently dropped.
  • Live POTA count: pota_activation.qso_count was only re-read when the phone's POTA screen was open, so the car would have shown a stale count while driving. DatabaseOpr now calls PotaSessionManager.onQsoLogged() beside the existing RotaTripManager.onQsoLogged hook; 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
  • Not run on-device: no phone attached during this change.

🤖 Generated with Claude Code

… 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

codecov Bot commented Aug 7, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 30.76923% with 36 lines in your changes missing coverage. Please review.
✅ Project coverage is 36.19%. Comparing base (7052afc) to head (ac88315).

Files with missing lines Patch % Lines
...n/kotlin/radio/ks3ckc/ft8af/car/QsoStatusScreen.kt 0.00% 26 Missing ⚠️
...debug/kotlin/radio/ks3ckc/ft8af/car/DebugInject.kt 22.22% 7 Missing ⚠️
...tlin/radio/ks3ckc/ft8af/pota/PotaSessionManager.kt 25.00% 2 Missing and 1 partial ⚠️
Additional details and impacted files

Impacted file tree graph

@@             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     
Flag Coverage Δ
android 17.79% <30.76%> (+0.14%) ⬆️
native 9.93% <ø> (ø)

Flags with carried forward coverage won't be shown. Click here to find out more.

Files with missing lines Coverage Δ
...main/kotlin/radio/ks3ckc/ft8af/car/CarQsoStatus.kt 96.05% <100.00%> (+1.84%) ⬆️
.../kotlin/radio/ks3ckc/ft8af/ui/map/WorldOutlines.kt 64.63% <ø> (ø)
...tlin/radio/ks3ckc/ft8af/pota/PotaSessionManager.kt 13.63% <25.00%> (+0.73%) ⬆️
...debug/kotlin/radio/ks3ckc/ft8af/car/DebugInject.kt 58.45% <22.22%> (-0.25%) ⬇️
...n/kotlin/radio/ks3ckc/ft8af/car/QsoStatusScreen.kt 0.00% <0.00%> (ø)
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

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>
@patrickrb patrickrb changed the title Restore Android Auto in the Play-approved IOT shape Restore Android Auto (Play-approved IOT shape) + POTA/ROTA status rows Aug 7, 2026
…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>

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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 + CarAppService wiring (IOT category, minCarApiLevel=1) and update manifest guard tests to pin the approved shape.
  • Revert car UI back to PaneTemplate/ListTemplate and 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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants