A foreground service is work the user knows about: it shows an ongoing notification, and the system treats the app almost like a visible one. Since Android 14 each one declares a type (dataSync, location, mediaPlayback, shortService and ten more) plus a matching FOREGROUND_SERVICE_<TYPE> permission. Since Android 12 an app can't start one from the background except in listed cases, and since Android 15 dataSync and mediaProcessing get six hours per 24, then Service.onTimeout() asks them to stop.
BookNest's "download the offline pack" saves every cover for reading on a plane. The user asked for it and waits, so OfflinePackWorker calls setForeground(progress(done)) before each cover:
private fun progress(done: Int): ForegroundInfo {
val notification = NotificationCompat.Builder(applicationContext, BookNestNotifications.SYNC)
.setSmallIcon(R.drawable.menu_book_24px)
.setContentTitle("Downloading the offline pack")
.setContentText("$done of $TOTAL covers")
.setProgress(TOTAL, done, false)
.setOngoing(true)
.build()
return ForegroundInfo(NOTIFICATION_ID, notification,
ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC) // must match the manifest
}The first run crashed the app, because WorkManager 234 's SystemForegroundService declares no type:
E AndroidRuntime: java.lang.RuntimeException: Unable to start service androidx.work.impl.foreground. SystemForegroundService@21e2b21 ... java.lang.IllegalArgumentException: foregroundServiceType 0x00000001 is not a subset of foregroundServiceType attribute 0x00000000 in service element of manifest file
With the type merged into the library's service, the next run hit SecurityException: Starting FGS with type dataSync ... requires permissions: ... [android.permission.FOREGROUND_SERVICE_DATA_SYNC], which WorkManager caught, running the download as plain background work. Both parts are needed (WorkManager already adds FOREGROUND_SERVICE itself):
<uses-permission android:name="android.permission.FOREGROUND_SERVICE_DATA_SYNC" />
<service android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync" tools:node="merge" />Then adb shell dumpsys activity services com.example.booknest showed isForeground=true foregroundId=900 types=0x00000001 and the six covers arrived in 14 seconds. Yet the shade, pulled down four seconds in, showed nothing from BookNest: Android 12 and later may hold a foreground service's notification back for 10 seconds, so short jobs never clutter it.