From c81ce8b6e254b9b2e569d5ff00981af3a1421ec2 Mon Sep 17 00:00:00 2001 From: Jeroen van de Ven Date: Fri, 17 Dec 2021 15:03:28 +0100 Subject: [PATCH 01/12] Use setAlarmClock --- .../FlutterLocalNotificationsPlugin.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index d417da74d..0ff55cb80 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -450,10 +450,10 @@ private static void scheduleNotification( AlarmManager alarmManager = getAlarmManager(context); if (BooleanUtils.getValue(notificationDetails.allowWhileIdle)) { - AlarmManagerCompat.setExactAndAllowWhileIdle( + AlarmManagerCompat.setAlarmClock( alarmManager, - AlarmManager.RTC_WAKEUP, notificationDetails.millisecondsSinceEpoch, + pendingIntent, pendingIntent); } else { AlarmManagerCompat.setExact( @@ -492,8 +492,8 @@ private static void zonedScheduleNotification( .toInstant() .toEpochMilli(); if (BooleanUtils.getValue(notificationDetails.allowWhileIdle)) { - AlarmManagerCompat.setExactAndAllowWhileIdle( - alarmManager, AlarmManager.RTC_WAKEUP, epochMilli, pendingIntent); + AlarmManagerCompat.setAlarmClock( + alarmManager, epochMilli, pendingIntent, pendingIntent); } else { AlarmManagerCompat.setExact(alarmManager, AlarmManager.RTC_WAKEUP, epochMilli, pendingIntent); } @@ -515,8 +515,8 @@ static void scheduleNextRepeatingNotification( PendingIntent pendingIntent = getBroadcastPendingIntent(context, notificationDetails.id, notificationIntent); AlarmManager alarmManager = getAlarmManager(context); - AlarmManagerCompat.setExactAndAllowWhileIdle( - alarmManager, AlarmManager.RTC_WAKEUP, notificationTriggerTime, pendingIntent); + AlarmManagerCompat.setAlarmClock( + alarmManager, notificationTriggerTime, pendingIntent, pendingIntent); saveScheduledNotification(context, notificationDetails); } @@ -568,8 +568,8 @@ private static void repeatNotification( AlarmManager alarmManager = getAlarmManager(context); if (BooleanUtils.getValue(notificationDetails.allowWhileIdle)) { - AlarmManagerCompat.setExactAndAllowWhileIdle( - alarmManager, AlarmManager.RTC_WAKEUP, notificationTriggerTime, pendingIntent); + AlarmManagerCompat.setAlarmClock( + alarmManager, notificationTriggerTime, pendingIntent, pendingIntent); } else { alarmManager.setInexactRepeating( AlarmManager.RTC_WAKEUP, notificationTriggerTime, repeatInterval, pendingIntent); From c9c07a4724f8335f8c7dadcc440b4be9a6fcc1f5 Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Fri, 17 Dec 2021 14:13:37 +0000 Subject: [PATCH 02/12] Google Java Format --- .../FlutterLocalNotificationsPlugin.java | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index 0ff55cb80..389bfbfc2 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -451,10 +451,7 @@ private static void scheduleNotification( AlarmManager alarmManager = getAlarmManager(context); if (BooleanUtils.getValue(notificationDetails.allowWhileIdle)) { AlarmManagerCompat.setAlarmClock( - alarmManager, - notificationDetails.millisecondsSinceEpoch, - pendingIntent, - pendingIntent); + alarmManager, notificationDetails.millisecondsSinceEpoch, pendingIntent, pendingIntent); } else { AlarmManagerCompat.setExact( alarmManager, @@ -492,8 +489,7 @@ private static void zonedScheduleNotification( .toInstant() .toEpochMilli(); if (BooleanUtils.getValue(notificationDetails.allowWhileIdle)) { - AlarmManagerCompat.setAlarmClock( - alarmManager, epochMilli, pendingIntent, pendingIntent); + AlarmManagerCompat.setAlarmClock(alarmManager, epochMilli, pendingIntent, pendingIntent); } else { AlarmManagerCompat.setExact(alarmManager, AlarmManager.RTC_WAKEUP, epochMilli, pendingIntent); } From 2b16361b6051f8f8eec9085a2d57499cb6b5fc14 Mon Sep 17 00:00:00 2001 From: Jeroen van de Ven Date: Mon, 10 Jan 2022 17:28:11 +0100 Subject: [PATCH 03/12] [WIP] Use StringSet to avoid very big json strings, test performance --- .../FlutterLocalNotificationsPlugin.java | 32 +++++++++++++------ 1 file changed, 23 insertions(+), 9 deletions(-) diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index 389bfbfc2..29fe21762 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -87,6 +87,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; +import java.util.Set; /** FlutterLocalNotificationsPlugin */ @Keep @@ -100,6 +101,8 @@ public class FlutterLocalNotificationsPlugin private static final String DEFAULT_ICON = "defaultIcon"; private static final String SELECT_NOTIFICATION = "SELECT_NOTIFICATION"; private static final String SCHEDULED_NOTIFICATIONS = "scheduled_notifications"; + // NOTE: We don't convert on update, so we can never release this until we do + private static final String SCHEDULED_NOTIFICATIONS_SET = "scheduled_notifications_set"; private static final String INITIALIZE_METHOD = "initialize"; private static final String GET_CALLBACK_HANDLE_METHOD = "getCallbackHandle"; private static final String ARE_NOTIFICATIONS_ENABLED_METHOD = "areNotificationsEnabled"; @@ -392,12 +395,14 @@ static Gson buildGson() { private static ArrayList loadScheduledNotifications(Context context) { ArrayList scheduledNotifications = new ArrayList<>(); SharedPreferences sharedPreferences = - context.getSharedPreferences(SCHEDULED_NOTIFICATIONS, Context.MODE_PRIVATE); - String json = sharedPreferences.getString(SCHEDULED_NOTIFICATIONS, null); - if (json != null) { + context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_SET, Context.MODE_PRIVATE); + Set jsons = sharedPreferences.getStringSet(SCHEDULED_NOTIFICATIONS_SET, null); + if (jsons != null) { Gson gson = buildGson(); - Type type = new TypeToken>() {}.getType(); - scheduledNotifications = gson.fromJson(json, type); + Type type = new TypeToken() {}.getType(); + for (String json : jsons) { + scheduledNotifications.add(gson.fromJson(json, type)); + } } return scheduledNotifications; } @@ -405,11 +410,15 @@ private static ArrayList loadScheduledNotifications(Context private static void saveScheduledNotifications( Context context, ArrayList scheduledNotifications) { Gson gson = buildGson(); - String json = gson.toJson(scheduledNotifications); + int amount = scheduledNotifications.size(); + String[] jsons = new String[amount]; + for (int i = 0; i < amount; i++) { + jsons[i] = gson.toJson(scheduledNotifications.get(i)); + } SharedPreferences sharedPreferences = - context.getSharedPreferences(SCHEDULED_NOTIFICATIONS, Context.MODE_PRIVATE); + context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_SET, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putString(SCHEDULED_NOTIFICATIONS, json); + editor.putStringSet(SCHEDULED_NOTIFICATIONS_SET, Set.of(jsons)); editor.apply(); } @@ -606,6 +615,7 @@ private static long calculateRepeatIntervalMilliseconds(NotificationDetails noti return repeatInterval; } + // TODO don't json parse the whole list, but this will allow duplicate notifications with the same id private static void saveScheduledNotification( Context context, NotificationDetails notificationDetails) { ArrayList scheduledNotifications = loadScheduledNotifications(context); @@ -1615,7 +1625,11 @@ private void cancelAllNotifications(Result result) { alarmManager.cancel(pendingIntent); } - saveScheduledNotifications(applicationContext, new ArrayList<>()); + SharedPreferences sharedPreferences = + applicationContext.getSharedPreferences(SCHEDULED_NOTIFICATIONS_SET, Context.MODE_PRIVATE); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.remove(SCHEDULED_NOTIFICATIONS_SET); + editor.apply(); result.success(null); } From 4302ce1eadcd5f5678751e920e520beecd69655c Mon Sep 17 00:00:00 2001 From: Jeroen van de Ven Date: Mon, 10 Jan 2022 18:04:43 +0100 Subject: [PATCH 04/12] [WIP] Don't parse all jsons on add, improve performance 85% --- .../FlutterLocalNotificationsPlugin.java | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index 29fe21762..52917e5b3 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -84,6 +84,7 @@ import java.util.Arrays; import java.util.Calendar; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -615,19 +616,18 @@ private static long calculateRepeatIntervalMilliseconds(NotificationDetails noti return repeatInterval; } - // TODO don't json parse the whole list, but this will allow duplicate notifications with the same id + // Don't json parse the whole list, but this will allow duplicate notifications with the same id private static void saveScheduledNotification( Context context, NotificationDetails notificationDetails) { - ArrayList scheduledNotifications = loadScheduledNotifications(context); - ArrayList scheduledNotificationsToSave = new ArrayList<>(); - for (NotificationDetails scheduledNotification : scheduledNotifications) { - if (scheduledNotification.id.equals(notificationDetails.id)) { - continue; - } - scheduledNotificationsToSave.add(scheduledNotification); - } - scheduledNotificationsToSave.add(notificationDetails); - saveScheduledNotifications(context, scheduledNotificationsToSave); + SharedPreferences sharedPreferences = + context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_SET, Context.MODE_PRIVATE); + Set jsons = sharedPreferences.getStringSet(SCHEDULED_NOTIFICATIONS_SET, new HashSet()); + Set newSet = new HashSet(jsons); + Gson gson = buildGson(); + newSet.add(gson.toJson(notificationDetails)); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.putStringSet(SCHEDULED_NOTIFICATIONS_SET, newSet); + editor.apply(); } private static int getDrawableResourceId(Context context, String name) { From e358b3b31c538358aa5524bd8af15209ddfab4d5 Mon Sep 17 00:00:00 2001 From: Jeroen van de Ven Date: Tue, 11 Jan 2022 10:37:07 +0100 Subject: [PATCH 05/12] Add data migration from big String to StringSet --- .../FlutterLocalNotificationsPlugin.java | 95 +++++++++++++++---- 1 file changed, 78 insertions(+), 17 deletions(-) diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index 52917e5b3..f13b65428 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -26,6 +26,7 @@ import android.text.Spanned; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; +import android.util.Log; import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.core.app.AlarmManagerCompat; @@ -101,8 +102,8 @@ public class FlutterLocalNotificationsPlugin private static final String DRAWABLE = "drawable"; private static final String DEFAULT_ICON = "defaultIcon"; private static final String SELECT_NOTIFICATION = "SELECT_NOTIFICATION"; - private static final String SCHEDULED_NOTIFICATIONS = "scheduled_notifications"; - // NOTE: We don't convert on update, so we can never release this until we do + private static final String SCHEDULED_NOTIFICATIONS_FILE = "scheduled_notifications"; + private static final String SCHEDULED_NOTIFICATIONS_STRING = "scheduled_notifications"; private static final String SCHEDULED_NOTIFICATIONS_SET = "scheduled_notifications_set"; private static final String INITIALIZE_METHOD = "initialize"; private static final String GET_CALLBACK_HANDLE_METHOD = "getCallbackHandle"; @@ -396,30 +397,84 @@ static Gson buildGson() { private static ArrayList loadScheduledNotifications(Context context) { ArrayList scheduledNotifications = new ArrayList<>(); SharedPreferences sharedPreferences = - context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_SET, Context.MODE_PRIVATE); - Set jsons = sharedPreferences.getStringSet(SCHEDULED_NOTIFICATIONS_SET, null); - if (jsons != null) { + context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); + Set jsonNotifications = getScheduledNotificationsJsonSet(sharedPreferences); + if (jsonNotifications != null) { Gson gson = buildGson(); Type type = new TypeToken() {}.getType(); - for (String json : jsons) { + for (String json : jsonNotifications) { scheduledNotifications.add(gson.fromJson(json, type)); } } return scheduledNotifications; } + /** + * Get scheduled notifications from shared preferences, converting from old format if present. + * + * Returns null if neither are present + * The returned Set may not be mutated! + */ + private static Set getScheduledNotificationsJsonSet(SharedPreferences sharedPreferences) { + Set jsonNotifications = sharedPreferences.getStringSet(SCHEDULED_NOTIFICATIONS_SET, null); + if (jsonNotifications != null) { + return jsonNotifications; + } + String notificationsJson = sharedPreferences.getString(SCHEDULED_NOTIFICATIONS_STRING, null); + if (notificationsJson == null) { + return null; + } + + // Convert (once) from the old format to the new format and delete the old + Gson gson = buildGson(); + Type type = new TypeToken>() {}.getType(); + ArrayList notificationsList = gson.fromJson(notificationsJson, type); + int amount = notificationsList.size(); + String[] jsonNotificationsToSave = new String[amount]; + for (int i = 0; i < amount; i++) { + jsonNotificationsToSave[i] = gson.toJson(notificationsList.get(i)); + if (i == 0) { + logLongJson(jsonNotificationsToSave[i]); + } + } + Set scheduledNotifications = Set.of(jsonNotificationsToSave); + SharedPreferences.Editor editor = sharedPreferences.edit(); + editor.remove(SCHEDULED_NOTIFICATIONS_STRING); + editor.putStringSet(SCHEDULED_NOTIFICATIONS_SET, scheduledNotifications); + editor.apply(); + return scheduledNotifications; + } + + private static void logLongJson(String json) { + String TAG = "json_example"; + if (json.length() > 4000) { + Log.v(TAG, "sb.length = " + json.length()); + int chunkCount = json.length() / 4000; // integer division + for (int i = 0; i <= chunkCount; i++) { + int max = 4000 * (i + 1); + if (max >= json.length()) { + Log.v(TAG, json.substring(4000 * i)); + } else { + Log.v(TAG, json.substring(4000 * i, max)); + } + } + } else { + Log.v(TAG, json); + } + } + private static void saveScheduledNotifications( Context context, ArrayList scheduledNotifications) { Gson gson = buildGson(); int amount = scheduledNotifications.size(); - String[] jsons = new String[amount]; + String[] jsonNotificationsToSave = new String[amount]; for (int i = 0; i < amount; i++) { - jsons[i] = gson.toJson(scheduledNotifications.get(i)); + jsonNotificationsToSave[i] = gson.toJson(scheduledNotifications.get(i)); } SharedPreferences sharedPreferences = - context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_SET, Context.MODE_PRIVATE); + context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putStringSet(SCHEDULED_NOTIFICATIONS_SET, Set.of(jsons)); + editor.putStringSet(SCHEDULED_NOTIFICATIONS_SET, Set.of(jsonNotificationsToSave)); editor.apply(); } @@ -616,17 +671,23 @@ private static long calculateRepeatIntervalMilliseconds(NotificationDetails noti return repeatInterval; } - // Don't json parse the whole list, but this will allow duplicate notifications with the same id + // Note: This will now allow duplicate notifications on ID which would be overwritten before. private static void saveScheduledNotification( Context context, NotificationDetails notificationDetails) { SharedPreferences sharedPreferences = - context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_SET, Context.MODE_PRIVATE); - Set jsons = sharedPreferences.getStringSet(SCHEDULED_NOTIFICATIONS_SET, new HashSet()); - Set newSet = new HashSet(jsons); + context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); + Set jsonNotifications = getScheduledNotificationsJsonSet(sharedPreferences); + if (jsonNotifications == null) { + jsonNotifications = new HashSet(); + } + + // Mutations on the Set from getStringSet() are not allowed! + Set jsonNotificationsToSave = new HashSet(jsonNotifications); + Gson gson = buildGson(); - newSet.add(gson.toJson(notificationDetails)); + jsonNotificationsToSave.add(gson.toJson(notificationDetails)); SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putStringSet(SCHEDULED_NOTIFICATIONS_SET, newSet); + editor.putStringSet(SCHEDULED_NOTIFICATIONS_SET, jsonNotificationsToSave); editor.apply(); } @@ -1626,7 +1687,7 @@ private void cancelAllNotifications(Result result) { } SharedPreferences sharedPreferences = - applicationContext.getSharedPreferences(SCHEDULED_NOTIFICATIONS_SET, Context.MODE_PRIVATE); + applicationContext.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.remove(SCHEDULED_NOTIFICATIONS_SET); editor.apply(); From c5c5e76d4b1666648d85fb8160b922b05c7e74ce Mon Sep 17 00:00:00 2001 From: Jeroen van de Ven Date: Tue, 11 Jan 2022 11:09:33 +0100 Subject: [PATCH 06/12] Remove log of example json --- .../FlutterLocalNotificationsPlugin.java | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index f13b65428..dcb2a66c8 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -26,7 +26,6 @@ import android.text.Spanned; import android.text.TextUtils; import android.text.style.ForegroundColorSpan; -import android.util.Log; import androidx.annotation.Keep; import androidx.annotation.NonNull; import androidx.core.app.AlarmManagerCompat; @@ -433,9 +432,6 @@ private static Set getScheduledNotificationsJsonSet(SharedPreferences sh String[] jsonNotificationsToSave = new String[amount]; for (int i = 0; i < amount; i++) { jsonNotificationsToSave[i] = gson.toJson(notificationsList.get(i)); - if (i == 0) { - logLongJson(jsonNotificationsToSave[i]); - } } Set scheduledNotifications = Set.of(jsonNotificationsToSave); SharedPreferences.Editor editor = sharedPreferences.edit(); @@ -445,24 +441,6 @@ private static Set getScheduledNotificationsJsonSet(SharedPreferences sh return scheduledNotifications; } - private static void logLongJson(String json) { - String TAG = "json_example"; - if (json.length() > 4000) { - Log.v(TAG, "sb.length = " + json.length()); - int chunkCount = json.length() / 4000; // integer division - for (int i = 0; i <= chunkCount; i++) { - int max = 4000 * (i + 1); - if (max >= json.length()) { - Log.v(TAG, json.substring(4000 * i)); - } else { - Log.v(TAG, json.substring(4000 * i, max)); - } - } - } else { - Log.v(TAG, json); - } - } - private static void saveScheduledNotifications( Context context, ArrayList scheduledNotifications) { Gson gson = buildGson(); From fdd342ef70ff160496137c8b7e54f339fe6339a6 Mon Sep 17 00:00:00 2001 From: Jeroen van de Ven Date: Tue, 11 Jan 2022 17:00:50 +0100 Subject: [PATCH 07/12] Allow canceling of all pending notifications --- .../FlutterLocalNotificationsPlugin.java | 37 +++++++++++++++---- 1 file changed, 30 insertions(+), 7 deletions(-) diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index dcb2a66c8..a8a322bca 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -121,6 +121,7 @@ public class FlutterLocalNotificationsPlugin private static final String SHOW_METHOD = "show"; private static final String CANCEL_METHOD = "cancel"; private static final String CANCEL_ALL_METHOD = "cancelAll"; + private static final String CANCEL_ALL_PENDING_METHOD = "cancelAllPending"; private static final String SCHEDULE_METHOD = "schedule"; private static final String ZONED_SCHEDULE_METHOD = "zonedSchedule"; private static final String PERIODICALLY_SHOW_METHOD = "periodicallyShow"; @@ -1364,6 +1365,9 @@ public void onMethodCall(MethodCall call, @NonNull Result result) { case CANCEL_ALL_METHOD: cancelAllNotifications(result); break; + case CANCEL_ALL_PENDING_METHOD: + cancelAllPendingNotifications(result); + break; case PENDING_NOTIFICATION_REQUESTS_METHOD: pendingNotificationRequests(result); break; @@ -1632,6 +1636,12 @@ private boolean hasInvalidIcon(Result result, String icon) { && !isValidDrawableResource(applicationContext, icon, result, INVALID_ICON_ERROR_CODE); } + /** + * Cancels a single notification by ID + * + * @param id + * @param tag + */ private void cancelNotification(Integer id, String tag) { Intent intent = new Intent(applicationContext, ScheduledNotificationReceiver.class); PendingIntent pendingIntent = getBroadcastPendingIntent(applicationContext, id, intent); @@ -1646,21 +1656,22 @@ private void cancelNotification(Integer id, String tag) { removeNotificationFromCache(applicationContext, id); } - private void cancelAllNotifications(Result result) { - NotificationManagerCompat notificationManager = getNotificationManager(applicationContext); - notificationManager.cancelAll(); + /** + * Cancels only all pending notifications, leaving active ones. + */ + private void cancelAllPendingNotifications(Result result) { ArrayList scheduledNotifications = - loadScheduledNotifications(applicationContext); - if (scheduledNotifications == null || scheduledNotifications.isEmpty()) { + loadScheduledNotifications(applicationContext); + if (scheduledNotifications.isEmpty()) { result.success(null); return; } Intent intent = new Intent(applicationContext, ScheduledNotificationReceiver.class); + AlarmManager alarmManager = getAlarmManager(applicationContext); for (NotificationDetails scheduledNotification : scheduledNotifications) { PendingIntent pendingIntent = - getBroadcastPendingIntent(applicationContext, scheduledNotification.id, intent); - AlarmManager alarmManager = getAlarmManager(applicationContext); + getBroadcastPendingIntent(applicationContext, scheduledNotification.id, intent); alarmManager.cancel(pendingIntent); } @@ -1672,6 +1683,18 @@ private void cancelAllNotifications(Result result) { result.success(null); } + /** + * Cancels all notifications, both scheduled and active + * + * @param result + */ + private void cancelAllNotifications(Result result) { + NotificationManagerCompat notificationManager = getNotificationManager(applicationContext); + notificationManager.cancelAll(); + + cancelAllPendingNotifications(result); + } + @Override public boolean onNewIntent(Intent intent) { boolean res = sendNotificationPayloadMessage(intent); From c520ee36c3f03166a25c4f5ec0d1e344a6958afc Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Tue, 11 Jan 2022 16:01:18 +0000 Subject: [PATCH 08/12] Google Java Format --- .../FlutterLocalNotificationsPlugin.java | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index a8a322bca..fad4602dd 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -412,11 +412,11 @@ private static ArrayList loadScheduledNotifications(Context /** * Get scheduled notifications from shared preferences, converting from old format if present. * - * Returns null if neither are present - * The returned Set may not be mutated! + *

Returns null if neither are present The returned Set may not be mutated! */ private static Set getScheduledNotificationsJsonSet(SharedPreferences sharedPreferences) { - Set jsonNotifications = sharedPreferences.getStringSet(SCHEDULED_NOTIFICATIONS_SET, null); + Set jsonNotifications = + sharedPreferences.getStringSet(SCHEDULED_NOTIFICATIONS_SET, null); if (jsonNotifications != null) { return jsonNotifications; } @@ -1656,12 +1656,10 @@ private void cancelNotification(Integer id, String tag) { removeNotificationFromCache(applicationContext, id); } - /** - * Cancels only all pending notifications, leaving active ones. - */ + /** Cancels only all pending notifications, leaving active ones. */ private void cancelAllPendingNotifications(Result result) { ArrayList scheduledNotifications = - loadScheduledNotifications(applicationContext); + loadScheduledNotifications(applicationContext); if (scheduledNotifications.isEmpty()) { result.success(null); return; @@ -1671,12 +1669,12 @@ private void cancelAllPendingNotifications(Result result) { AlarmManager alarmManager = getAlarmManager(applicationContext); for (NotificationDetails scheduledNotification : scheduledNotifications) { PendingIntent pendingIntent = - getBroadcastPendingIntent(applicationContext, scheduledNotification.id, intent); + getBroadcastPendingIntent(applicationContext, scheduledNotification.id, intent); alarmManager.cancel(pendingIntent); } SharedPreferences sharedPreferences = - applicationContext.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); + applicationContext.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); editor.remove(SCHEDULED_NOTIFICATIONS_SET); editor.apply(); From e3cb88c4e627348f37c1002dac4de7181888be41 Mon Sep 17 00:00:00 2001 From: Jeroen van de Ven Date: Tue, 11 Jan 2022 17:12:18 +0100 Subject: [PATCH 09/12] Simplify scheduling code --- .../FlutterLocalNotificationsPlugin.java | 58 ++++++++----------- 1 file changed, 23 insertions(+), 35 deletions(-) diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index fad4602dd..19aeaa2a1 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -485,53 +485,41 @@ private static void scheduleNotification( Context context, final NotificationDetails notificationDetails, Boolean updateScheduledNotificationsCache) { - Gson gson = buildGson(); - String notificationDetailsJson = gson.toJson(notificationDetails); - Intent notificationIntent = new Intent(context, ScheduledNotificationReceiver.class); - notificationIntent.putExtra(NOTIFICATION_DETAILS, notificationDetailsJson); - PendingIntent pendingIntent = - getBroadcastPendingIntent(context, notificationDetails.id, notificationIntent); - - AlarmManager alarmManager = getAlarmManager(context); - if (BooleanUtils.getValue(notificationDetails.allowWhileIdle)) { - AlarmManagerCompat.setAlarmClock( - alarmManager, notificationDetails.millisecondsSinceEpoch, pendingIntent, pendingIntent); - } else { - AlarmManagerCompat.setExact( - alarmManager, - AlarmManager.RTC_WAKEUP, - notificationDetails.millisecondsSinceEpoch, - pendingIntent); - } - - if (updateScheduledNotificationsCache) { - saveScheduledNotification(context, notificationDetails); - } + scheduleNotificationAtTime(context, notificationDetails, notificationDetails.millisecondsSinceEpoch, updateScheduledNotificationsCache); } private static void zonedScheduleNotification( Context context, final NotificationDetails notificationDetails, Boolean updateScheduledNotificationsCache) { + long epochMilli = + VERSION.SDK_INT >= VERSION_CODES.O + ? ZonedDateTime.of( + LocalDateTime.parse(notificationDetails.scheduledDateTime), + ZoneId.of(notificationDetails.timeZoneName)) + .toInstant() + .toEpochMilli() + : org.threeten.bp.ZonedDateTime.of( + org.threeten.bp.LocalDateTime.parse(notificationDetails.scheduledDateTime), + org.threeten.bp.ZoneId.of(notificationDetails.timeZoneName)) + .toInstant() + .toEpochMilli(); + scheduleNotificationAtTime(context, notificationDetails, epochMilli, updateScheduledNotificationsCache); + } + + private static void scheduleNotificationAtTime( + Context context, + NotificationDetails notificationDetails, + long epochMilli, + Boolean updateScheduledNotificationsCache) { Gson gson = buildGson(); String notificationDetailsJson = gson.toJson(notificationDetails); Intent notificationIntent = new Intent(context, ScheduledNotificationReceiver.class); notificationIntent.putExtra(NOTIFICATION_DETAILS, notificationDetailsJson); PendingIntent pendingIntent = - getBroadcastPendingIntent(context, notificationDetails.id, notificationIntent); + getBroadcastPendingIntent(context, notificationDetails.id, notificationIntent); + AlarmManager alarmManager = getAlarmManager(context); - long epochMilli = - VERSION.SDK_INT >= VERSION_CODES.O - ? ZonedDateTime.of( - LocalDateTime.parse(notificationDetails.scheduledDateTime), - ZoneId.of(notificationDetails.timeZoneName)) - .toInstant() - .toEpochMilli() - : org.threeten.bp.ZonedDateTime.of( - org.threeten.bp.LocalDateTime.parse(notificationDetails.scheduledDateTime), - org.threeten.bp.ZoneId.of(notificationDetails.timeZoneName)) - .toInstant() - .toEpochMilli(); if (BooleanUtils.getValue(notificationDetails.allowWhileIdle)) { AlarmManagerCompat.setAlarmClock(alarmManager, epochMilli, pendingIntent, pendingIntent); } else { From e474cb696385d5492cddd5e6e19564fb9d691094 Mon Sep 17 00:00:00 2001 From: Jeroen van de Ven Date: Tue, 11 Jan 2022 17:26:13 +0100 Subject: [PATCH 10/12] [WIP] Interface to schedule multiple notifications in one call --- .../FlutterLocalNotificationsPlugin.java | 34 +++++++++++++++---- 1 file changed, 28 insertions(+), 6 deletions(-) diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index 19aeaa2a1..a87844aa7 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -154,6 +154,7 @@ public class FlutterLocalNotificationsPlugin + " your Android head project."; private static final String CANCEL_ID = "id"; private static final String CANCEL_TAG = "tag"; + private static final String REPLACE = "replace"; static String NOTIFICATION_DETAILS = "notificationDetails"; static Gson gson; private MethodChannel channel; @@ -1354,7 +1355,7 @@ public void onMethodCall(MethodCall call, @NonNull Result result) { cancelAllNotifications(result); break; case CANCEL_ALL_PENDING_METHOD: - cancelAllPendingNotifications(result); + cancelAllPending(result); break; case PENDING_NOTIFICATION_REQUESTS_METHOD: pendingNotificationRequests(result); @@ -1468,16 +1469,34 @@ private void schedule(MethodCall call, Result result) { private void zonedSchedule(MethodCall call, Result result) { Map arguments = call.arguments(); NotificationDetails notificationDetails = extractNotificationDetails(result, arguments); + zonedScheduleDetails(result, notificationDetails, applicationContext); + } + + private static void zonedScheduleDetails(Result result, NotificationDetails notificationDetails, Context applicationContext) { if (notificationDetails != null) { if (notificationDetails.matchDateTimeComponents != null) { notificationDetails.scheduledDateTime = - getNextFireDateMatchingDateTimeComponents(notificationDetails); + getNextFireDateMatchingDateTimeComponents(notificationDetails); } zonedScheduleNotification(applicationContext, notificationDetails, true); result.success(null); } } + private void zonedScheduleMultiple(MethodCall call, Result result) { + Map arguments = call.arguments(); + boolean replace = arguments.get(REPLACE); + ArrayList multiNotificationDetails = extractMultipleNotificationDetails(result, arguments); + + if (replace) { + cancelAllPendingNotifications(); + } + + for (NotificationDetails notificationDetails : multiNotificationDetails) { + zonedScheduleDetails(result, notificationDetails, applicationContext); + } + } + private void show(MethodCall call, Result result) { Map arguments = call.arguments(); NotificationDetails notificationDetails = extractNotificationDetails(result, arguments); @@ -1645,11 +1664,15 @@ private void cancelNotification(Integer id, String tag) { } /** Cancels only all pending notifications, leaving active ones. */ - private void cancelAllPendingNotifications(Result result) { + private void cancelAllPending(Result result) { + cancelAllPendingNotifications(); + result.success(null); + } + + private void cancelAllPendingNotifications() { ArrayList scheduledNotifications = loadScheduledNotifications(applicationContext); if (scheduledNotifications.isEmpty()) { - result.success(null); return; } @@ -1666,7 +1689,6 @@ private void cancelAllPendingNotifications(Result result) { SharedPreferences.Editor editor = sharedPreferences.edit(); editor.remove(SCHEDULED_NOTIFICATIONS_SET); editor.apply(); - result.success(null); } /** @@ -1678,7 +1700,7 @@ private void cancelAllNotifications(Result result) { NotificationManagerCompat notificationManager = getNotificationManager(applicationContext); notificationManager.cancelAll(); - cancelAllPendingNotifications(result); + cancelAllPending(result); } @Override From 68597daef81724a641a75e4d1eac650402e496b4 Mon Sep 17 00:00:00 2001 From: Jeroen van de Ven Date: Tue, 11 Jan 2022 17:46:42 +0100 Subject: [PATCH 11/12] [WIP] Save scheduled notifications as separate String items rather than StringSet --- .../FlutterLocalNotificationsPlugin.java | 73 +++++++------------ 1 file changed, 26 insertions(+), 47 deletions(-) diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index a87844aa7..f4c3553c3 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -84,8 +84,6 @@ import java.util.Arrays; import java.util.Calendar; import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Set; @@ -103,7 +101,7 @@ public class FlutterLocalNotificationsPlugin private static final String SELECT_NOTIFICATION = "SELECT_NOTIFICATION"; private static final String SCHEDULED_NOTIFICATIONS_FILE = "scheduled_notifications"; private static final String SCHEDULED_NOTIFICATIONS_STRING = "scheduled_notifications"; - private static final String SCHEDULED_NOTIFICATIONS_SET = "scheduled_notifications_set"; + private static final String SCHEDULED_NOTIFICATIONS_ID = "snid"; private static final String INITIALIZE_METHOD = "initialize"; private static final String GET_CALLBACK_HANDLE_METHOD = "getCallbackHandle"; private static final String ARE_NOTIFICATIONS_ENABLED_METHOD = "areNotificationsEnabled"; @@ -399,17 +397,19 @@ private static ArrayList loadScheduledNotifications(Context ArrayList scheduledNotifications = new ArrayList<>(); SharedPreferences sharedPreferences = context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); - Set jsonNotifications = getScheduledNotificationsJsonSet(sharedPreferences); + Map jsonNotifications = + (Map) sharedPreferences.getAll(); if (jsonNotifications != null) { Gson gson = buildGson(); Type type = new TypeToken() {}.getType(); - for (String json : jsonNotifications) { + for (String json : jsonNotifications.values()) { scheduledNotifications.add(gson.fromJson(json, type)); } } return scheduledNotifications; } + // TODO rewrite migration code /** * Get scheduled notifications from shared preferences, converting from old format if present. * @@ -443,33 +443,14 @@ private static Set getScheduledNotificationsJsonSet(SharedPreferences sh return scheduledNotifications; } - private static void saveScheduledNotifications( - Context context, ArrayList scheduledNotifications) { - Gson gson = buildGson(); - int amount = scheduledNotifications.size(); - String[] jsonNotificationsToSave = new String[amount]; - for (int i = 0; i < amount; i++) { - jsonNotificationsToSave[i] = gson.toJson(scheduledNotifications.get(i)); - } - SharedPreferences sharedPreferences = + static void removeNotificationFromCache(Context context, Integer notificationId) { + SharedPreferences sharedPreferences1 = context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); - SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putStringSet(SCHEDULED_NOTIFICATIONS_SET, Set.of(jsonNotificationsToSave)); + SharedPreferences.Editor editor = sharedPreferences1.edit(); + editor.remove(SCHEDULED_NOTIFICATIONS_ID + notificationId); editor.apply(); } - static void removeNotificationFromCache(Context context, Integer notificationId) { - ArrayList scheduledNotifications = loadScheduledNotifications(context); - for (Iterator it = scheduledNotifications.iterator(); it.hasNext(); ) { - NotificationDetails notificationDetails = it.next(); - if (notificationDetails.id.equals(notificationId)) { - it.remove(); - break; - } - } - saveScheduledNotifications(context, scheduledNotifications); - } - @SuppressWarnings("deprecation") private static Spanned fromHtml(String html) { if (html == null) { @@ -644,18 +625,10 @@ private static void saveScheduledNotification( Context context, NotificationDetails notificationDetails) { SharedPreferences sharedPreferences = context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); - Set jsonNotifications = getScheduledNotificationsJsonSet(sharedPreferences); - if (jsonNotifications == null) { - jsonNotifications = new HashSet(); - } - - // Mutations on the Set from getStringSet() are not allowed! - Set jsonNotificationsToSave = new HashSet(jsonNotifications); - - Gson gson = buildGson(); - jsonNotificationsToSave.add(gson.toJson(notificationDetails)); SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.putStringSet(SCHEDULED_NOTIFICATIONS_SET, jsonNotificationsToSave); + Gson gson = buildGson(); + String jsonNotificationToSave = gson.toJson(notificationDetails); + editor.putString(SCHEDULED_NOTIFICATIONS_ID + notificationDetails.id, jsonNotificationToSave); editor.apply(); } @@ -1669,25 +1642,31 @@ private void cancelAllPending(Result result) { result.success(null); } + /** + * Cancels all pending notifications without parsing any JSON + */ private void cancelAllPendingNotifications() { - ArrayList scheduledNotifications = - loadScheduledNotifications(applicationContext); - if (scheduledNotifications.isEmpty()) { + SharedPreferences sharedPreferences = + applicationContext.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); + Map jsonNotifications = + (Map) sharedPreferences.getAll(); + + if (jsonNotifications.isEmpty()) { return; } Intent intent = new Intent(applicationContext, ScheduledNotificationReceiver.class); AlarmManager alarmManager = getAlarmManager(applicationContext); - for (NotificationDetails scheduledNotification : scheduledNotifications) { + for (String id : jsonNotifications.keySet()) { + // TODO filter out non-matching IDs + int intId = Integer.parseInt(id.substring(SCHEDULED_NOTIFICATIONS_ID.length() - 1)); PendingIntent pendingIntent = - getBroadcastPendingIntent(applicationContext, scheduledNotification.id, intent); + getBroadcastPendingIntent(applicationContext, intId, intent); alarmManager.cancel(pendingIntent); } - SharedPreferences sharedPreferences = - applicationContext.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); SharedPreferences.Editor editor = sharedPreferences.edit(); - editor.remove(SCHEDULED_NOTIFICATIONS_SET); + editor.clear(); editor.apply(); } From 6ff76f59dc50e836756eb4f4b9a2e8569ee8e166 Mon Sep 17 00:00:00 2001 From: github-actions <> Date: Tue, 11 Jan 2022 16:47:13 +0000 Subject: [PATCH 12/12] Google Java Format --- .../FlutterLocalNotificationsPlugin.java | 54 ++++++++++--------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java index f4c3553c3..44378be0f 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/FlutterLocalNotificationsPlugin.java @@ -397,8 +397,7 @@ private static ArrayList loadScheduledNotifications(Context ArrayList scheduledNotifications = new ArrayList<>(); SharedPreferences sharedPreferences = context.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); - Map jsonNotifications = - (Map) sharedPreferences.getAll(); + Map jsonNotifications = (Map) sharedPreferences.getAll(); if (jsonNotifications != null) { Gson gson = buildGson(); Type type = new TypeToken() {}.getType(); @@ -467,7 +466,11 @@ private static void scheduleNotification( Context context, final NotificationDetails notificationDetails, Boolean updateScheduledNotificationsCache) { - scheduleNotificationAtTime(context, notificationDetails, notificationDetails.millisecondsSinceEpoch, updateScheduledNotificationsCache); + scheduleNotificationAtTime( + context, + notificationDetails, + notificationDetails.millisecondsSinceEpoch, + updateScheduledNotificationsCache); } private static void zonedScheduleNotification( @@ -475,31 +478,32 @@ private static void zonedScheduleNotification( final NotificationDetails notificationDetails, Boolean updateScheduledNotificationsCache) { long epochMilli = - VERSION.SDK_INT >= VERSION_CODES.O - ? ZonedDateTime.of( + VERSION.SDK_INT >= VERSION_CODES.O + ? ZonedDateTime.of( LocalDateTime.parse(notificationDetails.scheduledDateTime), ZoneId.of(notificationDetails.timeZoneName)) - .toInstant() - .toEpochMilli() - : org.threeten.bp.ZonedDateTime.of( + .toInstant() + .toEpochMilli() + : org.threeten.bp.ZonedDateTime.of( org.threeten.bp.LocalDateTime.parse(notificationDetails.scheduledDateTime), org.threeten.bp.ZoneId.of(notificationDetails.timeZoneName)) - .toInstant() - .toEpochMilli(); - scheduleNotificationAtTime(context, notificationDetails, epochMilli, updateScheduledNotificationsCache); + .toInstant() + .toEpochMilli(); + scheduleNotificationAtTime( + context, notificationDetails, epochMilli, updateScheduledNotificationsCache); } private static void scheduleNotificationAtTime( - Context context, - NotificationDetails notificationDetails, - long epochMilli, - Boolean updateScheduledNotificationsCache) { + Context context, + NotificationDetails notificationDetails, + long epochMilli, + Boolean updateScheduledNotificationsCache) { Gson gson = buildGson(); String notificationDetailsJson = gson.toJson(notificationDetails); Intent notificationIntent = new Intent(context, ScheduledNotificationReceiver.class); notificationIntent.putExtra(NOTIFICATION_DETAILS, notificationDetailsJson); PendingIntent pendingIntent = - getBroadcastPendingIntent(context, notificationDetails.id, notificationIntent); + getBroadcastPendingIntent(context, notificationDetails.id, notificationIntent); AlarmManager alarmManager = getAlarmManager(context); if (BooleanUtils.getValue(notificationDetails.allowWhileIdle)) { @@ -1445,11 +1449,12 @@ private void zonedSchedule(MethodCall call, Result result) { zonedScheduleDetails(result, notificationDetails, applicationContext); } - private static void zonedScheduleDetails(Result result, NotificationDetails notificationDetails, Context applicationContext) { + private static void zonedScheduleDetails( + Result result, NotificationDetails notificationDetails, Context applicationContext) { if (notificationDetails != null) { if (notificationDetails.matchDateTimeComponents != null) { notificationDetails.scheduledDateTime = - getNextFireDateMatchingDateTimeComponents(notificationDetails); + getNextFireDateMatchingDateTimeComponents(notificationDetails); } zonedScheduleNotification(applicationContext, notificationDetails, true); result.success(null); @@ -1459,7 +1464,8 @@ private static void zonedScheduleDetails(Result result, NotificationDetails noti private void zonedScheduleMultiple(MethodCall call, Result result) { Map arguments = call.arguments(); boolean replace = arguments.get(REPLACE); - ArrayList multiNotificationDetails = extractMultipleNotificationDetails(result, arguments); + ArrayList multiNotificationDetails = + extractMultipleNotificationDetails(result, arguments); if (replace) { cancelAllPendingNotifications(); @@ -1642,14 +1648,11 @@ private void cancelAllPending(Result result) { result.success(null); } - /** - * Cancels all pending notifications without parsing any JSON - */ + /** Cancels all pending notifications without parsing any JSON */ private void cancelAllPendingNotifications() { SharedPreferences sharedPreferences = applicationContext.getSharedPreferences(SCHEDULED_NOTIFICATIONS_FILE, Context.MODE_PRIVATE); - Map jsonNotifications = - (Map) sharedPreferences.getAll(); + Map jsonNotifications = (Map) sharedPreferences.getAll(); if (jsonNotifications.isEmpty()) { return; @@ -1660,8 +1663,7 @@ private void cancelAllPendingNotifications() { for (String id : jsonNotifications.keySet()) { // TODO filter out non-matching IDs int intId = Integer.parseInt(id.substring(SCHEDULED_NOTIFICATIONS_ID.length() - 1)); - PendingIntent pendingIntent = - getBroadcastPendingIntent(applicationContext, intId, intent); + PendingIntent pendingIntent = getBroadcastPendingIntent(applicationContext, intId, intent); alarmManager.cancel(pendingIntent); }