From f189b7d885d03c9acf476b895b2ce964bbebdede Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Wed, 4 Mar 2026 12:48:14 -0500 Subject: [PATCH 1/6] Fix upload failures in UploadService and UploadWorker - Show toast when publishing without network instead of silently skipping - Recover interrupted media uploads (QUEUED/UPLOADING/FAILED) on service restart with loop prevention via process-lifetime tracking set - Wrap UploadWorker.doWork() in try/catch returning Result.retry() - Change network constraint from NOT_ROAMING to CONNECTED - Add exponential backoff policy (10 min) to work requests - Log warning when onPostUploaded receives event for untracked post Co-Authored-By: Claude Opus 4.6 --- .../android/ui/uploads/PostUploadHandler.java | 6 ++ .../android/ui/uploads/UploadService.java | 66 ++++++++++++++++++- .../android/ui/uploads/UploadUtils.java | 2 + .../wordpress/android/util/UploadWorker.kt | 33 +++++++--- 4 files changed, 97 insertions(+), 10 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/uploads/PostUploadHandler.java b/WordPress/src/main/java/org/wordpress/android/ui/uploads/PostUploadHandler.java index ccdb5534c0e2..7eda3b84c335 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/uploads/PostUploadHandler.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/uploads/PostUploadHandler.java @@ -662,6 +662,12 @@ public void handleAutoSavePostIfNotDraftResult(@NonNull AutoSavePostIfNotDraftRe public void onPostUploaded(OnPostUploaded event) { // check if the event is related to the PostModel that is being uploaded by PostUploadHandler if (!isPostUploading(event.post)) { + AppLog.w(T.POSTS, "PostUploadHandler > onPostUploaded for untracked post" + + " (postId=" + (event.post != null ? event.post.getId() : "null") + "," + + " currentUploadingPostId=" + + (sCurrentUploadingPost != null ? sCurrentUploadingPost.getId() : "null") + + (event.isError() ? ", error=" + event.error.type + + ": " + event.error.message : "") + ")"); return; } SiteModel site = mSiteStore.getSiteByLocalId(event.post.getLocalSiteId()); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java index ee9fef5329f9..15613be5b04c 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java @@ -50,6 +50,7 @@ import org.wordpress.android.util.ToastUtils; import org.wordpress.android.util.WPMediaUtils; +import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -83,6 +84,9 @@ public class UploadService extends Service { // for media that the user actively cancelled uploads for private static HashSet mUserDeletedMediaItemIds = new HashSet<>(); + // tracks media IDs that have already been recovered to prevent recovery loops + private static final Set RECOVERED_MEDIA_IDS = new HashSet<>(); + @Inject Dispatcher mDispatcher; @Inject MediaStore mMediaStore; @@ -99,8 +103,6 @@ public void onCreate() { AppLog.i(T.MAIN, "UploadService > Created"); mDispatcher.register(this); sInstance = this; - // TODO: Recover any posts/media uploads that were interrupted by the service being stopped - if (mMediaUploadHandler == null) { mMediaUploadHandler = new MediaUploadHandler(); } @@ -112,6 +114,66 @@ public void onCreate() { if (mPostUploadHandler == null) { mPostUploadHandler = new PostUploadHandler(mPostUploadNotifier); } + + recoverInterruptedMediaUploads(); + } + + /** + * Recovers media uploads that were interrupted when the service was killed. + * Re-queues QUEUED and UPLOADING media, and retries FAILED media that is + * bound to a post and still has a valid local file. + */ + private void recoverInterruptedMediaUploads() { + List recoveredMedia = new ArrayList<>(); + for (SiteModel site : mSiteStore.getSites()) { + List queuedMedia = mMediaStore.getSiteMediaWithState( + site, MediaUploadState.QUEUED); + for (MediaModel media : queuedMedia) { + if (RECOVERED_MEDIA_IDS.add(media.getId())) { + recoveredMedia.add(media); + } + } + + List uploadingMedia = mMediaStore.getSiteMediaWithState( + site, MediaUploadState.UPLOADING); + for (MediaModel media : uploadingMedia) { + if (RECOVERED_MEDIA_IDS.add(media.getId())) { + media.setUploadState(MediaUploadState.QUEUED.name()); + mDispatcher.dispatch( + MediaActionBuilder.newUpdateMediaAction(media)); + recoveredMedia.add(media); + } + } + + List failedMedia = mMediaStore.getSiteMediaWithState( + site, MediaUploadState.FAILED); + for (MediaModel media : failedMedia) { + if (RECOVERED_MEDIA_IDS.add(media.getId()) + && media.getLocalPostId() > 0 + && hasValidFile(media)) { + media.setUploadState(MediaUploadState.QUEUED.name()); + mDispatcher.dispatch( + MediaActionBuilder.newUpdateMediaAction(media)); + recoveredMedia.add(media); + } + } + } + + if (!recoveredMedia.isEmpty()) { + AppLog.i(T.MAIN, "UploadService > Recovering " + + recoveredMedia.size() + " interrupted media uploads"); + registerPostModelsForMedia(recoveredMedia, false); + for (MediaModel media : recoveredMedia) { + mMediaUploadHandler.upload(media); + } + mPostUploadNotifier + .addMediaInfoToForegroundNotification(recoveredMedia); + } + } + + private static boolean hasValidFile(@NonNull MediaModel media) { + String filePath = media.getFilePath(); + return filePath != null && new File(filePath).exists(); } @Override diff --git a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadUtils.java b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadUtils.java index 01acbd97fc0c..83cd6f7b29a8 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadUtils.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadUtils.java @@ -459,6 +459,8 @@ public static void publishPost(Activity activity, final PostModel post, SiteMode if (onPublishingCallback != null) { onPublishingCallback.onPublishing(isFirstTimePublish); } + } else { + ToastUtils.showToast(activity, R.string.no_network_message, ToastUtils.Duration.SHORT); } PostUtils.trackSavePostAnalytics(post, site); } diff --git a/WordPress/src/main/java/org/wordpress/android/util/UploadWorker.kt b/WordPress/src/main/java/org/wordpress/android/util/UploadWorker.kt index de72c5a5f861..d244bea0d1e8 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/UploadWorker.kt +++ b/WordPress/src/main/java/org/wordpress/android/util/UploadWorker.kt @@ -1,6 +1,7 @@ package org.wordpress.android.util import android.content.Context +import androidx.work.BackoffPolicy import androidx.work.Constraints import androidx.work.ExistingPeriodicWorkPolicy import androidx.work.ExistingWorkPolicy @@ -21,6 +22,7 @@ import org.wordpress.android.fluxc.model.SiteModel import org.wordpress.android.fluxc.store.SiteStore import org.wordpress.android.ui.uploads.UploadStarter import java.util.concurrent.TimeUnit.HOURS +import java.util.concurrent.TimeUnit.MINUTES class UploadWorker( appContext: Context, @@ -32,17 +34,30 @@ class UploadWorker( private const val UPLOAD_FROM_ALL_SITES = -1 } + @Suppress("TooGenericExceptionCaught") override fun doWork(): Result { AppLog.i(AppLog.T.MAIN, "UploadWorker started") - runBlocking { - val job = when (val localSiteId = inputData.getInt(WordPress.LOCAL_SITE_ID, UPLOAD_FROM_ALL_SITES)) { - UPLOAD_FROM_ALL_SITES -> uploadStarter.queueUploadFromAllSites() - else -> siteStore.getSiteByLocalId(localSiteId)?.let { uploadStarter.queueUploadFromSite(it) } + return try { + runBlocking { + val job = when ( + val localSiteId = inputData.getInt( + WordPress.LOCAL_SITE_ID, + UPLOAD_FROM_ALL_SITES + ) + ) { + UPLOAD_FROM_ALL_SITES -> uploadStarter.queueUploadFromAllSites() + else -> siteStore.getSiteByLocalId(localSiteId)?.let { + uploadStarter.queueUploadFromSite(it) + } + } + job?.join() } - job?.join() + AppLog.i(AppLog.T.MAIN, "UploadWorker finished") + Result.success() + } catch (e: Exception) { + AppLog.e(AppLog.T.MAIN, "UploadWorker failed", e) + Result.retry() } - AppLog.i(AppLog.T.MAIN, "UploadWorker finished") - return Result.success() } class Factory( @@ -65,13 +80,14 @@ class UploadWorker( private fun getUploadConstraints(): Constraints { return Constraints.Builder() - .setRequiredNetworkType(NetworkType.NOT_ROAMING) + .setRequiredNetworkType(NetworkType.CONNECTED) .build() } fun enqueueUploadWorkRequestForSite(site: SiteModel): Pair { val request = OneTimeWorkRequestBuilder() .setConstraints(getUploadConstraints()) + .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, MINUTES) .setInputData(workDataOf(WordPress.LOCAL_SITE_ID to site.id)) .build() val operation = WorkManager.getInstance(WordPress.getContext()).enqueueUniqueWork( @@ -84,6 +100,7 @@ fun enqueueUploadWorkRequestForSite(site: SiteModel): Pair { val request = PeriodicWorkRequestBuilder(8, HOURS, 6, HOURS) .setConstraints(getUploadConstraints()) + .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, MINUTES) .build() val operation = WorkManager.getInstance(WordPress.getContext()).enqueueUniquePeriodicWork( "periodic auto-upload", From 8ee630f38f2c0d5d6dccc9934126d1666010b0a4 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Wed, 4 Mar 2026 13:03:25 -0500 Subject: [PATCH 2/6] Simplify upload code: remove dead code and use idiomatic Kotlin - Remove stale TODO and 18 lines of commented-out recovery code in unpackMediaIntent(), now superseded by recoverInterruptedMediaUploads() - Remove double blank line in UploadService - Use string template in UploadWorker - Use expression-body for getUploadConstraints() Co-Authored-By: Claude Opus 4.6 --- .../android/ui/uploads/UploadService.java | 27 ------------------- .../wordpress/android/util/UploadWorker.kt | 10 +++---- 2 files changed, 4 insertions(+), 33 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java index 15613be5b04c..016360f6f783 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java @@ -87,7 +87,6 @@ public class UploadService extends Service { // tracks media IDs that have already been recovered to prevent recovery loops private static final Set RECOVERED_MEDIA_IDS = new HashSet<>(); - @Inject Dispatcher mDispatcher; @Inject MediaStore mMediaStore; @Inject PostStore mPostStore; @@ -241,32 +240,6 @@ public void onTimeout(int startId) { } private void unpackMediaIntent(@NonNull Intent intent) { - // TODO right now, in the case we had pending uploads and the app/service was restarted, - // we don't really have a way to tell which media was supposed to be added to which post, - // unless we open each draft post from the PostStore and try to see if there was any locally added media to try - // and match their IDs. - // So let's hold on a bit on this functionality, the service won't be recovering any - // pending / missing / cancelled / interrupted uploads for now - -// // add local queued media from store -// List localMedia = mMediaStore.getLocalSiteMedia(site); -// if (localMedia != null && !localMedia.isEmpty()) { -// // uploading is updated to queued, queued media added to the queue, failed media added to completed list -// for (MediaModel mediaItem : localMedia) { -// -// if (MediaUploadState.UPLOADING.name().equals(mediaItem.getUploadState())) { -// mediaItem.setUploadState(MediaUploadState.QUEUED.name()); -// mDispatcher.dispatch(MediaActionBuilder.newUpdateMediaAction(mediaItem)); -// } -// -// if (MediaUploadState.QUEUED.name().equals(mediaItem.getUploadState())) { -// addUniqueMediaToQueue(mediaItem); -// } else if (MediaUploadState.FAILED.name().equals(mediaItem.getUploadState())) { -// getCompletedItems().add(mediaItem); -// } -// } -// } - // add new media @SuppressWarnings("unchecked") List mediaList = (List) intent.getSerializableExtra(KEY_MEDIA_LIST); diff --git a/WordPress/src/main/java/org/wordpress/android/util/UploadWorker.kt b/WordPress/src/main/java/org/wordpress/android/util/UploadWorker.kt index d244bea0d1e8..94e09d39761e 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/UploadWorker.kt +++ b/WordPress/src/main/java/org/wordpress/android/util/UploadWorker.kt @@ -78,11 +78,9 @@ class UploadWorker( } } -private fun getUploadConstraints(): Constraints { - return Constraints.Builder() - .setRequiredNetworkType(NetworkType.CONNECTED) - .build() -} +private fun getUploadConstraints() = Constraints.Builder() + .setRequiredNetworkType(NetworkType.CONNECTED) + .build() fun enqueueUploadWorkRequestForSite(site: SiteModel): Pair { val request = OneTimeWorkRequestBuilder() @@ -91,7 +89,7 @@ fun enqueueUploadWorkRequestForSite(site: SiteModel): Pair Date: Wed, 4 Mar 2026 13:24:50 -0500 Subject: [PATCH 3/6] Fix detekt MagicNumber violation in UploadWorker Extract backoff delay literal to a named constant. Co-Authored-By: Claude Opus 4.6 --- .../main/java/org/wordpress/android/util/UploadWorker.kt | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/util/UploadWorker.kt b/WordPress/src/main/java/org/wordpress/android/util/UploadWorker.kt index 94e09d39761e..c9dd8bbe6d06 100644 --- a/WordPress/src/main/java/org/wordpress/android/util/UploadWorker.kt +++ b/WordPress/src/main/java/org/wordpress/android/util/UploadWorker.kt @@ -78,6 +78,8 @@ class UploadWorker( } } +private const val BACKOFF_DELAY_MINUTES = 10L + private fun getUploadConstraints() = Constraints.Builder() .setRequiredNetworkType(NetworkType.CONNECTED) .build() @@ -85,7 +87,7 @@ private fun getUploadConstraints() = Constraints.Builder() fun enqueueUploadWorkRequestForSite(site: SiteModel): Pair { val request = OneTimeWorkRequestBuilder() .setConstraints(getUploadConstraints()) - .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, MINUTES) + .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, BACKOFF_DELAY_MINUTES, MINUTES) .setInputData(workDataOf(WordPress.LOCAL_SITE_ID to site.id)) .build() val operation = WorkManager.getInstance(WordPress.getContext()).enqueueUniqueWork( @@ -98,7 +100,7 @@ fun enqueueUploadWorkRequestForSite(site: SiteModel): Pair { val request = PeriodicWorkRequestBuilder(8, HOURS, 6, HOURS) .setConstraints(getUploadConstraints()) - .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, 10, MINUTES) + .setBackoffCriteria(BackoffPolicy.EXPONENTIAL, BACKOFF_DELAY_MINUTES, MINUTES) .build() val operation = WorkManager.getInstance(WordPress.getContext()).enqueueUniquePeriodicWork( "periodic auto-upload", From b1f460f51f666f334e0bf9e836274e099faa8a80 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Wed, 4 Mar 2026 13:29:56 -0500 Subject: [PATCH 4/6] Reduce cognitive complexity of recoverInterruptedMediaUploads Extract helper methods to flatten nested loops and conditionals: - recoverMediaForSite() handles per-site recovery - collectNewMedia() and collectAndResetMedia() handle queue collection - resetToQueued() consolidates state reset + dispatch Co-Authored-By: Claude Opus 4.6 --- .../android/ui/uploads/UploadService.java | 94 ++++++++++++------- 1 file changed, 59 insertions(+), 35 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java index 016360f6f783..c4126e5b7794 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java @@ -125,51 +125,75 @@ public void onCreate() { private void recoverInterruptedMediaUploads() { List recoveredMedia = new ArrayList<>(); for (SiteModel site : mSiteStore.getSites()) { - List queuedMedia = mMediaStore.getSiteMediaWithState( - site, MediaUploadState.QUEUED); - for (MediaModel media : queuedMedia) { - if (RECOVERED_MEDIA_IDS.add(media.getId())) { - recoveredMedia.add(media); - } - } + recoverMediaForSite(site, recoveredMedia); + } - List uploadingMedia = mMediaStore.getSiteMediaWithState( - site, MediaUploadState.UPLOADING); - for (MediaModel media : uploadingMedia) { - if (RECOVERED_MEDIA_IDS.add(media.getId())) { - media.setUploadState(MediaUploadState.QUEUED.name()); - mDispatcher.dispatch( - MediaActionBuilder.newUpdateMediaAction(media)); - recoveredMedia.add(media); - } + if (recoveredMedia.isEmpty()) { + return; + } + + AppLog.i(T.MAIN, "UploadService > Recovering " + + recoveredMedia.size() + " interrupted media uploads"); + registerPostModelsForMedia(recoveredMedia, false); + for (MediaModel media : recoveredMedia) { + mMediaUploadHandler.upload(media); + } + mPostUploadNotifier + .addMediaInfoToForegroundNotification(recoveredMedia); + } + + private void recoverMediaForSite( + @NonNull SiteModel site, + @NonNull List out + ) { + collectNewMedia( + mMediaStore.getSiteMediaWithState(site, MediaUploadState.QUEUED), + out + ); + collectAndResetMedia( + mMediaStore.getSiteMediaWithState(site, MediaUploadState.UPLOADING), + out + ); + + for (MediaModel media : mMediaStore.getSiteMediaWithState(site, MediaUploadState.FAILED)) { + if (!RECOVERED_MEDIA_IDS.add(media.getId())) { + continue; } + if (media.getLocalPostId() > 0 && hasValidFile(media)) { + resetToQueued(media); + out.add(media); + } + } + } - List failedMedia = mMediaStore.getSiteMediaWithState( - site, MediaUploadState.FAILED); - for (MediaModel media : failedMedia) { - if (RECOVERED_MEDIA_IDS.add(media.getId()) - && media.getLocalPostId() > 0 - && hasValidFile(media)) { - media.setUploadState(MediaUploadState.QUEUED.name()); - mDispatcher.dispatch( - MediaActionBuilder.newUpdateMediaAction(media)); - recoveredMedia.add(media); - } + private void collectNewMedia( + @NonNull List source, + @NonNull List out + ) { + for (MediaModel media : source) { + if (RECOVERED_MEDIA_IDS.add(media.getId())) { + out.add(media); } } + } - if (!recoveredMedia.isEmpty()) { - AppLog.i(T.MAIN, "UploadService > Recovering " - + recoveredMedia.size() + " interrupted media uploads"); - registerPostModelsForMedia(recoveredMedia, false); - for (MediaModel media : recoveredMedia) { - mMediaUploadHandler.upload(media); + private void collectAndResetMedia( + @NonNull List source, + @NonNull List out + ) { + for (MediaModel media : source) { + if (RECOVERED_MEDIA_IDS.add(media.getId())) { + resetToQueued(media); + out.add(media); } - mPostUploadNotifier - .addMediaInfoToForegroundNotification(recoveredMedia); } } + private void resetToQueued(@NonNull MediaModel media) { + media.setUploadState(MediaUploadState.QUEUED.name()); + mDispatcher.dispatch(MediaActionBuilder.newUpdateMediaAction(media)); + } + private static boolean hasValidFile(@NonNull MediaModel media) { String filePath = media.getFilePath(); return filePath != null && new File(filePath).exists(); From e47b9917f28236a093d8ce598bf8b85708671560 Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 5 Mar 2026 07:33:51 -0500 Subject: [PATCH 5/6] Fix media upload recovery race condition Remove startup sanitizeMediaUploadStateForSite() call that races with UploadService.onCreate() recovery, marking media as FAILED before it can be re-queued. Also remove hasValidFile() guard from FAILED media recovery since it rejects content:// URIs and large cached files. Co-Authored-By: Claude Opus 4.6 --- .../src/main/java/org/wordpress/android/AppInitializer.kt | 3 --- .../org/wordpress/android/ui/uploads/UploadService.java | 8 +------- 2 files changed, 1 insertion(+), 10 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/AppInitializer.kt b/WordPress/src/main/java/org/wordpress/android/AppInitializer.kt index 186a8fe287bf..c50324b65155 100644 --- a/WordPress/src/main/java/org/wordpress/android/AppInitializer.kt +++ b/WordPress/src/main/java/org/wordpress/android/AppInitializer.kt @@ -356,9 +356,6 @@ class AppInitializer @Inject constructor( AppCompatDelegate.setCompatVectorFromResourcesEnabled(true) AppThemeUtils.setAppTheme(application) - // verify media is sanitized - sanitizeMediaUploadStateForSite() - // remove expired lists dispatcher.dispatch(ListActionBuilder.newRemoveExpiredListsAction(RemoveExpiredListsPayload())) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java index c4126e5b7794..5997339da7eb 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java @@ -50,7 +50,6 @@ import org.wordpress.android.util.ToastUtils; import org.wordpress.android.util.WPMediaUtils; -import java.io.File; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; @@ -159,7 +158,7 @@ private void recoverMediaForSite( if (!RECOVERED_MEDIA_IDS.add(media.getId())) { continue; } - if (media.getLocalPostId() > 0 && hasValidFile(media)) { + if (media.getLocalPostId() > 0) { resetToQueued(media); out.add(media); } @@ -194,11 +193,6 @@ private void resetToQueued(@NonNull MediaModel media) { mDispatcher.dispatch(MediaActionBuilder.newUpdateMediaAction(media)); } - private static boolean hasValidFile(@NonNull MediaModel media) { - String filePath = media.getFilePath(); - return filePath != null && new File(filePath).exists(); - } - @Override public void onDestroy() { if (mMediaUploadHandler != null) { From bbce4e0919d0c6e54116fd304f89dc8fc4be0a4d Mon Sep 17 00:00:00 2001 From: Nick Bradbury Date: Thu, 5 Mar 2026 09:49:44 -0500 Subject: [PATCH 6/6] Simplify upload recovery code Remove unnecessary null checks in onCreate(), merge duplicate collectNewMedia/collectAndResetMedia into a single collectMedia() method, fix stale Javadoc, and use String.format for log message. Co-Authored-By: Claude Opus 4.6 --- .../android/ui/uploads/PostUploadHandler.java | 15 ++++--- .../android/ui/uploads/UploadService.java | 44 ++++++------------- 2 files changed, 23 insertions(+), 36 deletions(-) diff --git a/WordPress/src/main/java/org/wordpress/android/ui/uploads/PostUploadHandler.java b/WordPress/src/main/java/org/wordpress/android/ui/uploads/PostUploadHandler.java index 7eda3b84c335..e70277e1c8bd 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/uploads/PostUploadHandler.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/uploads/PostUploadHandler.java @@ -662,12 +662,15 @@ public void handleAutoSavePostIfNotDraftResult(@NonNull AutoSavePostIfNotDraftRe public void onPostUploaded(OnPostUploaded event) { // check if the event is related to the PostModel that is being uploaded by PostUploadHandler if (!isPostUploading(event.post)) { - AppLog.w(T.POSTS, "PostUploadHandler > onPostUploaded for untracked post" - + " (postId=" + (event.post != null ? event.post.getId() : "null") + "," - + " currentUploadingPostId=" - + (sCurrentUploadingPost != null ? sCurrentUploadingPost.getId() : "null") - + (event.isError() ? ", error=" + event.error.type - + ": " + event.error.message : "") + ")"); + AppLog.w(T.POSTS, String.format( + "PostUploadHandler > onPostUploaded for untracked post" + + " (postId=%s, currentUploadingPostId=%s%s)", + event.post != null ? event.post.getId() : "null", + sCurrentUploadingPost != null + ? sCurrentUploadingPost.getId() : "null", + event.isError() + ? ", error=" + event.error.type + ": " + event.error.message + : "")); return; } SiteModel site = mSiteStore.getSiteByLocalId(event.post.getLocalSiteId()); diff --git a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java index 5997339da7eb..cbf8d0fbde56 100644 --- a/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java +++ b/WordPress/src/main/java/org/wordpress/android/ui/uploads/UploadService.java @@ -101,17 +101,9 @@ public void onCreate() { AppLog.i(T.MAIN, "UploadService > Created"); mDispatcher.register(this); sInstance = this; - if (mMediaUploadHandler == null) { - mMediaUploadHandler = new MediaUploadHandler(); - } - - if (mPostUploadNotifier == null) { - mPostUploadNotifier = new PostUploadNotifier(getApplicationContext(), this, mSystemNotificationsTracker); - } - - if (mPostUploadHandler == null) { - mPostUploadHandler = new PostUploadHandler(mPostUploadNotifier); - } + mMediaUploadHandler = new MediaUploadHandler(); + mPostUploadNotifier = new PostUploadNotifier(getApplicationContext(), this, mSystemNotificationsTracker); + mPostUploadHandler = new PostUploadHandler(mPostUploadNotifier); recoverInterruptedMediaUploads(); } @@ -119,7 +111,7 @@ public void onCreate() { /** * Recovers media uploads that were interrupted when the service was killed. * Re-queues QUEUED and UPLOADING media, and retries FAILED media that is - * bound to a post and still has a valid local file. + * bound to a post. */ private void recoverInterruptedMediaUploads() { List recoveredMedia = new ArrayList<>(); @@ -145,13 +137,13 @@ private void recoverMediaForSite( @NonNull SiteModel site, @NonNull List out ) { - collectNewMedia( + collectMedia( mMediaStore.getSiteMediaWithState(site, MediaUploadState.QUEUED), - out + out, false ); - collectAndResetMedia( + collectMedia( mMediaStore.getSiteMediaWithState(site, MediaUploadState.UPLOADING), - out + out, true ); for (MediaModel media : mMediaStore.getSiteMediaWithState(site, MediaUploadState.FAILED)) { @@ -165,24 +157,16 @@ private void recoverMediaForSite( } } - private void collectNewMedia( - @NonNull List source, - @NonNull List out - ) { - for (MediaModel media : source) { - if (RECOVERED_MEDIA_IDS.add(media.getId())) { - out.add(media); - } - } - } - - private void collectAndResetMedia( + private void collectMedia( @NonNull List source, - @NonNull List out + @NonNull List out, + boolean resetState ) { for (MediaModel media : source) { if (RECOVERED_MEDIA_IDS.add(media.getId())) { - resetToQueued(media); + if (resetState) { + resetToQueued(media); + } out.add(media); } }