-
released this
2026-05-15 14:31:10 +02:00 | 7 commits to main since this releaseGPS2Audio v2.0.4 — Atmo Background Playback Fix
Overview
- Version:
2.0.4(versionCode32, ↑ from 31) - Baseline:
GPS2Audio_v2_0_3_ptt_waypoint_pause_source.zip - Build type: signed release, RSA-4096 (
gps2audio_releasealias), SHA-256
fingerprint matches the v2.0.x release keystore on file.
Artifacts
- APK:
/home/user/workspace/GPS2Audio_v2_0_4_atmo_background_signed.apk - Source:
/home/user/workspace/GPS2Audio_v2_0_4_atmo_background_source.zip - Handoff:
/home/user/workspace/GPS2Audio_v2_0_4_atmo_background_handoff.md
Root cause
v2.0.3 starts Atmo (Begleitmusik) through
BackgroundMusicManager/BackgroundMusicPlayer,
an app-singleton that owns an ExoPlayer instance. No code in MainActivity,
DisposableEffect, Lifecycle observer, oronCleared()callspause()/stop()on
the player when the app moves to background — i.e. the app was not explicitly
pausing Atmo on minimize.However, when the activity goes to background and the screen turns off, the
Android process is moved to a "cached / restricted background" state. Because no
foreground service of typemediaPlaybackwas holding the audio session,
Android terminates or freezes the process within ~10–30 s, which the user
observes as "Atmo stopped when minimized". When the activity is brought back to
the front, the user manually re-enters Atmo or the GPS service rebinds and
restarts the player — looking like "starts again on reopen".This is the canonical Android behaviour for non-foreground audio playback on
API 26+ (and tightens on Android 12 / 14). The robust, documented fix is to run
aforegroundServiceType="mediaPlayback"service whenever Atmo is alive.Exact change
1. New foreground service
AtmoPlaybackService- File:
app/src/main/kotlin/de/waypointaudio/service/AtmoPlaybackService.kt foregroundServiceType="mediaPlayback"(uses
FOREGROUND_SERVICE_TYPE_MEDIA_PLAYBACKon API 34+).- Owns no playback logic — only signals the OS that the app is legitimately
playing media in the background and posts a low-priority, silent ongoing
notification (channelatmo_playback_channel, importance LOW). start(ctx,title,source)/stop(ctx)companion helpers;stopForeground
withSTOP_FOREGROUND_REMOVEremoves the notification on stop.
2.
BackgroundMusicPlayerhooks the service lifecycle to the player lifetimebuildPlayer()→AtmoPlaybackService.start(...)immediately after building
the ExoPlayer (i.e. when Atmo actually starts playing for a tour / test).releasePlayer()→AtmoPlaybackService.stop(ctx).- Pause/duck/fade do NOT stop the service. The service is tied to the
existence of an active ExoPlayer instance, not to play/pause state. This is
what preserves PTT, waypoint, and manual-player interruption resumes —
during those, the player is paused but still allocated, so the foreground
service keeps the process alive and resume works exactly as in v2.0.3.
3. ExoPlayer audio plumbing
setAudioAttributes(USAGE_MEDIA / AUDIO_CONTENT_TYPE_MUSIC, handleAudioFocus=false)
— declares the stream as media. Audio-focus arbitration stays with the
app-internal coordinator (AtmoResumeManager,WaypointAudioInterruptionCoordinator)
exactly as before; ExoPlayer does not auto-pause on transient focus loss.setHandleAudioBecomingNoisy(true)— when headphones are unplugged, ExoPlayer
pauses (not stops). The foreground service stays up, so the user can
resume from PTT/waypoint logic or the manual play button.
4. Manifest
- Added permission
android.permission.FOREGROUND_SERVICE_MEDIA_PLAYBACK
(Android 14+ requirement). - Declared the new service with
foregroundServiceType="mediaPlayback".
5. Strings (German UI, consistent with rest of app)
atmo_notification_channel_name— "Begleitmusik (Atmo)"atmo_notification_channel_descriptionatmo_notification_default_title— "Begleitmusik läuft"atmo_notification_default_source— fallback when stream/playlist label
is blank.
6. Version bump
versionCode 31 → 32,versionName 2.0.3 → 2.0.4inapp/build.gradle.kts.
What was deliberately NOT changed
MainActivity.onPause/onResume— only WakeLockController is touched there;
it manipulates the screen-on flag, never the audio. Confirmed via grep:
nopauseMusic/stopMusic/player.pause/player.stopis called from any
Activity / Compose lifecycle path.BackgroundMusicManager.loadTour()— still stops music on intentional
tour change (previousTour != tourNamewithenabled=false).BackgroundMusicManager.saveAndApplySettings()— still stops music when the
user disables Begleitmusik.AtmoResumeManager(PTT pause/resume) — untouched.WaypointAudioInterruptionCoordinator— untouched.BackgroundMusicPlayer.beforeWaypointAudio / afterWaypointAudio— untouched.WakeLockController— untouched. The window flag still drops on background
(as designed in v2.0.0); audio is now decoupled from that flag.
Manual test plan
Primary regression (the actual user bug)
- Set up Atmo for a tour (either local playlist or HTTP stream).
- Open the app, start Atmo via the music dialog test button or via the
start-tour flow. - Confirm a small ongoing notification "Begleitmusik (Atmo)" appears.
- Press the Home button to minimize. Audio must keep playing.
- Lock the screen. Wait at least 60 seconds with the screen off.
- Audio must still be playing. Unlock the screen — still playing.
- Reopen the app — the music dialog / mini-player must show "Playing"
with the same track / stream still running, no glitch / restart.
PTT still pauses Atmo (v2.0.3 contract)
- With Atmo playing in foreground, hold PTT.
- Atmo pauses (or fades / ducks per settings).
- Release PTT — Atmo resumes from where it left off.
- Repeat with the app minimized: hold PTT (e.g. via headset key if mapped),
Atmo should still pause/resume.
Waypoint audio still pauses Atmo (v2.0.3 contract)
- Manually trigger a waypoint audio from the list, or walk into a radius.
- Atmo follows the configured
WaypointMusicBehavior
(PAUSE_RESUME / FADE_OUT_IN / DUCK_UNDERLAY / CONTINUE_UNDERLAY). - After the waypoint audio finishes naturally, Atmo continues / resumes /
auto-starts perautoStartAfterWaypoint.
Manual player still pauses Atmo
- Tap a waypoint to play its audio manually.
- Atmo pauses for the duration, resumes after.
User stop / pause / disable still works
- Press stop in the music dialog → Atmo stops, notification disappears,
no resume. - Press pause → Atmo pauses, notification stays (player still allocated),
pressing play resumes. - Open Begleitmusik dialog → toggle "Aktiviert" off → save. Atmo stops,
notification disappears.
Tour change
- Switch to a tour that has
enabled=false. Atmo stops on tour switch.
Headphone unplug
- With wired/Bluetooth headphones connected and Atmo playing, unplug
(or disconnect Bluetooth). Atmo pauses (does not stop) — resume by
pressing play in the dialog/mini-player.
Wake Lock interaction
- Set Wake Lock mode to "Active tour only". Start the tour, screen stays on.
- Press Power to lock the screen. The screen-on flag releases (expected),
but Atmo keeps playing. - Unlock — Atmo is still playing, screen-on flag re-applied if mode dictates.
Regression checklist
- PTT pauses waypoint audio (v2.0.3 feature) — unchanged code path.
- PTT pauses Atmo with resume —
AtmoResumeManager.notifyInterruptStart
still callspauseMusic(), only releasing service on hard stop. - Drag-and-drop reorder of waypoints — unrelated, untouched.
- Wake Lock settings (NEVER / APP_FOREGROUND / ACTIVE_TOUR) — untouched.
- Map provider selection — untouched.
- Track-Editor / drafts — untouched.
- Backup import / export — untouched.
- Map search (everywhere / current view) — untouched.
- Audio library playlist (drag/drop, picker) — untouched.
- OSM attribution badge — untouched.
- TabRow fix — untouched.
- About / PayPal / version notice — untouched.
- Signed-release path (keystore.properties + env vars) — unchanged.
- Version notice will trigger again because versionCode advanced (31 → 32).
- APK targets SDK 35, min SDK 26, includes the new
FOREGROUND_SERVICE_MEDIA_PLAYBACKpermission and the new service in
manifest (verified viaaapt dump badging). - Signature: SHA-256
7B:0E:A4:D5:…:BB:46matches keystore record (verified
viaapksigner verify --print-certs).
Limitations
- The user will now see a persistent low-priority "Begleitmusik (Atmo)"
notification while Atmo is loaded. This is required by Android 12+ to keep
background audio reliably alive and is the minimal acceptable solution.
It is silent (setSilent(true), importance LOW,setOnlyAlertOnce) and
disappears the moment the user presses Stop or Begleitmusik is disabled. - The notification has no media-style transport controls. A future iteration
could add play/pause/next/previous through aMediaSessionService; left out
intentionally to keep the diff minimal and avoid touching the v2.0.3 PTT /
waypoint pause logic.
Build verification
package: name='de.waypointaudio' versionCode='32' versionName='2.0.4' sdkVersion:'26' targetSdkVersion:'35' uses-permission: …FOREGROUND_SERVICE_MEDIA_PLAYBACK service: de.waypointaudio.service.AtmoPlaybackService (mediaPlayback) Signer #1 SHA-256: 7b0ea4d5528605173d299d7b268e7ab8768dd504ec15b66a52d47b4257b3bb46 BUILD SUCCESSFUL (gradle 8.9, AGP via wrapper config, SDK 35 build-tools 35.0.0)Downloads
- Version: