I'm using a PeriodicWorker to make a daily backup of my app's data, that is, uploading mu local data to a cloud storage service.
However when I use setForegroundAsync(foregroundInfo); it first, shows me a warning
(startForegroundService() not allowed due to mAllowStartForeground false: service com.mydomain/androidx.work.impl.foreground.SystemForegroundService) and at the of the process, it gives me the error below
Unable to stop foreground service
android.app.BackgroundServiceStartNotAllowedException: Not allowed to start service Intent { act=ACTION_STOP_FOREGROUND cmp=com.mydomain/androidx.work.impl.foreground.SystemForegroundService }: app is in background uid UidRecord{dff373e u0a386 TRNB bg:+3m49s885ms idle change:procadj procs:0 seq(7594403,7591739)} caps=------
at android.app.ContextImpl.startServiceCommon(ContextImpl.java:1945)
at android.app.ContextImpl.startService(ContextImpl.java:1900)
at android.content.ContextWrapper.startService(ContextWrapper.java:825)
at androidx.work.impl.Processor.stopForegroundService(Processor.java:425)
at androidx.work.impl.Processor.stopForeground(Processor.java:303)
at androidx.work.impl.WorkerWrapper.resolve(WorkerWrapper.java:464)
at androidx.work.impl.WorkerWrapper.resetPeriodicAndResolve(WorkerWrapper.java:577)
at androidx.work.impl.WorkerWrapper.handleResult(WorkerWrapper.java:480)
at androidx.work.impl.WorkerWrapper.onWorkFinished(WorkerWrapper.java:358)
at androidx.work.impl.WorkerWrapper$2.run(WorkerWrapper.java:335)
at androidx.work.impl.utils.SerialExecutorImpl$Task.run(SerialExecutorImpl.java:96)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at java.lang.Thread.run(Thread.java:1012)
The "funny" part is the process runs perfectly fine, all the data are perfectly copied to the cloud and nothing is wrong, except the notification that is not shown.
Does anybody has any idea of how I can show the notification even though the application is in the background?
Here is my Worker's code.
public class DatabaseCloudBackupWorker extends Worker {
public static final String TAG = DatabaseCloudBackupWorker.class.getName();
@Override
public Result doWork() {
Result result = Result.failure();
Log.i(TAG, "Starting Database Backup");
this.showProgressNotification();
try {
uploadData()
result = Result.success();
} catch (Exception e) {
Log.e(TAG, "Error")
}
return result;
}
private void showProgressNotification() {
Log.i(TAG, "Showing Database Backup Progress Notification");
Notification notification = this.newProgressNotification();
ForegroundInfo foregroundInfo;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
foregroundInfo = new ForegroundInfo(PROGRESS_NOTIFICATION_ID, notification, ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC);
} else {
foregroundInfo = new ForegroundInfo(PROGRESS_NOTIFICATION_ID, notification);
}
this.setForegroundAsync(foregroundInfo);
}
private Notification newProgressNotification() {
Notification notification = new NotificationCompat.Builder(MyApp.getAppContext(), MyNotificationManager.CHANNEL_ID)
.setSmallIcon(R.mipmap.ic_launcher)
.setOnlyAlertOnce(true)
.setOngoing(true)
.setPriority(NotificationCompat.PRIORITY_HIGH)
.setProgress(0, 0, true)
.setForegroundServiceBehavior(NotificationCompat.FOREGROUND_SERVICE_IMMEDIATE)
.setContentTitle("Database Backup")
.setContentText("Database Backup in Progress")
.build();
return notification;
}
}
Here's the session of my manifest where I set the type of the foreground service
<service
android:name="androidx.work.impl.foreground.SystemForegroundService"
android:foregroundServiceType="dataSync"
tools:node="merge" />
Here's where I create the PeriodicWorkRequest
// Creating Work Request
Constraints constraints = new Constraints.Builder().setRequiredNetworkType(NetworkType.UNMETERED).build();
PeriodicWorkRequest workRequest = new PeriodicWorkRequest.Builder(DatabaseCloudBackupWorker.class, 1, TimeUnit.DAYS)
.setInitialDelay(initialDelayInMinutes, TimeUnit.MINUTES)
.addTag(DatabaseCloudBackupWorker.TAG_PERIODIC_WORKER)
.setConstraints(constraints)
.setInputData(inputData)
.build();
//
WorkManager workManager = WorkManager.getInstance(MyApp.getAppContext());
Log.i(TAG, "Enqueuing DatabaseCloudBackupWorker");
Operation operation = workManager.enqueueUniquePeriodicWork(DatabaseCloudBackupWorker.NAME_PERIODIC, ExistingPeriodicWorkPolicy.UPDATE, workRequest);
Use below code for notifications.
If your Backup Data is working fine in Background, then use below code for notifications, it will work
You have to create channel for notifications in Android 8.1 and later.