Conversation
Discard local trip was local-only: it dropped the queue and forgot the trip, but a row already created on roadsontheair.com stayed active forever — the site called the rover live for a day (the heard-from window) and badged the trip active after that, and with the app's local state gone no client could ever complete it. Exactly this stranded K1AF 2026-08-03 in production. abandonTrip now snapshots the trip id and credentials before clearTrip wipes them and fires one best-effort completeTrip. Fire-and-forget is deliberate: the button also serves the broken cases (bad key, deleted trip) where the call fails and the row was unreachable anyway. A trip still pending creation, or an install with no key, skips the doomed attempt — shouldCompleteAbandonedTrip covers the decision. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
A whitespace-only trip id now counts as no id (isNotBlank, matching the key check), and rota_abandon_desc — which was defined but rendered nowhere — is wired up as a caption under the active-trip buttons, since Discard destroying undelivered data deserves saying before the tap. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
… 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>
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>
- 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>
Restore Android Auto (Play-approved IOT shape) + POTA/ROTA status rows
…s on the pane Ports the CarPlay/Android Auto status-dashboard design onto dev's pane path (the surface/map variant was removed in #729). The activation block now shows, via pure helpers in CarQsoStatus.kt: - POTA row with a "N more to validate the activation" / "Activation validated" secondary (POTA_ACTIVATION_TARGET = 10). - ROTA row with a "X.X mi driven this activation" secondary; car_rota_line is split to a 2-arg title + car_rota_miles secondary. - Session-fallback row ("Session · N QSOs" / "Last logged JA1XYZ · 20m · 41 min") when neither POTA nor ROTA is active — the design's "activation rows drop out, session stats take the slot." - Band row gains a "N decodes last cycle" secondary, read from currentMessages (per-cycle overlay, so it drops to 0 on a silent slot) rather than the cross-cycle mutableFt8MessageList. Activation rows keep #729's row-priority selection, so on a tight host they replace the band line instead of being dropped. buildCarActivationRows, potaValidateSpec, buildCarSessionRow, formatMiles, minutesAgo, and carDecodesSecondary are unit-tested in CarDashboardTest (17 cases). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
…a render crash Reworks the pane to the FT8AF Android Auto design doc's "1a" Pane variant (claude.ai/design project): every row now carries a colored circular leading badge and the rows are restructured to the design's shape — - Status row: green dot badge (gray when TX off), "<state> · <countdown>" title, and a "<target> · <SNR> · <TX-queue>" secondary. - Band row: blue "20m" badge, "14.074 MHz · FT8" title, "N decodes last cycle". - POTA row: amber "P" badge, green-count title, "N more to validate" secondary. - ROTA row: amber "R" badge, miles secondary. - Session-fallback row: gray "Σ" badge, "Last logged …" secondary, when idle. Decision/format/color logic is pure (CarQsoStatus.kt) and unit-tested in CarDashboardTest; QsoStatusScreen rasterizes the badges to CarIcons and applies ForegroundCarColorSpan. Crash fix: the Car App Library rejects ForegroundCarColorSpan on a Row *title* (Row.setTitle validates against a no-color constraint and throws IllegalArgumentException, killing the CarAppService process the moment a populated pane renders). Titles are now plain text; color spans are applied only to secondary lines, where the library permits them. Verified on an Android Automotive emulator: the pane renders with the badges and the POTA "to validate" secondary, no crash. Also removes the now-unused car_* string resources (rows build their text in code, matching the existing carDecodeSecondary pattern). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
- Session row "Last logged …" now uses GeneralVariables.QSL_Callsign_list .lastOrNull() (the worked-list, appended in completion order) instead of the current TX target, which differs right after a QSO completes while calling CQ — the target would then wrongly collapse the row to "No QSOs logged yet". - Add qsosLabel()/decodesLabel() so counts read "1 QSO"/"1 decode" at exactly one instead of "1 QSOs"/"1 decodes"; applied to the POTA/ROTA/session titles and the band decode-count secondary. Covered by new CarDashboardTest cases. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Car status dashboard (Android Auto) — design-doc pane with colored badges
Complete the server trip when the operator discards it locally
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## staging #732 +/- ##
=============================================
+ Coverage 35.89% 36.23% +0.34%
- Complexity 289 290 +1
=============================================
Files 248 244 -4
Lines 30512 30264 -248
Branches 4031 3982 -49
=============================================
+ Hits 10952 10967 +15
+ Misses 19208 18941 -267
- Partials 352 356 +4
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
Promotes the current dev branch state to staging for the Play internal track, bringing back the Play-approved Android Auto (IOT) wiring with a new status-dashboard Pane, plus a fix to ensure abandoned ROTA trips are still completed server-side and POTA activation counters stay live in-car.
Changes:
- Restore Android Auto manifest wiring (IOT-category
CarAppService+ descriptor) and replace the prior map/surface approach with a read-only dashboard Pane (badges, spans, row selection). - Keep POTA activation QSO counts in sync in-memory on each QSO insert; expand debug injection + tests to cover ROTA trip naming and new dashboard behaviors.
- Ensure “Discard local trip” (ROTA abandon) makes a best-effort
completeTripcall to avoid stranding server rows as active.
Reviewed changes
Copilot reviewed 23 out of 23 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| ft8af/app/src/testDebug/kotlin/radio/ks3ckc/ft8af/car/DebugInjectTest.kt | Adds rota extra coverage and ensures blank/trim behavior is tested. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/rota/RotaAbandonTest.kt | New unit tests for abandon → server-complete eligibility logic. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/pota/PotaSessionManagerTest.kt | Adds tests for onQsoLogged no-op when idle and bump predicate matching. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarQsoStatusTest.kt | Replaces removed surface-era tests with pane row-selection tests. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarPanelLayoutTest.kt | Removes tests for deleted surface banner placement math. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarMapProjectionTest.kt | Removes tests for deleted surface map projection code. |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarDashboardTest.kt | New unit tests for the pure dashboard row builders (badges/spans/labels). |
| ft8af/app/src/test/kotlin/radio/ks3ckc/ft8af/car/CarAppManifestWiringTest.kt | Updates manifest wiring tests to assert Android Auto is present and pinned to the approved shape. |
| ft8af/app/src/main/res/xml/automotive_app_desc.xml | Adds the Android Auto app descriptor referenced by manifest meta-data. |
| ft8af/app/src/main/res/values/strings_compose.xml | Updates/removes car-related strings and updates the ROTA abandon description. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/rota/RoadTripScreen.kt | Shows the updated abandon description in the active-trip card UI. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/ui/map/WorldOutlines.kt | Comment update reflecting removal of map/surface renderer path. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/rota/RotaTripManager.kt | Implements best-effort server completion on abandon + adds pure helper. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/pota/PotaSessionManager.kt | Adds synchronized onQsoLogged + extracted bump predicate helper. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/QsoStatusScreen.kt | Replaces surface-map template with dashboard pane rendering and badge rasterization cache. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarSurfaceState.kt | Removes surface snapshot model (no longer used). |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarQsoStatus.kt | Adds dashboard row model/builders + row selection priorities and helpers. |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarPanelLayout.kt | Removes surface banner layout helpers (no longer used). |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarMapSurfaceRenderer.kt | Removes surface renderer implementation (NAVIGATION map path removed). |
| ft8af/app/src/main/kotlin/radio/ks3ckc/ft8af/car/CarMapProjection.kt | Removes surface map projection geometry (no longer used). |
| ft8af/app/src/main/java/com/k1af/ft8af/database/DatabaseOpr.java | Calls PotaSessionManager.onQsoLogged after bumping activation qso_count. |
| ft8af/app/src/main/AndroidManifest.xml | Restores Android Auto meta-data + IOT-category CarAppService wiring. |
| ft8af/app/src/debug/kotlin/radio/ks3ckc/ft8af/car/DebugInject.kt | Adds rota extra to start an offline trip + ensures demo QSOs stamp POTA via real helper. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
… local CarAppManifestWiringTest re-accessed the platform-nullable ApplicationInfo.metaData on each getInt(); read it once via checkNotNull into a non-null local so a dropped meta-data block fails with an actionable message instead of an NPE mid-assertion. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Promotes the current
devtostagingfor the Play internal track (per theandroid.ymlrelease flow: push tostaging→ internal track).Included since staging
CarAppServicewiring that cleared Play production review (versionCode 1327), deletes the rejected NAVIGATION map/Surface variant, and adds live POTA/ROTA activation rows to the car pane. Includes the Copilot fixes (onQsoLoggedsynchronized; manifest wiring test guardsmetaDatanull).ForegroundCarColorSpanis not allowed on a Row title — it threw and killed the CarAppService process on every populated render). Includes the Copilot fixes (last-logged callsign from the worked-list; singular/plural counts).Notes
targetSdk/compileSdkare already 36 on bothdevandstaging, so no SDK change rides along here.testDebugUnitTest+ instrumented tests green on the constituent PRs.🤖 Generated with Claude Code