From 1a80ef74aca79b283667974ad4e80085db08b124 Mon Sep 17 00:00:00 2001 From: J4tinP Date: Tue, 23 Dec 2025 14:29:25 +0400 Subject: [PATCH 1/4] Add ForegroundInfo support for upload notifications --- src/android/UploadNotification.java | 17 +++++++++++++++-- src/android/UploadTask.java | 16 ++++++++++++++-- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/src/android/UploadNotification.java b/src/android/UploadNotification.java index 092ce707..e3fd5cc5 100644 --- a/src/android/UploadNotification.java +++ b/src/android/UploadNotification.java @@ -14,8 +14,10 @@ import androidx.annotation.IntegerRes; import androidx.annotation.RequiresApi; import androidx.core.app.NotificationCompat; +import androidx.work.ForegroundInfo; import androidx.work.WorkInfo; import androidx.work.WorkManager; +import android.content.pm.ServiceInfo; import java.util.Collections; import java.util.List; @@ -82,7 +84,7 @@ public static Notification createNotification(NotificationCompat.Builder notific Notification notification = notificationBuilder.build(); notification.flags |= Notification.FLAG_NO_CLEAR; notification.flags |= Notification.FLAG_ONGOING_EVENT; - return notification; + return notification; } @RequiresApi(api = Build.VERSION_CODES.O) @@ -103,7 +105,9 @@ private static NotificationCompat.Builder getUploadNotification(final Context co PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, notificationIntent, pendingIntentFlag); // TODO: click intent open app - @SuppressLint("ResourceType") NotificationCompat.Builder uploadNotificationBuilder = new NotificationCompat.Builder(context, UploadTask.NOTIFICATION_CHANNEL_ID) + @SuppressLint("ResourceType") + NotificationCompat.Builder uploadNotificationBuilder = new NotificationCompat.Builder(context, + UploadTask.NOTIFICATION_CHANNEL_ID) .setContentTitle(notificationTitle) .setTicker(notificationTitle) .setSmallIcon(notificationIconRes) @@ -117,4 +121,13 @@ private static NotificationCompat.Builder getUploadNotification(final Context co return uploadNotificationBuilder; } + + public ForegroundInfo getForegroundInfo() { + if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + return new ForegroundInfo(notificationId, notificationBuilder.build(), + ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC); + } else { + return new ForegroundInfo(notificationId, notificationBuilder.build()); + } + } } diff --git a/src/android/UploadTask.java b/src/android/UploadTask.java index 9fd1c5c0..b7bf2e75 100644 --- a/src/android/UploadTask.java +++ b/src/android/UploadTask.java @@ -7,6 +7,7 @@ import android.webkit.MimeTypeMap; import androidx.annotation.NonNull; +import androidx.work.ForegroundInfo; import androidx.work.Data; import androidx.work.Worker; import androidx.work.WorkerParameters; @@ -155,7 +156,7 @@ public UploadTask(@NonNull Context context, @NonNull WorkerParameters workerPara @NonNull @Override public Result doWork() { - if(!hasNetworkConnection()) { + if (!hasNetworkConnection()) { return Result.retry(); } @@ -395,12 +396,23 @@ private void handleNotification() { Log.d(TAG, "Upload Notification"); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { setForegroundAsync(uploadForegroundNotification.getForegroundInfo(getApplicationContext())); - } else { + } else { uploadNotification.updateProgress(); } Log.d(TAG, "Upload Notification Exit"); } + @NonNull + @Override + public ForegroundInfo getForegroundInfo() { + Log.d(TAG, "getForegroundInfo: Promoting to foreground service"); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + return uploadForegroundNotification.getForegroundInfo(getApplicationContext()); + } else { + return uploadNotification.getForegroundInfo(); + } + } + private synchronized boolean hasNetworkConnection() { ConnectivityManager connectivityManager = (ConnectivityManager) getApplicationContext().getSystemService(Context.CONNECTIVITY_SERVICE); if((connectivityManager == null) || (connectivityManager.getActiveNetworkInfo() == null) || (connectivityManager.getActiveNetworkInfo().isConnectedOrConnecting() == false)) { From 9a2f821edf63f990939918e8fcf819ad2c621ebb Mon Sep 17 00:00:00 2001 From: J4tinP Date: Mon, 5 Jan 2026 11:14:06 +0400 Subject: [PATCH 2/4] Refactor code --- src/android/UploadNotification.java | 6 +++--- src/android/UploadTask.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/android/UploadNotification.java b/src/android/UploadNotification.java index e3fd5cc5..c970a751 100644 --- a/src/android/UploadNotification.java +++ b/src/android/UploadNotification.java @@ -126,8 +126,8 @@ public ForegroundInfo getForegroundInfo() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { return new ForegroundInfo(notificationId, notificationBuilder.build(), ServiceInfo.FOREGROUND_SERVICE_TYPE_DATA_SYNC); - } else { - return new ForegroundInfo(notificationId, notificationBuilder.build()); - } + } + + return new ForegroundInfo(notificationId, notificationBuilder.build()); } } diff --git a/src/android/UploadTask.java b/src/android/UploadTask.java index b7bf2e75..2bb7a681 100644 --- a/src/android/UploadTask.java +++ b/src/android/UploadTask.java @@ -408,9 +408,9 @@ public ForegroundInfo getForegroundInfo() { Log.d(TAG, "getForegroundInfo: Promoting to foreground service"); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { return uploadForegroundNotification.getForegroundInfo(getApplicationContext()); - } else { - return uploadNotification.getForegroundInfo(); - } + } + + return uploadNotification.getForegroundInfo(); } private synchronized boolean hasNetworkConnection() { From d5a86cb7f19ea3bf0e5df63b570f0051528cfc4f Mon Sep 17 00:00:00 2001 From: Jatin Purmessur Date: Wed, 14 Jan 2026 11:39:22 +0400 Subject: [PATCH 3/4] Update src/android/UploadTask.java Co-authored-by: Mouhammad Hashir Hassam Rajah <99130092+HashirRajah@users.noreply.github.com> --- src/android/UploadTask.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/android/UploadTask.java b/src/android/UploadTask.java index 2bb7a681..ec57fe36 100644 --- a/src/android/UploadTask.java +++ b/src/android/UploadTask.java @@ -405,7 +405,6 @@ private void handleNotification() { @NonNull @Override public ForegroundInfo getForegroundInfo() { - Log.d(TAG, "getForegroundInfo: Promoting to foreground service"); if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { return uploadForegroundNotification.getForegroundInfo(getApplicationContext()); } From cc7bc88de324bef64dd41dde3977185435880e8a Mon Sep 17 00:00:00 2001 From: parveshneedhoo Date: Thu, 15 Jan 2026 17:17:59 +0400 Subject: [PATCH 4/4] test background upload --- plugin.xml | 2 ++ src/android/UploadTask.java | 18 ++++++++++++++---- 2 files changed, 16 insertions(+), 4 deletions(-) diff --git a/plugin.xml b/plugin.xml index 69290c1d..340a7941 100644 --- a/plugin.xml +++ b/plugin.xml @@ -35,6 +35,8 @@ + + diff --git a/src/android/UploadTask.java b/src/android/UploadTask.java index ec57fe36..f2361fb9 100644 --- a/src/android/UploadTask.java +++ b/src/android/UploadTask.java @@ -195,9 +195,16 @@ public Result doWork() { } startTime = System.currentTimeMillis(); - // Register me - uploadForegroundNotification.progress(getId(), 0f); - handleNotification(); + // Register me and start foreground service IMMEDIATELY + // This must be done before any blocking operations to ensure uploads continue when app is killed + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + uploadForegroundNotification.progress(getId(), 0f); + setForegroundAsync(uploadForegroundNotification.getForegroundInfo(getApplicationContext())); + } else { + // Android 12+: Still need to start foreground service for WorkManager to continue after app kill + uploadNotification.updateProgress(); + setForegroundAsync(uploadNotification.getForegroundInfo()); + } // Start call currentCall = httpClient.newCall(request); @@ -306,7 +313,10 @@ private void handleProgress(long bytesWritten, long totalBytes) { } float percent = (float) bytesWritten / (float) totalBytes; - UploadForegroundNotification.progress(getId(), percent); + if (Build.VERSION.SDK_INT < Build.VERSION_CODES.S) { + UploadForegroundNotification.progress(getId(), percent); + } + // On Android 12+, progress is tracked via WorkManager progress data Log.i(TAG, "handleProgress: " + getId() + " Progress: " + (int) (percent * 100f));