From 24ea7ec59a7d8d48613594c5d47c0b32c300b65c Mon Sep 17 00:00:00 2001 From: inventory69 Date: Mon, 2 Feb 2026 13:09:12 +0100 Subject: [PATCH] fix: Android 9 crash - Implement getForegroundInfo() for WorkManager Expedited Work (Issue #15) This commit fixes the critical crash on Android 9 (API 28) that occurred when using WorkManager Expedited Work for background sync operations. ## Root Cause When setExpedited() is used in WorkManager, the CoroutineWorker must implement getForegroundInfo() to return a ForegroundInfo object with a Foreground Service notification. On Android 9-11, WorkManager calls this method, but the default implementation throws: IllegalStateException: Not implemented ## Solution - Implemented getForegroundInfo() in SyncWorker - Returns ForegroundInfo with sync progress notification - Android 10+: Sets FOREGROUND_SERVICE_TYPE_DATA_SYNC for proper service typing - Added required Foreground Service permissions to AndroidManifest.xml ## Technical Changes - SyncWorker.kt: Added getForegroundInfo() override - NotificationHelper.kt: Added createSyncProgressNotification() factory method - strings.xml: Added sync_in_progress UI strings (EN + DE) - AndroidManifest.xml: Added FOREGROUND_SERVICE permissions - Version updated to 1.7.1 (versionCode 18) ## Previously Fixed (in this release) - Kernel-VPN compatibility (Wireguard interface detection) - HTTP connection lifecycle optimization (SafeSardineWrapper) - Stability improvements for sync sessions ## Testing - Tested on Android 9 (API 28) - No crash on second app start - Tested on Android 15 (API 35) - No regressions - WiFi-connect sync working correctly - Expedited work notifications display properly Fixes #15 Thanks to @roughnecks for detailed bug report and testing! --- CHANGELOG.de.md | 31 ++++++++++++------ CHANGELOG.md | 31 ++++++++++++------ android/app/build.gradle.kts | 4 +-- android/app/src/main/AndroidManifest.xml | 5 +++ .../dettmer/simplenotes/sync/SyncWorker.kt | 32 +++++++++++++++++++ .../simplenotes/utils/NotificationHelper.kt | 21 ++++++++++++ .../app/src/main/res/values-de/strings.xml | 2 ++ android/app/src/main/res/values/strings.xml | 2 ++ .../metadata/android/de-DE/changelogs/18.txt | 10 +++--- .../metadata/android/en-US/changelogs/18.txt | 9 +++--- 10 files changed, 119 insertions(+), 28 deletions(-) diff --git a/CHANGELOG.de.md b/CHANGELOG.de.md index 2e157d1..c0e0723 100644 --- a/CHANGELOG.de.md +++ b/CHANGELOG.de.md @@ -8,19 +8,30 @@ Das Format basiert auf [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). --- -## [1.7.1] - 2026-01-30 +## [1.7.1] - 2026-02-02 ### 🐛 Kritische Fehlerbehebungen -- **App-Absturz auf Android 9 nach längerer Nutzung behoben** ([ref #15](https://github.com/inventory69/simple-notes-sync/issues/15)) - - Ressourcenerschöpfung durch nicht geschlossene HTTP-Verbindungen behoben - - App konnte nach ~30-45 Minuten Nutzung durch angesammelte Connection-Leaks abstürzen - - Danke an [@roughnecks] für den detaillierten Fehlerbericht! +#### Android 9 App-Absturz Fix ([#15](https://github.com/inventory69/simple-notes-sync/issues/15)) -- **VPN-Kompatibilitäts-Regression behoben** ([ref #11](https://github.com/inventory69/simple-notes-sync/issues/11)) - - WiFi Socket-Binding erkennt jetzt korrekt Wireguard VPN-Interfaces (tun*, wg*, *-wg-*) - - Traffic wird korrekt durch VPN-Tunnel geleitet statt direkt über WiFi - - Behebt "Verbindungs-Timeout" beim Sync zu externen Servern über VPN +**Problem:** App stürzte auf Android 9 (API 28) ab wenn WorkManager Expedited Work für Hintergrund-Sync verwendet wurde. + +**Root Cause:** Wenn `setExpedited()` in WorkManager verwendet wird, muss die `CoroutineWorker` die Methode `getForegroundInfo()` implementieren um eine Foreground Service Notification zurückzugeben. Auf Android 9-11 ruft WorkManager diese Methode auf, aber die Standard-Implementierung wirft `IllegalStateException: Not implemented`. + +**Lösung:** `getForegroundInfo()` in `SyncWorker` implementiert um eine korrekte `ForegroundInfo` mit Sync-Progress-Notification zurückzugeben. + +**Details:** +- `ForegroundInfo` mit Sync-Progress-Notification für Android 9-11 hinzugefügt +- Android 10+: Setzt `FOREGROUND_SERVICE_TYPE_DATA_SYNC` für korrekte Service-Typisierung +- Foreground Service Permissions in AndroidManifest.xml hinzugefügt +- Notification zeigt Sync-Progress mit indeterminiertem Progress Bar +- Danke an [@roughnecks](https://github.com/roughnecks) für das detaillierte Debugging! + +#### VPN-Kompatibilitäts-Fix ([#11](https://github.com/inventory69/simple-notes-sync/issues/11)) + +- WiFi Socket-Binding erkennt jetzt korrekt Wireguard VPN-Interfaces (tun*, wg*, *-wg-*) +- Traffic wird korrekt durch VPN-Tunnel geleitet statt direkt über WiFi +- Behebt "Verbindungs-Timeout" beim Sync zu externen Servern über VPN ### 🔧 Technische Änderungen @@ -28,10 +39,12 @@ Das Format basiert auf [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Weniger unnötige 401-Authentifizierungs-Challenges durch preemptive Auth-Header - ProGuard-Regel hinzugefügt um harmlose TextInclusionStrategy-Warnungen zu unterdrücken - VPN-Interface-Erkennung via `NetworkInterface.getNetworkInterfaces()` Pattern-Matching +- Foreground Service Erkennung und Notification-System für Hintergrund-Sync-Tasks ### 🌍 Lokalisierung - Hardcodierte deutsche Fehlermeldungen behoben - jetzt String-Resources für korrekte Lokalisierung +- Deutsche und englische Strings für Sync-Progress-Notifications hinzugefügt --- diff --git a/CHANGELOG.md b/CHANGELOG.md index 3a63608..759db93 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,19 +8,30 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). --- -## [1.7.1] - 2026-01-30 +## [1.7.1] - 2026-02-02 ### 🐛 Critical Bug Fixes -- **Fixed app crash on Android 9 after extended use** ([ref #15](https://github.com/inventory69/simple-notes-sync/issues/15)) - - Fixed resource exhaustion caused by unclosed HTTP connections - - App could crash after ~30-45 minutes of use due to accumulated connection leaks - - Thanks to [@roughnecks] for the detailed bug report! +#### Android 9 App Crash Fix ([#15](https://github.com/inventory69/simple-notes-sync/issues/15)) -- **Fixed VPN compatibility regression** ([ref #11](https://github.com/inventory69/simple-notes-sync/issues/11)) - - WiFi socket binding now correctly detects Wireguard VPN interfaces (tun*, wg*, *-wg-*) - - Traffic routes through VPN tunnel instead of bypassing it directly to WiFi - - Fixes "Connection timeout" when syncing to external servers via VPN +**Problem:** App crashed on Android 9 (API 28) when using WorkManager Expedited Work for background sync. + +**Root Cause:** When `setExpedited()` is used in WorkManager, the `CoroutineWorker` must implement `getForegroundInfo()` to return a Foreground Service notification. On Android 9-11, WorkManager calls this method, but the default implementation throws `IllegalStateException: Not implemented`. + +**Solution:** Implemented `getForegroundInfo()` in `SyncWorker` to return a proper `ForegroundInfo` with sync progress notification. + +**Details:** +- Added `ForegroundInfo` with sync progress notification for Android 9-11 +- Android 10+: Sets `FOREGROUND_SERVICE_TYPE_DATA_SYNC` for proper service typing +- Added Foreground Service permissions to AndroidManifest.xml +- Notification shows sync progress with indeterminate progress bar +- Thanks to [@roughnecks](https://github.com/roughnecks) for the detailed debugging! + +#### VPN Compatibility Fix ([#11](https://github.com/inventory69/simple-notes-sync/issues/11)) + +- WiFi socket binding now correctly detects Wireguard VPN interfaces (tun*, wg*, *-wg-*) +- Traffic routes through VPN tunnel instead of bypassing it directly to WiFi +- Fixes "Connection timeout" when syncing to external servers via VPN ### 🔧 Technical Changes @@ -28,10 +39,12 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). - Reduced unnecessary 401 authentication challenges with preemptive auth headers - Added ProGuard rule to suppress harmless TextInclusionStrategy warnings on older Android versions - VPN interface detection via `NetworkInterface.getNetworkInterfaces()` pattern matching +- Foreground Service detection and notification system for background sync tasks ### 🌍 Localization - Fixed hardcoded German error messages - now uses string resources for proper localization +- Added German and English strings for sync progress notifications --- diff --git a/android/app/build.gradle.kts b/android/app/build.gradle.kts index e6d274b..e315feb 100644 --- a/android/app/build.gradle.kts +++ b/android/app/build.gradle.kts @@ -20,8 +20,8 @@ android { applicationId = "dev.dettmer.simplenotes" minSdk = 24 targetSdk = 36 - versionCode = 18 // 🔧 v1.7.1: Connection Leak Fix (Issue #15) - versionName = "1.7.1" // 🔧 v1.7.1: Connection Leak Fix + versionCode = 18 // 🔧 v1.7.1: Android 9 getForegroundInfo Fix (Issue #15) + versionName = "1.7.1" // 🔧 v1.7.1: Android 9 getForegroundInfo Fix testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner" } diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml index bc7094a..601b20a 100644 --- a/android/app/src/main/AndroidManifest.xml +++ b/android/app/src/main/AndroidManifest.xml @@ -12,6 +12,11 @@ + + + + + diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/sync/SyncWorker.kt b/android/app/src/main/java/dev/dettmer/simplenotes/sync/SyncWorker.kt index 692db55..43ee154 100644 --- a/android/app/src/main/java/dev/dettmer/simplenotes/sync/SyncWorker.kt +++ b/android/app/src/main/java/dev/dettmer/simplenotes/sync/SyncWorker.kt @@ -5,8 +5,11 @@ package dev.dettmer.simplenotes.sync import android.app.ActivityManager import android.content.Context import android.content.Intent +import android.content.pm.ServiceInfo +import android.os.Build import androidx.localbroadcastmanager.content.LocalBroadcastManager import androidx.work.CoroutineWorker +import androidx.work.ForegroundInfo import androidx.work.WorkerParameters import dev.dettmer.simplenotes.BuildConfig import dev.dettmer.simplenotes.utils.Constants @@ -26,6 +29,35 @@ class SyncWorker( const val ACTION_SYNC_COMPLETED = "dev.dettmer.simplenotes.SYNC_COMPLETED" } + /** + * 🔧 v1.7.2: Required for expedited work on Android 9-11 + * + * WorkManager ruft diese Methode auf um die Foreground-Notification zu erstellen + * wenn der Worker als Expedited Work gestartet wird. + * + * Ab Android 12+ wird diese Methode NICHT aufgerufen (neue Expedited API). + * Auf Android 9-11 MUSS diese Methode implementiert sein! + * + * @see https://developer.android.com/develop/background-work/background-tasks/persistent/getting-started/define-work#foregroundinfo + */ + override suspend fun getForegroundInfo(): ForegroundInfo { + val notification = NotificationHelper.createSyncProgressNotification(applicationContext) + + // Android 10+ benötigt foregroundServiceType + return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + ForegroundInfo( + NotificationHelper.SYNC_PROGRESS_NOTIFICATION_ID, + notification, + ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC + ) + } else { + ForegroundInfo( + NotificationHelper.SYNC_PROGRESS_NOTIFICATION_ID, + notification + ) + } + } + /** * Prüft ob die App im Vordergrund ist. * Wenn ja, brauchen wir keine Benachrichtigung - die UI zeigt die Änderungen direkt. diff --git a/android/app/src/main/java/dev/dettmer/simplenotes/utils/NotificationHelper.kt b/android/app/src/main/java/dev/dettmer/simplenotes/utils/NotificationHelper.kt index 62d2eda..e4909e5 100644 --- a/android/app/src/main/java/dev/dettmer/simplenotes/utils/NotificationHelper.kt +++ b/android/app/src/main/java/dev/dettmer/simplenotes/utils/NotificationHelper.kt @@ -19,6 +19,7 @@ object NotificationHelper { private const val CHANNEL_ID = "notes_sync_channel" private const val NOTIFICATION_ID = 1001 private const val SYNC_NOTIFICATION_ID = 2 + const val SYNC_PROGRESS_NOTIFICATION_ID = 1003 // v1.7.2: For expedited work foreground notification private const val AUTO_CANCEL_TIMEOUT_MS = 30_000L /** @@ -54,6 +55,26 @@ object NotificationHelper { Logger.d(TAG, "🗑️ Cleared old sync notifications") } + /** + * 🔧 v1.7.2: Erstellt Notification für Sync-Progress (Expedited Work) + * + * Wird von SyncWorker.getForegroundInfo() aufgerufen auf Android 9-11. + * Muss eine gültige, sichtbare Notification zurückgeben. + * + * @return Notification (nicht anzeigen, nur erstellen) + */ + fun createSyncProgressNotification(context: Context): android.app.Notification { + return NotificationCompat.Builder(context, CHANNEL_ID) + .setSmallIcon(android.R.drawable.stat_notify_sync) + .setContentTitle(context.getString(R.string.sync_in_progress)) + .setContentText(context.getString(R.string.sync_in_progress_text)) + .setPriority(NotificationCompat.PRIORITY_LOW) + .setOngoing(true) + .setProgress(0, 0, true) // Indeterminate progress + .setCategory(NotificationCompat.CATEGORY_PROGRESS) + .build() + } + /** * Zeigt Erfolgs-Notification nach Sync */ diff --git a/android/app/src/main/res/values-de/strings.xml b/android/app/src/main/res/values-de/strings.xml index eeff55f..f773ecd 100644 --- a/android/app/src/main/res/values-de/strings.xml +++ b/android/app/src/main/res/values-de/strings.xml @@ -438,6 +438,8 @@ Notizen Synchronisierung Benachrichtigungen über Sync-Status + Synchronisierung läuft + Notizen werden synchronisiert… Sync erfolgreich %d Notiz(en) synchronisiert Sync fehlgeschlagen diff --git a/android/app/src/main/res/values/strings.xml b/android/app/src/main/res/values/strings.xml index cd9d711..e51bbf0 100644 --- a/android/app/src/main/res/values/strings.xml +++ b/android/app/src/main/res/values/strings.xml @@ -438,6 +438,8 @@ Notes Synchronization Notifications about sync status + Syncing + Syncing notes… Sync successful %d note(s) synchronized Sync failed diff --git a/fastlane/metadata/android/de-DE/changelogs/18.txt b/fastlane/metadata/android/de-DE/changelogs/18.txt index 3896169..9336b4d 100644 --- a/fastlane/metadata/android/de-DE/changelogs/18.txt +++ b/fastlane/metadata/android/de-DE/changelogs/18.txt @@ -1,4 +1,6 @@ -• Behoben: App-Absturz auf Android 9 - Danke an @roughnecks -• Behoben: Kernel-VPN-Kompatibilität (Wireguard) -• Verbessert: Stabilität der Sync-Sessions -• Technisch: Optimierte Verbindungsverwaltung +• Behoben: App-Absturz auf Android 9 (Issue #15) - Danke an @roughnecks + - WorkManager Expedited Work Kompatibilität (getForegroundInfo) + - Kernel-VPN-Kompatibilität (Wireguard tun/wg Interfaces) +• Verbessert: Stabilität und Verbindungsverwaltung +• Technisch: Optimierter HTTP-Connection-Lebenszyklus + diff --git a/fastlane/metadata/android/en-US/changelogs/18.txt b/fastlane/metadata/android/en-US/changelogs/18.txt index e0fabd8..aa74861 100644 --- a/fastlane/metadata/android/en-US/changelogs/18.txt +++ b/fastlane/metadata/android/en-US/changelogs/18.txt @@ -1,4 +1,5 @@ -• Fixed: App crash on Android 9 - Thanks to @roughnecks -• Fixed: Kernel-VPN compatibility (Wireguard) -• Improved: Stability at sync sessions -• Technical: Optimized connection management +• Fixed: App crash on Android 9 (Issue #15) - Thanks to @roughnecks + - WorkManager expedited work compatibility (getForegroundInfo) + - Kernel-VPN compatibility (Wireguard tun/wg interfaces) +• Improved: Stability and connection management +• Technical: Optimized HTTP connection lifecycle