diff --git a/flutter_local_notifications/CHANGELOG.md b/flutter_local_notifications/CHANGELOG.md index 5e06399f8..b04d1b407 100644 --- a/flutter_local_notifications/CHANGELOG.md +++ b/flutter_local_notifications/CHANGELOG.md @@ -1,3 +1,12 @@ +# [17.0.3] + +* [Android] Added `shownNotificationsInfo` param to `NotificationDetails`. If you pass this param +it will save in local store if notification show. + * You can load this stored information by `FlutterLocalNotificationsPlugin.getShownNotificationsInfo()` + method and clear stored info by `FlutterLocalNotificationsPlugin.cleanShownNotificationsInfo()` method. + +* [Android] Fixed: `inexactWindowLengthMillis` always null in `NotificationDetails`. + # [17.0.2] * [Android] Remove old corrupted notifications. diff --git a/flutter_local_notifications/README.md b/flutter_local_notifications/README.md index 6e94de977..46fbce92c 100644 --- a/flutter_local_notifications/README.md +++ b/flutter_local_notifications/README.md @@ -17,6 +17,10 @@ This is fork of [flutter_local_notifications](https://github.com/MaikuB/flutter_ * Ability to set your own custom layout for notifications. * More detailed exceptions in `ScheduledNotificationReceiver.onReceive()`. * Ability to set notification window for inexact alarm. See `AndroidNotificationDetails.inexactWindowLengthMillis` +* Ability to store info about shown notifications. See `AndroidNotificationDetails.shownNotificationsInfo`. If you pass this param + it will save in local store if notification show. + * You can load this stored information by `FlutterLocalNotificationsPlugin.getShownNotificationsInfo()` + method and clear stored info by `FlutterLocalNotificationsPlugin.cleanShownNotificationsInfo()` method. ### iOS 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 edcacd6fd..529ec6949 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 @@ -152,6 +152,8 @@ public class FlutterLocalNotificationsPlugin private static final String GET_NOTIFICATION_CHANNELS_METHOD = "getNotificationChannels"; private static final String START_FOREGROUND_SERVICE = "startForegroundService"; private static final String STOP_FOREGROUND_SERVICE = "stopForegroundService"; + private static final String GET_SHOWN_NOTIFICATIONS_INFO = "getShownNotificationsInfo"; + private static final String CLEAR_SHOWN_NOTIFICATIONS_INFO = "clearShownNotificationsInfo"; private static final String PENDING_NOTIFICATION_REQUESTS_METHOD = "pendingNotificationRequests"; private static final String GET_ACTIVE_NOTIFICATIONS_METHOD = "getActiveNotifications"; private static final String SHOW_METHOD = "show"; @@ -1645,12 +1647,32 @@ public void fail(String message) { case STOP_FOREGROUND_SERVICE: stopForegroundService(result); break; + case GET_SHOWN_NOTIFICATIONS_INFO: + getShownNotificationsInfo(result); + break; + case CLEAR_SHOWN_NOTIFICATIONS_INFO: + clearShownNotificationsInfo(result); + break; default: result.notImplemented(); break; } } + private void getShownNotificationsInfo(Result result) { + final ShownNotificationsPreferences prefs = + new ShownNotificationsPreferences(applicationContext); + final ArrayList res = prefs.getShownNotificationsInfo(); + result.success(res); + } + + private void clearShownNotificationsInfo(Result result) { + final ShownNotificationsPreferences prefs = + new ShownNotificationsPreferences(applicationContext); + prefs.clearShownNotificationsInfo(); + result.success(true); + } + private void pendingNotificationRequests(Result result) { ArrayList scheduledNotifications = loadScheduledNotifications(applicationContext); diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/ScheduledNotificationReceiver.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/ScheduledNotificationReceiver.java index 744194dbf..86d4b4022 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/ScheduledNotificationReceiver.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/ScheduledNotificationReceiver.java @@ -24,12 +24,12 @@ /** Created by michaelbui on 24/3/18. */ @Keep public class ScheduledNotificationReceiver extends BroadcastReceiver { - private static final String TAG = "ScheduledNotifReceiver"; @Override @SuppressWarnings("deprecation") public void onReceive(final Context context, Intent intent) { + String notificationDetailsJson = intent.getStringExtra(FlutterLocalNotificationsPlugin.NOTIFICATION_DETAILS); if (StringUtils.isNullOrEmpty(notificationDetailsJson)) { @@ -93,6 +93,13 @@ public void onReceive(final Context context, Intent intent) { return; } + final String info = notificationDetails.shownNotificationsInfo; + if (!StringUtils.isNullOrEmpty(info)) { + final ShownNotificationsPreferences preferences = + new ShownNotificationsPreferences(context); + preferences.saveShownNotificationInfo(info); + } + try { FlutterLocalNotificationsPlugin.scheduleNextNotification(context, notificationDetails); } catch (Exception e) { diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/ShownNotificationsPreferences.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/ShownNotificationsPreferences.java new file mode 100644 index 000000000..e3d934982 --- /dev/null +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/ShownNotificationsPreferences.java @@ -0,0 +1,56 @@ +package com.dexterous.flutterlocalnotifications; + +import android.content.Context; +import android.content.SharedPreferences; + +import java.util.ArrayList; +import java.util.Arrays; + +public class ShownNotificationsPreferences { + private static final String SHARED_PREFS_FILE_NAME = + "flutter_local_notifications_plugin_shown_info"; + private final String SHOWN_NOTIFICATIONS_INFO_KEY = + "com.dexterous.flutterlocalnotifications.SHOWN_NOTIFICATIONS_INFO_KEY"; + private final String SHOWN_NOTIFICATIONS_INFO_DIVIDER = "/"; + + private final Context context; + + public ShownNotificationsPreferences(Context context) { + + this.context = context; + } + + public void saveShownNotificationInfo(String info) { + final SharedPreferences pref = get(); + final SharedPreferences.Editor editor = pref.edit(); + String currentInfo = pref.getString(SHOWN_NOTIFICATIONS_INFO_KEY, ""); + if (!currentInfo.isEmpty()) { + currentInfo = currentInfo + SHOWN_NOTIFICATIONS_INFO_DIVIDER + info; + } else { + currentInfo = info; + } + editor.putString(SHOWN_NOTIFICATIONS_INFO_KEY, currentInfo); + editor.apply(); + } + + public ArrayList getShownNotificationsInfo() { + final SharedPreferences pref = get(); + final String currentInfo = pref.getString(SHOWN_NOTIFICATIONS_INFO_KEY, ""); + if (currentInfo.isEmpty()) { + return new ArrayList<>(); + } + final String[] list = currentInfo.split(SHOWN_NOTIFICATIONS_INFO_DIVIDER); + return new ArrayList<>(Arrays.asList(list)); + } + + public void clearShownNotificationsInfo() { + final SharedPreferences pref = get(); + final SharedPreferences.Editor editor = pref.edit(); + editor.remove(SHOWN_NOTIFICATIONS_INFO_KEY); + editor.apply(); + } + + private SharedPreferences get() { + return context.getSharedPreferences(SHARED_PREFS_FILE_NAME, Context.MODE_PRIVATE); + } +} diff --git a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/models/NotificationDetails.java b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/models/NotificationDetails.java index 1248bded8..825941786 100644 --- a/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/models/NotificationDetails.java +++ b/flutter_local_notifications/android/src/main/java/com/dexterous/flutterlocalnotifications/models/NotificationDetails.java @@ -131,6 +131,7 @@ public class NotificationDetails implements Serializable { private static final String CUSTOM_LAYOUT_COLLAPSED_NAME = "customLayoutCollapsedName"; private static final String CUSTOM_LAYOUT_EXPANDED_NAME = "customLayoutExpandedName"; private static final String INEXACT_WINDOW_LENGTH_MILLIS = "inexactWindowLengthMillis"; + private static final String SHOWN_NOTIFICATION_INFO = "shownNotificationsInfo"; public Integer id; public String title; @@ -208,6 +209,8 @@ public class NotificationDetails implements Serializable { public Integer iconResourceId; public Long inexactWindowLengthMillis; + public String shownNotificationsInfo; + public static NotificationDetails from(Map arguments) { NotificationDetails notificationDetails = new NotificationDetails(); notificationDetails.payload = (String) arguments.get(PAYLOAD); @@ -244,13 +247,6 @@ public static NotificationDetails from(Map arguments) { notificationDetails.day = (Integer) arguments.get(DAY); } - if (arguments.containsKey(INEXACT_WINDOW_LENGTH_MILLIS)) { - notificationDetails.inexactWindowLengthMillis = - (Long) arguments.get(INEXACT_WINDOW_LENGTH_MILLIS); - } else { - notificationDetails.inexactWindowLengthMillis = 0L; - } - readPlatformSpecifics(arguments, notificationDetails); return notificationDetails; } @@ -325,6 +321,20 @@ private static void readPlatformSpecifics( } } } + + if (platformChannelSpecifics.containsKey(INEXACT_WINDOW_LENGTH_MILLIS)) { + notificationDetails.inexactWindowLengthMillis = + (Long) platformChannelSpecifics.get(INEXACT_WINDOW_LENGTH_MILLIS); + } else { + notificationDetails.inexactWindowLengthMillis = 0L; + } + + if (platformChannelSpecifics.containsKey(SHOWN_NOTIFICATION_INFO)) { + notificationDetails.shownNotificationsInfo = + (String) platformChannelSpecifics.get(SHOWN_NOTIFICATION_INFO); + } else { + notificationDetails.shownNotificationsInfo = ""; + } } } diff --git a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart index 94b5d73ba..f7c9c3d5a 100644 --- a/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart +++ b/flutter_local_notifications/lib/src/flutter_local_notifications_plugin.dart @@ -264,6 +264,42 @@ class FlutterLocalNotificationsPlugin { } } + /// Returns info that stored when notifications was shown. + /// See [AndroidNotificationDetails.shownNotificationsInfo] + Future>> getShownNotificationsInfo() async { + if (defaultTargetPlatform != TargetPlatform.android) { + assert( + false, + 'The method getShownNotificationsInfo available only for android.', + ); + return const >[]; + } + + final List> res = + (await resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.getShownNotificationsInfo()) ?? + const >[]; + return res; + } + + /// Clear all stored info obout shown notifications. + Future clearShownNotificationsInfo() async { + if (defaultTargetPlatform != TargetPlatform.android) { + assert( + false, + 'The method clearShownNotificationsInfo available only for android.', + ); + return false; + } + + final bool res = (await resolvePlatformSpecificImplementation< + AndroidFlutterLocalNotificationsPlugin>() + ?.clearShownNotificationsInfo()) ?? + false; + return res; + } + /// Cancel/remove the notification with the specified id. /// /// This applies to notifications that have been scheduled and those that diff --git a/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart b/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart index 394ac4ece..48752b759 100644 --- a/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart +++ b/flutter_local_notifications/lib/src/platform_flutter_local_notifications.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:convert'; import 'dart:ui'; import 'package:clock/clock.dart'; @@ -107,7 +108,7 @@ class MethodChannelFlutterLocalNotificationsPlugin /// Android implementation of the local notifications plugin. class AndroidFlutterLocalNotificationsPlugin extends MethodChannelFlutterLocalNotificationsPlugin { - DidReceiveNotificationResponseCallback? _ondidReceiveNotificationResponse; + DidReceiveNotificationResponseCallback? _onDidReceiveNotificationResponse; /// Initializes the plugin. /// @@ -131,7 +132,7 @@ class AndroidFlutterLocalNotificationsPlugin DidReceiveBackgroundNotificationResponseCallback? onDidReceiveBackgroundNotificationResponse, }) async { - _ondidReceiveNotificationResponse = onDidReceiveNotificationResponse; + _onDidReceiveNotificationResponse = onDidReceiveNotificationResponse; _channel.setMethodCallHandler(_handleMethod); final Map arguments = initializationSettings.toMap(); @@ -513,6 +514,27 @@ class AndroidFlutterLocalNotificationsPlugin Future canScheduleExactNotifications() async => await _channel.invokeMethod('canScheduleExactNotifications'); + /// Returns info that stored when notifications was shown. + /// See [AndroidNotificationDetails.shownNotificationsInfo] + Future>> getShownNotificationsInfo() async { + final List? res = + await _channel.invokeMethod>('getShownNotificationsInfo'); + if (res == null || res.isEmpty) { + return >[]; + } + return res + .map((Object? e) => jsonDecode(e as String) as Map) + .toList(); + } + + /// Clear all stored info obout shown notifications. + Future clearShownNotificationsInfo() async { + final bool? res = + await _channel.invokeMethod('clearShownNotificationsInfo'); + + return res ?? false; + } + AndroidNotificationSound? _getNotificationChannelSound( Map channelMap) { final int? soundSourceIndex = channelMap['soundSource']; @@ -531,7 +553,7 @@ class AndroidFlutterLocalNotificationsPlugin Future _handleMethod(MethodCall call) async { switch (call.method) { case 'didReceiveNotificationResponse': - _ondidReceiveNotificationResponse?.call( + _onDidReceiveNotificationResponse?.call( NotificationResponse( id: call.arguments['notificationId'], actionId: call.arguments['actionId'], @@ -637,7 +659,7 @@ class IOSFlutterLocalNotificationsPlugin ); }, ); - + /// Sets badge number. Future setBadgeNumber(int value) => _channel.invokeMethod('setBadgeNumber', { diff --git a/flutter_local_notifications/lib/src/platform_specifics/android/method_channel_mappers.dart b/flutter_local_notifications/lib/src/platform_specifics/android/method_channel_mappers.dart index 11c0f4678..c8016731b 100644 --- a/flutter_local_notifications/lib/src/platform_specifics/android/method_channel_mappers.dart +++ b/flutter_local_notifications/lib/src/platform_specifics/android/method_channel_mappers.dart @@ -224,6 +224,8 @@ extension AndroidNotificationDetailsMapper on AndroidNotificationDetails { 'colorized': colorized, 'number': number, 'audioAttributesUsage': audioAttributesUsage.value, + 'inexactWindowLengthMillis': inexactWindowLengthMillis, + 'shownNotificationsInfo': shownNotificationsInfo, } ..addAll(_convertActionsToMap(actions)) ..addAll(_convertStyleInformationToMap()) diff --git a/flutter_local_notifications/lib/src/platform_specifics/android/notification_details.dart b/flutter_local_notifications/lib/src/platform_specifics/android/notification_details.dart index e44247a33..8f9ac9acb 100644 --- a/flutter_local_notifications/lib/src/platform_specifics/android/notification_details.dart +++ b/flutter_local_notifications/lib/src/platform_specifics/android/notification_details.dart @@ -162,6 +162,7 @@ class AndroidNotificationDetails { this.customLayoutCollapsedName, this.customLayoutExpandedName, this.inexactWindowLengthMillis, + this.shownNotificationsInfo, }) : customLayoutLegacyName = customLayoutLegacyName ?? customLayoutName; /// The icon that should be used when displaying the notification. @@ -458,4 +459,9 @@ class AndroidNotificationDetails { /// zero, inexact alarm will plan in this length, should be 10 minutes /// or more, see more in docs https://developer.android.com/about/versions/14/changes/schedule-exact-alarms#use-cases final int? inexactWindowLengthMillis; + + /// Some info that will save in local store if notification show, to get + /// it from store use + /// [AndroidFlutterLocalNotificationsPlugin.getShownNotificationsInfo()]. + final String? shownNotificationsInfo; } diff --git a/flutter_local_notifications/pubspec.yaml b/flutter_local_notifications/pubspec.yaml index e6ee281c9..80088104c 100644 --- a/flutter_local_notifications/pubspec.yaml +++ b/flutter_local_notifications/pubspec.yaml @@ -2,7 +2,7 @@ name: flutter_local_notifications_plus description: A cross platform plugin for displaying and scheduling local notifications for Flutter applications with the ability to customise for each platform. -version: 17.0.2 +version: 17.0.3 homepage: https://github.com/Innim/flutter_local_notifications repository: https://github.com/Innim/flutter_local_notifications issue_tracker: https://github.com/Innim/flutter_local_notifications/issues