fix(location): persist self-marker across screen-off + instant fix on foreground (#75)#87
Merged
Merged
Conversation
… foreground (#75) Root cause: TacticalMap's ON_PAUSE handler disables the MapLibre LocationComponent to silence its compass animator (Android 16 crash), but nothing ever re-enabled it on ON_RESUME — after screen-off/on the self-marker stayed hidden until the composable was rebuilt, and after process death there was no persisted fix to render while GPS reacquired. - TacticalMap ON_RESUME now re-enables the puck (follow-me-aware camera mode) so the marker survives screen-off in-process - Persist the last real fix (lat/lon/hae/time) to DataStore, throttled to one write per 15 s — UserPrefs selfHae/selfFixTimeMs join the existing selfLat/selfLon, which finally gain a writer - Seed LocationProvider from the persisted fix on cold start so the 2D puck, Cesium self entity, HUD card, and PPLI prefs-fallback all render immediately; the puck renders dimmed (45% alpha, no pulse) while the fix is older than 30 s, matching MapLibre's own stale-state timeout - Force an immediate fused refresh (cache + single-shot getCurrentLocation) on every foreground ON_RESUME instead of waiting for the next passive interval tick - Newer-wins gate in LocationProvider so a restored fix can never clobber live GPS - No manifest/permission changes — foreground lifecycle + DataStore only Tests: 19-case SelfFixPersistenceTest (restore round-trip, staleness boundary, persist throttle, newer-wins) + persisted-prefs PPLI fallback case in SelfPositionBroadcasterFixSourcingTest. assembleDebug + testDebugUnitTest green (300 tests, 0 failures). Closes #75 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…le (bearing) from #86
jfuginay
added a commit
that referenced
this pull request
Jun 11, 2026
… Cesium viewport handoff - versionName 0.35.2 -> 0.35.3, versionCode 90 -> 91 - carries #86 (Cesium camera inherits 2D viewport, #78) and #87 (self-marker survives screen-off + instant fix on resume, #75) — both from r/ATAK tester feedback, same-day turnaround Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
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.
Closes #75 — self-marker disappears after screen-off; slow to reappear on resume.
Root cause
TacticalMap.kt's lifecycle observer disables the MapLibre LocationComponent onON_PAUSE(added to kill the compass animator that crashed against a detached style on Android 16) — but nothing ever re-enabled it onON_RESUME. After screen-off/on, the puck stayed hidden until the composable happened to be rebuilt (nav away + back, basemap change). Two aggravators made the reacquire slow and the cold-start case worse:LocationProvider's fix was memory-only — process death (Doze kill) meant no position at all until fused delivered, and the cold-startlastLocationpath suppresses anything older than 5 min, so the marker sat empty while GPS reacquired.UserPrefs.selfLat/selfLon(the broadcaster's designed persisted-position fallback since GAP-030b) had no writer anywhere — the persistence half of the design was never wired.iOS parity note (issue comment): iOS holds the puck through screen-off via its background-location entitlement. Android mirrors the intent with zero new permissions: persist the last fix, render it immediately on resume (stale-marked), and force a refresh on foreground.
What changed
TacticalMap.ktON_RESUMEre-enables the LocationComponent, restoring follow-me's camera mode. NewselfFixparam feeds the puck viaforceLocationUpdate(verified unconditional in MapLibre 11.8.0 bytecode), so a restored fix renders the instant the map is up. Puck renders dimmed (45% alpha, no pulse) while the fix is >30 s old, andstaleStateTimeout(30s)+ a registered stale image make live-GPS-loss dim identically. Puck options re-applied after basemap swaps so the style-bound bitmaps survive reloads.UserPrefs.ktselfHae+selfFixTimeMsjoinselfLat/selfLon;setLastSelfFix()writer.SelfFixPersistence.kt(new)LocationProvider.ktseedFromPersisted(),requestImmediateFix()(fused cache + single-shotgetCurrentLocation), and a newer-wins write gate so the seed can never clobber a live fix (and a fresher fused cache upgrades a stale seed).OmniTAKApp.ktMainActivity.ktON_RESUMEobserver also firesrequestImmediateFix().SelfPositionBroadcaster.ktNo manifest or permission changes — foreground lifecycle + DataStore only (Play review window respected).
Test evidence
./gradlew assembleDebug— green./gradlew testDebugUnitTest— 300 tests, 0 failures (JDK 21)SelfFixPersistenceTest— 19 cases: restore round-trip (incl. NaN sentinels + never-claims-live-confidence), 30 s staleness boundary, persist throttle, newer-wins mergeSelfPositionBroadcasterFixSourcingTest— newbroadcasts_persisted_position_when_fix_nulllocks the persisted-prefs PPLI fallback (lat/lon/hae + honestce=9999999); the GAP-030b no-SF regressions still passRemaining verification
Per repo convention, on-device side-by-side verification (screen-off → resume on hardware, plus an iOS/Android composite for the parity check) remains before this ships in a release build — flagging for the next device session.
🤖 Generated with Claude Code