# GPS2Audio v2.7.36 — Handoff Critical bugfix on top of v2.7.35: **the app froze and crashed right after a backup was successfully created.** No feature/UI redesign; one targeted fix. ## Root cause `WaypointViewModel.exportBackupZip()` ran the **entire** backup on the **main (UI) thread**. Its `viewModelScope.launch { … }` block (viewModelScope defaults to `Dispatchers.Main`) directly performed: - several `repository.*.first()` / `musicStore.settingsFlow.first()` flow reads, and - `BackupExportManager.writeBackup(...)` — which opens the destination `OutputStream`, builds the ZIP, and copies **every referenced media file** in 64 KB chunks (`copyMediaToZip`). For any backup containing media this blocks the UI thread for seconds. Android raises an **ANR ("Application Not Responding")**, which the user experiences as "the app no longer responds and crashes." Crucially, the ZIP write itself completes first — so the backup file is created successfully and *then* the app hangs, which is exactly the reported symptom. The import paths (`loadBackupPreview`, the import-confirm flow) already correctly wrap their heavy work in `withContext(Dispatchers.IO)`. The **export path was the lone offender** — it never switched dispatchers. ## The fix In `exportBackupZip()`, the heavy work (flow reads + `writeBackup`) is now wrapped in `withContext(Dispatchers.IO)`, mirroring the existing import code. The success/error UI-state updates (`_infoMessage` / `_errorMessage`) stay after the IO block on the coroutine's resumption. The whole IO section is additionally guarded by `runCatching { … }.getOrElse { … }` so that any unexpected failure (e.g. a `SecurityException` on the target URI) surfaces as a **non-fatal error message** instead of crashing — the file is already written by then, so the user still keeps their backup. `BackupExportManager.writeBackup` already had robust internal `runCatching` handling per-file and overall, so no changes were needed there. The added outer guard is belt-and-suspenders for anything thrown before/around it. What was **not** changed: the backup ZIP schema/content, `formatVersion`, the import logic, and every other feature/fix (v2.7.32 tour ordering + player auto-open, v2.7.33 Begleitmusik UI, v2.7.34 waypoint-edit UI, v2.7.35 library UI, Explorer/MapLibre/routing/POI/license/PTT/Atmo/multiclip/background playback). ## Changed files 1. `app/src/main/kotlin/de/waypointaudio/viewmodel/WaypointViewModel.kt` - `exportBackupZip()`: heavy IO moved onto `Dispatchers.IO`; added outer `runCatching` so post-write failures are reported, not fatal. No signature, parameter, or behavior change beyond threading + error safety. Identical `BackupInput` / `BackupSelection` are built and the same `BackupExportManager.writeBackup(...)` is called. 2. `app/build.gradle.kts` - `versionCode 141 → 142`, `versionName 2.7.35 → 2.7.36`, changelog comment. ## Build & test - Command: `./gradlew :app:assembleRelease --no-daemon` - Result: **BUILD SUCCESSFUL** (~56s). Only pre-existing deprecation warnings; none from the changed function. - Signed with the release config from `keystore.properties`. Verified: `CN=GPS2Audio, OU=NesoHub, O=GPS2Audio, L=Germany, C=DE`, SHA-256 `490511f3…d4e5` (same key as prior releases). - `aapt2 badging`: `versionCode='142' versionName='2.7.36'`. - No unit/instrumented test suite in the project. Verification was build + signature + version + code-path review against the working import path (which already used the off-main-thread pattern this fix adopts). The flow was **not** exercised on a device/emulator in this environment. ### How to verify on device Create a backup that **includes media** (waypoint audio and/or Atmo playlists, i.e. the "Medien/Atmo" section enabled) to a SAF location. Before: the UI freezes for several seconds after the file appears, then ANR/crash. After: the UI stays responsive and a "Backup erfolgreich erstellt …" message is shown. ## Artifacts - `GPS2Audio_v2.7.36_universal-release-signed.apk` — signed universal release APK (single APK; no ABI splits configured). - `GPS2Audio_v2.7.36_src.zip` — clean source. Excludes `.gradle`, `.idea`, `.kotlin`, all `build/` dirs, `.git`, and binaries (`.apk/.aab/.jks/.keystore/.so` and raster images). Verified: changed files present, no excluded artifacts inside. **Note:** `keystore.properties` and `local.properties` text files are still included. `keystore.properties` carries the signing path/passwords — **strip it before distributing the source externally.**