-
released this
2026-05-15 14:31:53 +02:00 | 7 commits to main since this releaseGPS2Audio v2.0.5 — Atmo Foreground-Service Hotfix
Artifacts
- Signed APK:
/home/user/workspace/GPS2Audio_v2_0_5_atmo_service_hotfix_signed.apk - Source zip:
/home/user/workspace/GPS2Audio_v2_0_5_atmo_service_hotfix_source.zip - This handoff:
/home/user/workspace/GPS2Audio_v2_0_5_atmo_service_hotfix_handoff.md
Build & Signing Verification
Field Value applicationId de.waypointaudioversionCode 33(up from32in v2.0.4)versionName 2.0.5minSdk / targetSdk 26 / 35 compileSdk 35 Build type release, signed Signer DN CN=GPS2Audio, OU=NesoHub, O=GPS2Audio, L=Germany, C=DESigner cert SHA-256 7B:0E:A4:D5:52:86:05:17:3D:29:9D:7B:26:8E:7A:B8:76:8D:D5:04:EC:15:B6:6A:52:D4:7B:42:57:B3:BB:46Signer cert SHA-1 EB:92:2A:83:39:09:ED:6B:2D:CB:62:52:F0:CF:42:5F:26:DF:25:ADSignature matches the GPS2Audio release keystore used since v1 → installs as an
update over any existing release-channel install (no uninstall required).uses-permissionset is unchanged vs. v2.0.4 (FOREGROUND_SERVICE_MEDIA_PLAYBACK,
POST_NOTIFICATIONS, WAKE_LOCK, etc. all preserved).Bug Report Summary (what crashed)
After pressing the Atmo stream play button the app crashed with:
android.app.RemoteServiceException$ForegroundServiceDidNotStartInTimeException: Context.startForegroundService() did not then call Service.startForeground(): ServiceRecord ... de.waypointaudio/.service.AtmoPlaybackServiceThis is the Android 12+ deadline crash: when an app calls
Context.startForegroundService(intent), the system gives the service a hard
window (~5 s) to callService.startForeground(id, notification). Missing the
deadline → the platform kills the app process.Root Cause
In v2.0.4 (
app/src/main/kotlin/de/waypointaudio/service/AtmoPlaybackService.kt)
the deadline-relevantstartForeground(...)call lived inside
onStartCommand, gated byintent?.action == ACTION_START, and wrapped in
runCatching {}that silently swallowed any throwable. Two concrete ways
this could miss the deadline:- Non-START intent on the same
startForegroundService()cycle. Both
start()andstop()usedstartForegroundService()/startService(), but
thewhen (intent?.action)branch forACTION_STOP(or anullintent on
re-delivery /START_STICKY_COMPATIBILITYscenarios) never reached
startForeground. The system had been told "this is a FGS" but the service
never confirmed it. Deadline missed → crash. runCatchingswallowing astartForegroundthrowable. If notification
construction orstartForegrounditself threw (e.g. transient
RemoteExceptionfromNotificationManager, or any backwards-compatibility
edge fromsetForegroundServiceType), the failure was logged and the
service kept running without ever callingstartForegroundagain.
Deadline missed → crash.
The screenshot reported by the user is reproducible on Android 12+ devices
where the first start path was for a stream and any of the above branches
triggered.Fix (exact changes)
File:
app/src/main/kotlin/de/waypointaudio/service/AtmoPlaybackService.ktstartForeground()is now the very first thing the service does, in
onCreate(), with a minimal-valid notification (no network/player work,
no Intent parsing). This satisfies the system deadline unconditionally,
beforeonStartCommandis even invoked.- Re-arm in
onStartCommand: if the firststartForegroundattempt
threw, we retry as the very first action ofonStartCommand(if (!foregroundStarted)), before any branching on the action. - Notification channel created before
startForegroundon Android O+
(already true, kept; added aSDK < Oearly-return so the call is safe
on older devices). - Notification refresh on ACTION_START uses
NotificationManager.notify
with the same ID — keeps the current foreground notification valid even if
the rebuild with real title/source throws. stop()companion now also usesstartForegroundService()on Android
O+ instead ofstartService(). This avoidsIllegalStateExceptionif the
stop is requested while the app is in a state the platform considers
"background", and it guarantees the service still callsstartForeground
immediately (inonCreate) before stopping itself — so the stop path can
never be the cause of a missed-deadline crash either.onStartCommandnow handlesnull/unknown actions by stopping the
service (after the mandatorystartForeground) rather than leaving the
service running without any work.foregroundStartedflag prevents redundantstartForegroundcalls on
repeated starts and is reset instopForegroundCompat.
foregroundServiceType=mediaPlaybackand the
FOREGROUND_SERVICE_MEDIA_PLAYBACKpermission are preserved. The
POST_NOTIFICATIONS permission was already declared and is not hard-required
for a foreground-service notification — denying it merely hides the
notification, the FGS still runs.File:
app/build.gradle.ktsversionCode = 33,versionName = "2.0.5".
No changes elsewhere. All v2.0.4 behaviors preserved:
- Atmo continues playing in background while screen is off or app is minimized
(FGS still active across pause/duck/fade, as before). - PTT and Waypoint-Audio pause/resume semantics unchanged
(BackgroundMusicPlayer.beforeWaypointAudio/afterWaypointAudio
untouched; FGS deliberately stays alive across pauses). - Manual stop / tour switch still triggers
BackgroundMusicPlayer.releasePlayer()→AtmoPlaybackService.stop()→
notification + service torn down. - All previously delivered features intact: drag-and-drop reorder, Wake Lock
while recording / playing, multiple map providers, Track-Editor, Backup
import/export, map search, audio library, OSM attribution, TabRow fix,
About PayPal link + version notice dialog.
Manual Test Plan
These tests target the exact crash and the surrounding Atmo lifecycle. Use a
device on Android 12+ (deadline-enforcing).-
Atmo stream play — no crash (primary repro).
- Open Tour-Settings → Begleitmusik (Atmo) → switch source to Stream URL,
enter a valid stream (e.g. an Icecast.mp3URL). - Press the Play button.
- Expected: audio starts within a few seconds; no crash; status bar
shows an ongoing "Atmo / Stream — " notification.
- Open Tour-Settings → Begleitmusik (Atmo) → switch source to Stream URL,
-
Background continuation.
- With Atmo playing, press Home; then power off the screen.
- Expected: audio keeps playing for at least 60 s; FGS notification
remains visible in the status bar.
-
Stop / disable.
- Re-open app, press Stop on the Atmo controls (or disable Atmo in
Tour-Settings). - Expected: audio stops; foreground notification disappears; no crash.
Re-pressing Play starts a new stream cleanly.
- Re-open app, press Stop on the Atmo controls (or disable Atmo in
-
PTT interplay (do not regress).
- Start Atmo, then start a PTT session.
- Expected: Atmo behavior follows configured Wegpunkt-Verhalten
(pause/duck/fade/continue) for the PTT duration; FGS notification stays
ongoing; Atmo resumes (or stays ducked) on PTT end exactly as in v2.0.4.
-
Waypoint audio interplay.
- Place a waypoint with an audio file along a recorded track; trigger it
while Atmo is playing. - Expected: Atmo behaves per configured behavior; FGS stays up; Atmo
resumes after waypoint audio finishes, matching v2.0.4 behavior.
- Place a waypoint with an audio file along a recorded track; trigger it
-
Local playlist source.
- Switch Atmo source to Local playlist, pick 2–3 tracks, press Play.
- Expected: plays; notification reads "Atmo / Playlist — N Titel"; no
crash; track skip / shuffle behave as before.
-
POST_NOTIFICATIONS denied (Android 13+).
- Long-press the Atmo notification (or use App Info → Notifications) and
disable notifications for GPS2Audio, then start Atmo. - Expected: audio still plays in foreground (FGS keeps the process
alive); no crash; notification simply suppressed by user choice.
- Long-press the Atmo notification (or use App Info → Notifications) and
-
Repeated rapid Start/Stop.
- Toggle Atmo Play/Stop several times in quick succession.
- Expected: no crash; notification appears/disappears cleanly; service
ends after final Stop.
-
Version check.
- Settings → About → version line reads
2.0.5 (33).
- Settings → About → version line reads
Files Touched (delta vs. v2.0.4 baseline)
app/build.gradle.kts (versionCode 32→33, versionName 2.0.4→2.0.5) app/src/main/kotlin/de/waypointaudio/service/AtmoPlaybackService.kt (rewritten: always-on startForeground, null-intent handling, stop via startForegroundService)Nothing else changed.
Downloads
- Signed APK: