1111import androidx .annotation .Nullable ;
1212import androidx .collection .SparseArrayCompat ;
1313import androidx .core .app .NotificationCompat ;
14+ import androidx .core .app .ServiceCompat ;
1415import androidx .core .app .TaskStackBuilder ;
1516
1617import org .greenrobot .eventbus .EventBus ;
@@ -128,9 +129,7 @@ private void updateNotificationBuilder(@Nullable PostImmutableModel post) {
128129 }
129130
130131 private synchronized void startOrUpdateForegroundNotification (@ Nullable PostImmutableModel post ) {
131- boolean isTotalPostsAndMediaItemsCountZero = sNotificationData .mTotalPostItems == 0
132- && sNotificationData .mTotalMediaItems == 0 ;
133- if (isTotalPostsAndMediaItemsCountZero ) {
132+ if (hasNoForegroundItemsTracked ()) {
134133 return ;
135134 }
136135 updateNotificationBuilder (post );
@@ -214,6 +213,12 @@ void incrementUploadedPostCountFromForegroundNotification(@NonNull PostImmutable
214213 }
215214
216215 void incrementUploadedPostCountFromForegroundNotification (@ NonNull PostImmutableModel post , boolean force ) {
216+ // Ignore stale completion callbacks that arrive after the foreground state was reset (e.g.
217+ // cancellations dispatched during a foreground-service timeout). With nothing being tracked,
218+ // counting them would push the current counters past the zeroed totals and corrupt the state.
219+ if (hasNoForegroundItemsTracked ()) {
220+ return ;
221+ }
217222 // first we need to check that we only count this post once as "ended" (either successfully or with error)
218223 // for every error we get. We'll then try to increment the Post count as it's been cancelled/failed because the
219224 // related media was cancelled or has failed too (i.e. we can't upload a Post with failed media, therefore
@@ -232,6 +237,11 @@ void incrementUploadedPostCountFromForegroundNotification(@NonNull PostImmutable
232237 }
233238
234239 void incrementUploadedMediaCountFromProgressNotification (int mediaId ) {
240+ // Ignore stale completion callbacks that arrive after the foreground state was reset (see
241+ // incrementUploadedPostCountFromForegroundNotification above).
242+ if (hasNoForegroundItemsTracked ()) {
243+ return ;
244+ }
235245 sNotificationData .mCurrentMediaItem ++;
236246 if (!removeNotificationAndStopForegroundServiceIfNoItemsInQueue ()) {
237247 // update Notification now
@@ -242,16 +252,32 @@ void incrementUploadedMediaCountFromProgressNotification(int mediaId) {
242252 private boolean removeNotificationAndStopForegroundServiceIfNoItemsInQueue () {
243253 if (sNotificationData .mCurrentPostItem == sNotificationData .mTotalPostItems
244254 && sNotificationData .mCurrentMediaItem == sNotificationData .mTotalMediaItems ) {
245- mNotificationManager .cancel (sNotificationData .mNotificationId );
246- // reset the notification id so a new one is generated next time the service is started
247- sNotificationData .mNotificationId = 0 ;
248- resetNotificationCounters ();
249- mService .stopForeground (true );
255+ resetForegroundNotificationState ();
256+ ServiceCompat .stopForeground (mService , ServiceCompat .STOP_FOREGROUND_REMOVE );
250257 return true ;
251258 }
252259 return false ;
253260 }
254261
262+ private boolean hasNoForegroundItemsTracked () {
263+ return sNotificationData .mTotalPostItems == 0 && sNotificationData .mTotalMediaItems == 0 ;
264+ }
265+
266+ /**
267+ * Clears the outstanding foreground notification and resets its state. Called both when all
268+ * uploads complete and when the service is force-stopped (e.g. a foreground-service timeout),
269+ * so the next upload starts a fresh foreground notification via startForeground().
270+ */
271+ void resetForegroundNotificationState () {
272+ if (sNotificationData .mNotificationId != 0 ) {
273+ // cancel the outstanding notification and reset the id so a new one is generated next
274+ // time the service is started
275+ mNotificationManager .cancel (sNotificationData .mNotificationId );
276+ sNotificationData .mNotificationId = 0 ;
277+ }
278+ resetNotificationCounters ();
279+ }
280+
255281 private void resetNotificationCounters () {
256282 sNotificationData .mCurrentPostItem = 0 ;
257283 sNotificationData .mCurrentMediaItem = 0 ;
0 commit comments