# GPS2Audio v2.0.3 — PTT pauses waypoint audio ## Summary This release adds a single focused behavior on top of v2.0.2: > When the user starts PTT (Push-To-Talk) while a waypoint audio is playing > (either GPS-triggered or manually triggered), the waypoint audio is paused > immediately so that PTT and the waypoint audio are never heard at the same > time. When the user releases PTT, the waypoint audio resumes exactly where > it left off — but only if it was already playing when PTT started. All other v2.0.2 functionality is preserved unchanged (drag-reorder, tour counters, backup import/export, atmo pause/resume during PTT, manual playlist & single-item playback, etc.). There are no UI changes. ## Build & signing - Baseline: `GPS2Audio_v2_0_2_drag_reorder_source.zip` - `applicationId`: `de.waypointaudio` (unchanged) - `versionCode`: `31` (was 30 in v2.0.2) - `versionName`: `2.0.3` - Signed with `/home/user/workspace/GPS2Audio_release_keystore.jks`, alias `gps2audio_release`. - Verified `apksigner verify --print-certs`: - SHA-256: `7B0EA4D5528605173D299D7B268E7AB8768DD504EC15B66A52D47B4257B3BB46` (matches keystore credentials file → upgrade-compatible with previous signed releases). - Build host: Gradle 8.9, AGP per `libs.versions.toml`, Android SDK 35. ## Artifacts | Path | Contents | | --- | --- | | `/home/user/workspace/GPS2Audio_v2_0_3_ptt_waypoint_pause_signed.apk` | Signed release APK | | `/home/user/workspace/GPS2Audio_v2_0_3_ptt_waypoint_pause_source.zip` | Full source tree (no keystore, no `local.properties`, no build outputs) | | `/home/user/workspace/GPS2Audio_v2_0_3_ptt_waypoint_pause_handoff.md` | This document | ## Behavioural contract 1. **PTT start while a waypoint audio is playing** → that waypoint audio is paused (its `MediaPlayer` position is retained). 2. **PTT start while no waypoint audio is playing** → no pause/resume happens for waypoint audio (Atmo handling continues to work as before). 3. **PTT end** → only those waypoint audios that were paused by *this* PTT session are resumed. Anything that was already stopped/finished is not resurrected. 4. **Duplicate PTT state events** (e.g. another `startPtt()` while already active) → no repeated pause/resume. Idempotency is enforced both in `LivePttManager` and inside `WaypointAudioInterruptionCoordinator.beginInterruption / endInterruption`. 5. **Atmo (background music)** behaviour is unchanged: it is still paused on PTT start and resumed on PTT end via the existing `AtmoResumeManager`. 6. **GPS-triggered waypoints fired *during* PTT** continue to be queued and played after PTT ends (existing `pendingPttWaypoint` flow in `WaypointLocationService`). Unchanged. 7. **Manual playback during PTT** is still blocked by the existing "PTT-Sperre" guard in `WaypointViewModel.manualPlayPause` and `manualPlaySingle`. Unchanged. ## Implementation ### New file - `app/src/main/kotlin/de/waypointaudio/service/WaypointAudioInterruptionCoordinator.kt` - Process-wide `object` singleton. - Two `Source`s: `GPS` (location service `AudioPlayer`), `MANUAL` (`ManualAudioPlayer` in `WaypointViewModel`). - Each active player registers with three lambdas: `isCurrentlyPlaying`, `pause`, `resume`. - `beginInterruption()` pauses all currently-playing sources and remembers which ones it paused. `endInterruption()` resumes exactly those. - Self-deduplicates against double-`beginInterruption()` / double- `endInterruption()` calls (no-op if state is wrong). - Edge case: if a source registers *during* an active interruption and is already playing, it is paused immediately and marked for resume on `endInterruption()`. ### Changed files - `app/src/main/kotlin/de/waypointaudio/service/AudioPlayer.kt` - Added `pause()`, `resume()`, `isPlaying` (property), `hasContent` (property). Existing `play()` / `stop()` semantics unchanged. - `app/src/main/kotlin/de/waypointaudio/service/ManualAudioPlayer.kt` - Added `resume()` to complement existing `pause()`. The `play()`-resumes- paused-track path is untouched (manual UI resume still works). - `app/src/main/kotlin/de/waypointaudio/service/WaypointLocationService.kt` - `playWaypointAudio()` now registers the running `audioPlayer` with the coordinator (`Source.GPS`) and unregisters on natural completion, on error, and on `stopTracking()`. - `app/src/main/kotlin/de/waypointaudio/service/LivePttManager.kt` - `pauseAtmo()` now also calls `WaypointAudioInterruptionCoordinator.beginInterruption()`. - `restoreAtmo()` now also calls `WaypointAudioInterruptionCoordinator.endInterruption()` *before* the Atmo resume, so the waypoint audio comes back first and Atmo follows its existing logic. - `app/src/main/kotlin/de/waypointaudio/viewmodel/WaypointViewModel.kt` - Registers `manualPlayer` with the coordinator (`Source.MANUAL`) on VM creation and unregisters in `onCleared()`. `isCurrentlyPlaying` reads the underlying `MediaPlayer.isPlaying` so that only an actively-playing manual track is paused by PTT — a paused or stopped manual track is left alone. - `app/build.gradle.kts` - `versionCode = 31`, `versionName = "2.0.3"`. ### Files NOT changed No XML resources, no Compose UI, no manifests, no permissions, no Atmo logic, no backup/import code, no map code, no drag-reorder code, no PTT UI (`LivePttCard.kt`). ## Manual test plan Install over an existing v2.0.2 build of `de.waypointaudio` (signature matches, so direct update works without uninstall). 1. **Sanity: nothing is playing, press PTT, release.** - Expected: PTT mic activates and deactivates normally. No waypoint audio appears. No regression. 2. **Atmo only, PTT toggles.** - Start Atmo (Begleitmusik) for a tour. Press PTT → Atmo pauses. Release PTT → Atmo resumes. (Pre-existing behaviour, must still work.) 3. **Manual single-item waypoint, PTT toggles.** - In waypoint list, press Play on a card. While audio plays, press PTT start. **Audio must go silent immediately.** Release PTT. **Audio resumes from the same position.** Pause icon state on the card is unchanged across the cycle. 4. **Manual playlist, PTT toggles.** - From the manual player bar, start playback of the tour. While playing, press PTT. Audio pauses. Release PTT. Audio resumes from the same spot. 5. **GPS waypoint trigger + PTT mid-playback.** - Walk into a waypoint radius so its audio fires automatically. While it plays, press PTT. **Waypoint audio pauses.** Release PTT. **Waypoint audio resumes** and finishes; `playCount` increments only once on natural completion. 6. **GPS waypoint trigger *during* PTT (existing queue path).** - Press PTT and hold. While PTT is active, cross into a waypoint radius. The waypoint should NOT play yet (existing behaviour). Release PTT → the queued waypoint plays normally. 7. **Duplicate PTT state events.** - Rapidly toggle PTT or invoke `togglePtt()` repeatedly while audio is playing. The waypoint audio should pause exactly once per real activation and resume exactly once per real deactivation — never "double-resume" into a runaway. 8. **PTT during a manually paused track.** - Start a manual single-item audio, press Pause on the card. Press PTT start → release. The track must NOT auto-start on PTT release (it was already paused before PTT, so the coordinator does nothing for it). 9. **Stop GPS service or close app while paused by PTT.** - During PTT-induced pause, kill the GPS service or background the app. Release PTT → coordinator's resume call is a no-op (player released). No crash. 10. **Atmo + manual waypoint + PTT.** - Start Atmo and a manual waypoint together (waypoint ducks Atmo per existing logic). Press PTT → both Atmo and the waypoint audio go silent. Release PTT → both come back. Atmo's resume is still gated by its own rules in `AtmoResumeManager`. ## Known limitations - The pause is implemented on top of Android's `MediaPlayer.pause()` / `.start()`. On a tiny number of buggy device firmwares this can introduce a sub-second click when resuming. The existing manual-pause UI uses the same primitive, so this matches user expectations. - If the user manually stops a waypoint audio *during* PTT (e.g. through some future UI), the coordinator's resume call becomes a safe no-op because the underlying `MediaPlayer` is null. Current UI does not expose any such control while PTT is held, so this is theoretical. ## Rollback Replace the installed APK with `GPS2Audio_v2_0_2_drag_reorder_signed.apk`. `versionCode` 30 < 31 means Android may require uninstall to downgrade.