From 99f42a751719872f5b51f575daf5be9c8fcc29e6 Mon Sep 17 00:00:00 2001 From: Tyler Roach Date: Fri, 22 Jul 2022 16:12:17 -0400 Subject: [PATCH] Stop transfer service if all transfers complete (#2950) --- .../s3/transferutility/TransferService.java | 12 +++- .../s3/transferutility/TransferState.java | 6 ++ .../TransferStatusUpdater.java | 66 ++++++++++++------- 3 files changed, 57 insertions(+), 27 deletions(-) diff --git a/aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferService.java b/aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferService.java index f3695d863dc..0a070000421 100644 --- a/aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferService.java +++ b/aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferService.java @@ -49,14 +49,19 @@ public class TransferService extends Service { static TransferNetworkLossHandler transferNetworkLossHandler; /** - * A flag indicates whether the service is started the first time. + * A flag indicates whether or not the receiver has is started the first time. */ boolean isReceiverNotRegistered = true; + /** + * A flag that indicates whether or not the Foreground notification started + */ + boolean hasNotificationShown = false; + /** * The identifier used for the notification. */ - private int ongoingNotificationId = 1; + private int ongoingNotificationId = 3462; /** * This flag determines if the notification needs to be removed @@ -137,7 +142,8 @@ public int onStartCommand(Intent intent, int flags, int startId) { * b) An identifier for the ongoing notification c) Flag that determines if the notification * needs to be removed when the service is moved out of the foreground state. */ - if (Build.VERSION.SDK_INT >= ANDROID_OREO) { + if (Build.VERSION.SDK_INT >= ANDROID_OREO && !hasNotificationShown) { + hasNotificationShown = true; try { synchronized (this) { final Notification userProvidedNotification = (Notification) intent.getParcelableExtra(INTENT_KEY_NOTIFICATION); diff --git a/aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferState.java b/aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferState.java index bcc301d7c07..7810f26552d 100644 --- a/aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferState.java +++ b/aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferState.java @@ -127,4 +127,10 @@ public static TransferState getState(String stateAsString) { + " transfer will be have state set to UNKNOWN."); return UNKNOWN; } + + protected static boolean isFinalState(TransferState transferState) { + return TransferState.COMPLETED.equals(transferState) || + TransferState.FAILED.equals(transferState) || + TransferState.CANCELED.equals(transferState); + } } diff --git a/aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferStatusUpdater.java b/aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferStatusUpdater.java index 14bf6d5ceb8..c8f26152722 100644 --- a/aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferStatusUpdater.java +++ b/aws-android-sdk-s3/src/main/java/com/amazonaws/mobileconnectors/s3/transferutility/TransferStatusUpdater.java @@ -16,6 +16,7 @@ package com.amazonaws.mobileconnectors.s3.transferutility; import android.content.Context; +import android.content.Intent; import android.os.Handler; import android.os.Looper; @@ -70,6 +71,11 @@ class TransferStatusUpdater { */ private final Handler mainHandler; + /** + * Context required to stop TransferService on all transfers completed + */ + private Context context; + /** * The Singleton instance. */ @@ -88,8 +94,9 @@ class TransferStatusUpdater { * The updater is made a singleton. Use #getInstance for getting * the object of the updater. */ - TransferStatusUpdater(TransferDBUtil dbUtilInstance) { + TransferStatusUpdater(TransferDBUtil dbUtilInstance, Context context) { dbUtil = dbUtilInstance; + this.context = context; mainHandler = new Handler(Looper.getMainLooper()); transfers = new ConcurrentHashMap(); } @@ -103,7 +110,7 @@ class TransferStatusUpdater { public static synchronized TransferStatusUpdater getInstance(Context context) { if (transferStatusUpdater == null) { dbUtil = new TransferDBUtil(context); - transferStatusUpdater = new TransferStatusUpdater(dbUtil); + transferStatusUpdater = new TransferStatusUpdater(dbUtil, context); } return transferStatusUpdater; } @@ -212,33 +219,44 @@ synchronized void updateState(final int id, final TransferState newState) { synchronized (LISTENERS) { final List list = LISTENERS.get(id); - if (list == null || list.isEmpty()) { - return; - } + if (list != null && !list.isEmpty()) { + // invoke TransferListener callback on main thread + for (final TransferListener l : list) { + // If instance is TransferStatusListener, post immediately. + // Posting to main thread can cause a missed status. + if (l instanceof TransferObserver.TransferStatusListener) { + l.onStateChanged(id, newState); + } else { + mainHandler.post(new Runnable() { + @Override + public void run() { + l.onStateChanged(id, newState); + } + }); + } + } - // invoke TransferListener callback on main thread - for (final TransferListener l : list) { - // If instance is TransferStatusListener, post immediately. - // Posting to main thread can cause a missed status. - if (l instanceof TransferObserver.TransferStatusListener) { - l.onStateChanged(id, newState); - } else { - mainHandler.post(new Runnable() { - @Override - public void run() { - l.onStateChanged(id, newState); - } - }); + // remove all LISTENERS when the transfer is in a final state so + // as to release resources ASAP. + if (TransferState.isFinalState(newState)) { + list.clear(); } } + } - // remove all LISTENERS when the transfer is in a final state so - // as to release resources ASAP. - if (TransferState.COMPLETED.equals(newState) || - TransferState.FAILED.equals(newState) || - TransferState.CANCELED.equals(newState)) { - list.clear(); + // If all transfers in local map are completed, + // stop TransferService to clear foreground notification + boolean stopTransferService = true; + for (TransferRecord record: transfers.values()) { + if (!TransferState.isFinalState(record.state)) { + stopTransferService = false; + LOGGER.info("Transfers still pending, keeping TransferService running."); } + break; + } + if (stopTransferService) { + LOGGER.info("All transfers in final state. Stopping TransferService"); + context.stopService(new Intent(context, TransferService.class)); } }