From 1580b12f952d365dc5a44236e3fb27050c1d77c8 Mon Sep 17 00:00:00 2001 From: Alex Baker Date: Wed, 16 Jan 2019 10:38:14 -0600 Subject: [PATCH] Limit number of active notifications --- app/src/main/java/org/tasks/Notifier.java | 7 +++ .../notifications/NotificationLimiter.java | 43 +++++++++++++++++++ .../notifications/NotificationManager.java | 20 ++++++--- 3 files changed, 65 insertions(+), 5 deletions(-) create mode 100644 app/src/main/java/org/tasks/notifications/NotificationLimiter.java diff --git a/app/src/main/java/org/tasks/Notifier.java b/app/src/main/java/org/tasks/Notifier.java index 27e455ec7..a7dc6eb80 100644 --- a/app/src/main/java/org/tasks/Notifier.java +++ b/app/src/main/java/org/tasks/Notifier.java @@ -2,7 +2,10 @@ package org.tasks; import static android.content.Intent.FLAG_ACTIVITY_MULTIPLE_TASK; import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; +import static com.google.common.collect.Iterables.skip; +import static com.google.common.collect.Lists.newArrayList; import static com.google.common.collect.Lists.transform; +import static org.tasks.notifications.NotificationManager.MAX_NOTIFICATIONS; import static org.tasks.time.DateTimeUtils.currentTimeMillis; import android.app.PendingIntent; @@ -145,6 +148,10 @@ public class Notifier { Timber.d("Triggering %s", notifications); } + if (notifications.size() > MAX_NOTIFICATIONS) { + notifications = newArrayList(skip(notifications, notifications.size() - MAX_NOTIFICATIONS)); + } + notificationManager.notifyTasks(notifications, alert, ringNonstop, ringFiveTimes); if (alert diff --git a/app/src/main/java/org/tasks/notifications/NotificationLimiter.java b/app/src/main/java/org/tasks/notifications/NotificationLimiter.java new file mode 100644 index 000000000..314e7ca54 --- /dev/null +++ b/app/src/main/java/org/tasks/notifications/NotificationLimiter.java @@ -0,0 +1,43 @@ +package org.tasks.notifications; + +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.Queue; + +class NotificationLimiter { + + private final Queue queue = new LinkedList<>(); + private final int maxSize; + private boolean summary = false; + + NotificationLimiter(int maxSize) { + this.maxSize = maxSize; + } + + synchronized List add(long id) { + if (id == NotificationManager.SUMMARY_NOTIFICATION_ID) { + summary = true; + } else { + remove(id); + queue.add(id); + } + List evicted = new ArrayList<>(); + for (int i = 0 ; i < size() - maxSize ; i++) { + evicted.add(queue.remove()); + } + return evicted; + } + + synchronized void remove(long id) { + if (id == NotificationManager.SUMMARY_NOTIFICATION_ID) { + summary = false; + } else { + queue.remove(id); + } + } + + private int size() { + return queue.size() + (summary ? 1 : 0); + } +} diff --git a/app/src/main/java/org/tasks/notifications/NotificationManager.java b/app/src/main/java/org/tasks/notifications/NotificationManager.java index e5dff66de..95e04c2d2 100644 --- a/app/src/main/java/org/tasks/notifications/NotificationManager.java +++ b/app/src/main/java/org/tasks/notifications/NotificationManager.java @@ -58,10 +58,11 @@ public class NotificationManager { public static final String NOTIFICATION_CHANNEL_DEFAULT = "notifications"; public static final String NOTIFICATION_CHANNEL_TASKER = "notifications_tasker"; public static final String NOTIFICATION_CHANNEL_TIMERS = "notifications_timers"; + public static final int MAX_NOTIFICATIONS = 40; static final String EXTRA_NOTIFICATION_ID = "extra_notification_id"; + static final int SUMMARY_NOTIFICATION_ID = 0; private static final String GROUP_KEY = "tasks"; - private static final int SUMMARY_NOTIFICATION_ID = 0; - private static final int NOTIFICATIONS_PER_SECOND = 5; + private static final int NOTIFICATIONS_PER_SECOND = 4; private final NotificationManagerCompat notificationManagerCompat; private final LocationDao locationDao; private final NotificationDao notificationDao; @@ -70,6 +71,7 @@ public class NotificationManager { private final Preferences preferences; private final CheckBoxes checkBoxes; private final Throttle throttle = new Throttle(NOTIFICATIONS_PER_SECOND); + private final NotificationLimiter queue = new NotificationLimiter(MAX_NOTIFICATIONS); @Inject public NotificationManager( @@ -114,6 +116,7 @@ public class NotificationManager { public void cancel(long id) { notificationManagerCompat.cancel((int) id); + queue.remove(id); Completable.fromAction( () -> { if (id == SUMMARY_NOTIFICATION_ID) { @@ -132,11 +135,12 @@ public class NotificationManager { } public void cancel(List ids) { + for (Long id : ids) { + notificationManagerCompat.cancel(id.intValue()); + queue.remove(id); + } Completable.fromAction( () -> { - for (Long id : ids) { - notificationManagerCompat.cancel(id.intValue()); - } if (notificationDao.deleteAll(ids) > 0) { notifyTasks(Collections.emptyList(), false, false, false); } @@ -255,6 +259,12 @@ public class NotificationManager { notification.deleteIntent = PendingIntent.getBroadcast( context, (int) notificationId, deleteIntent, PendingIntent.FLAG_UPDATE_CURRENT); + + List evicted = queue.add(notificationId); + if (evicted.size() > 0) { + cancel(evicted); + } + for (int i = 0; i < ringTimes; i++) { throttle.run(() -> notificationManagerCompat.notify((int) notificationId, notification)); }