expo-notifications 1.0.0-canary-20240912-1059f85 → 1.0.0-canary-20241008-90b13ad

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/CHANGELOG.md +29 -4
  2. package/android/build.gradle +10 -7
  3. package/android/src/main/java/expo/modules/notifications/Utils.kt +2 -2
  4. package/android/src/main/java/expo/modules/notifications/notifications/NotificationManager.java +8 -0
  5. package/android/src/main/java/expo/modules/notifications/notifications/NotificationSerializer.java +13 -11
  6. package/android/src/main/java/expo/modules/notifications/notifications/SoundResolver.java +1 -1
  7. package/android/src/main/java/expo/modules/notifications/notifications/background/BackgroundRemoteNotificationTaskConsumer.java +2 -1
  8. package/android/src/main/java/expo/modules/notifications/notifications/channels/AbstractNotificationsChannelsProvider.java +0 -60
  9. package/android/src/main/java/expo/modules/notifications/notifications/channels/AndroidXNotificationsChannelsProvider.kt +26 -0
  10. package/android/src/main/java/expo/modules/notifications/notifications/channels/NotificationsChannelsProvider.kt +13 -0
  11. package/android/src/main/java/expo/modules/notifications/notifications/channels/managers/AndroidXNotificationsChannelGroupManager.java +1 -2
  12. package/android/src/main/java/expo/modules/notifications/notifications/debug/DebugLogging.kt +3 -5
  13. package/android/src/main/java/expo/modules/notifications/notifications/emitting/NotificationsEmitter.kt +5 -0
  14. package/android/src/main/java/expo/modules/notifications/notifications/handling/NotificationsHandler.kt +3 -1
  15. package/android/src/main/java/expo/modules/notifications/notifications/handling/SingleNotificationHandlerTask.java +2 -4
  16. package/android/src/main/java/expo/modules/notifications/notifications/interfaces/INotificationContent.kt +38 -0
  17. package/android/src/main/java/expo/modules/notifications/notifications/interfaces/NotificationBuilder.kt +26 -0
  18. package/android/src/main/java/expo/modules/notifications/notifications/interfaces/NotificationListener.java +1 -1
  19. package/android/src/main/java/expo/modules/notifications/notifications/interfaces/NotificationTrigger.java +0 -3
  20. package/android/src/main/java/expo/modules/notifications/notifications/model/Notification.java +7 -7
  21. package/android/src/main/java/expo/modules/notifications/notifications/model/NotificationAction.java +3 -0
  22. package/android/src/main/java/expo/modules/notifications/notifications/model/NotificationCategory.java +2 -0
  23. package/android/src/main/java/expo/modules/notifications/notifications/model/NotificationContent.java +64 -55
  24. package/android/src/main/java/expo/modules/notifications/notifications/model/NotificationRequest.java +4 -3
  25. package/android/src/main/java/expo/modules/notifications/notifications/model/RemoteNotificationContent.kt +99 -0
  26. package/android/src/main/java/expo/modules/notifications/notifications/presentation/ExpoNotificationPresentationModule.kt +2 -2
  27. package/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/BaseNotificationBuilder.kt +148 -0
  28. package/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/DownloadImage.kt +23 -0
  29. package/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.kt +395 -0
  30. package/android/src/main/java/expo/modules/notifications/notifications/scheduling/NotificationScheduler.kt +18 -0
  31. package/android/src/main/java/expo/modules/notifications/notifications/triggers/MonthlyTrigger.java +85 -0
  32. package/android/src/main/java/expo/modules/notifications/service/NotificationsService.kt +11 -6
  33. package/android/src/main/java/expo/modules/notifications/service/delegates/ExpoHandlingDelegate.kt +11 -0
  34. package/android/src/main/java/expo/modules/notifications/service/delegates/ExpoPresentationDelegate.kt +25 -17
  35. package/android/src/main/java/expo/modules/notifications/service/delegates/FirebaseMessagingDelegate.kt +10 -22
  36. package/build/NotificationScheduler.types.d.ts +32 -11
  37. package/build/NotificationScheduler.types.d.ts.map +1 -1
  38. package/build/NotificationScheduler.types.js.map +1 -1
  39. package/build/Notifications.types.d.ts +99 -35
  40. package/build/Notifications.types.d.ts.map +1 -1
  41. package/build/Notifications.types.js +14 -0
  42. package/build/Notifications.types.js.map +1 -1
  43. package/build/NotificationsEmitter.d.ts +11 -1
  44. package/build/NotificationsEmitter.d.ts.map +1 -1
  45. package/build/NotificationsEmitter.js +36 -3
  46. package/build/NotificationsEmitter.js.map +1 -1
  47. package/build/index.d.ts.map +1 -1
  48. package/build/index.js +9 -0
  49. package/build/index.js.map +1 -1
  50. package/build/scheduleNotificationAsync.d.ts +1 -1
  51. package/build/scheduleNotificationAsync.d.ts.map +1 -1
  52. package/build/scheduleNotificationAsync.js +155 -110
  53. package/build/scheduleNotificationAsync.js.map +1 -1
  54. package/build/useLastNotificationResponse.d.ts.map +1 -1
  55. package/build/useLastNotificationResponse.js +5 -1
  56. package/build/useLastNotificationResponse.js.map +1 -1
  57. package/ios/EXNotifications/Notifications/Emitter/EXNotificationsEmitter.h +1 -0
  58. package/ios/EXNotifications/Notifications/Emitter/EXNotificationsEmitter.m +8 -1
  59. package/ios/EXNotifications/Notifications/Scheduling/EXNotificationSchedulerModule.m +16 -0
  60. package/package.json +7 -7
  61. package/plugin/build/withNotificationsAndroid.d.ts +5 -5
  62. package/plugin/build/withNotificationsAndroid.js +18 -16
  63. package/plugin/build/withNotificationsIOS.js +3 -1
  64. package/plugin/src/withNotificationsAndroid.ts +18 -18
  65. package/plugin/src/withNotificationsIOS.ts +3 -1
  66. package/src/NotificationScheduler.types.ts +41 -22
  67. package/src/Notifications.types.ts +100 -40
  68. package/src/NotificationsEmitter.ts +39 -3
  69. package/src/index.ts +13 -0
  70. package/src/scheduleNotificationAsync.ts +198 -152
  71. package/src/useLastNotificationResponse.ts +5 -0
  72. package/android/src/main/java/expo/modules/notifications/notifications/JSONNotificationContentBuilder.java +0 -203
  73. package/android/src/main/java/expo/modules/notifications/notifications/channels/AndroidXNotificationsChannelsProvider.java +0 -38
  74. package/android/src/main/java/expo/modules/notifications/notifications/channels/NotificationsChannelsProvider.java +0 -13
  75. package/android/src/main/java/expo/modules/notifications/notifications/interfaces/NotificationBuilder.java +0 -35
  76. package/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/BaseNotificationBuilder.java +0 -50
  77. package/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/CategoryAwareNotificationBuilder.java +0 -80
  78. package/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ChannelAwareNotificationBuilder.java +0 -134
  79. package/android/src/main/java/expo/modules/notifications/notifications/presentation/builders/ExpoNotificationBuilder.java +0 -292
package/CHANGELOG.md CHANGED
@@ -5,21 +5,46 @@
5
5
  ### 🛠 Breaking changes
6
6
 
7
7
  - Bumped iOS deployment target to 15.1. ([#30840](https://github.com/expo/expo/pull/30840), [#30862](https://github.com/expo/expo/pull/30862) by [@tsapeta](https://github.com/tsapeta))
8
+ - Simplify calendar trigger input types. ([#31598](https://github.com/expo/expo/pull/31598) by [@douglowder](https://github.com/douglowder))
8
9
 
9
10
  ### 🎉 New features
10
11
 
12
+ - Add clearLastNotificationResponseAsync to API. ([#31607](https://github.com/expo/expo/pull/31607) by [@douglowder](https://github.com/douglowder))
13
+ - New monthly trigger type for scheduled notifications. ([#31823](https://github.com/expo/expo/pull/31823) by [@douglowder](https://github.com/douglowder))
14
+
11
15
  ### 🐛 Bug fixes
12
16
 
13
- - [Android] Take `channelId` into account when presenting notifications. ([#31201](https://github.com/expo/expo/pull/31201) by [@vonovak](https://github.com/vonovak))
17
+ - throw improved error on invalid subscription in removeNotificationSubscription ([#31842](https://github.com/expo/expo/pull/31842) by [@vonovak](https://github.com/vonovak))
18
+ - [android] fix notifications actions not being presented ([#31795](https://github.com/expo/expo/pull/31795) by [@vonovak](https://github.com/vonovak))
14
19
  - Add missing `react` and `react-native` peer dependencies for isolated modules. ([#30478](https://github.com/expo/expo/pull/30478) by [@byCedric](https://github.com/byCedric))
15
- - [Android] Eliminate unsupported types when processing notification intents from onCreate/onNewIntent. ([#30750](https://github.com/expo/expo/pull/30750) by [@douglowder](https://github.com/douglowder))
16
- - [Android] Fix content.data in scheduled notifications surfaced to JS. ([#31048](https://github.com/expo/expo/pull/31048) by [@douglowder](https://github.com/douglowder))
17
- - [Android] fix local notifications with null trigger. ([#31157](https://github.com/expo/expo/pull/31157) by [@douglowder](https://github.com/douglowder))
20
+ - [iOS] do not overwrite existing aps entitlement. ([#31892](https://github.com/expo/expo/pull/31892) by [@douglowder](https://github.com/douglowder))
18
21
 
19
22
  ### 💡 Others
20
23
 
24
+ - [android] refactor ExpoNotificationBuilder ([#31838](https://github.com/expo/expo/pull/31838) by [@vonovak](https://github.com/vonovak))
25
+ - Warn about limited support in Expo Go ([#31573](https://github.com/expo/expo/pull/31573) by [@vonovak](https://github.com/vonovak))
21
26
  - Keep using the legacy event emitter as the module is not fully migrated to Expo Modules API. ([#28946](https://github.com/expo/expo/pull/28946) by [@tsapeta](https://github.com/tsapeta))
22
27
 
28
+ ## 0.28.17 - 2024-09-17
29
+
30
+ ### 🐛 Bug fixes
31
+
32
+ - [Android] image was missing on android when in foreground ([#31405](https://github.com/expo/expo/pull/31405) by [@vonovak](https://github.com/vonovak))
33
+ - [Android] fix local notifications with null trigger. ([#31157](https://github.com/expo/expo/pull/31157) by [@douglowder](https://github.com/douglowder))
34
+ - [Android] Take `channelId` into account when presenting notifications. ([#31201](https://github.com/expo/expo/pull/31201) by [@vonovak](https://github.com/vonovak))
35
+
36
+ ## 0.28.16 - 2024-08-21
37
+
38
+ ### 🐛 Bug fixes
39
+
40
+ - [Android] Fix content.data in scheduled notifications surfaced to JS. ([#31048](https://github.com/expo/expo/pull/31048) by [@douglowder](https://github.com/douglowder))
41
+
42
+ ## 0.28.15 - 2024-08-05
43
+
44
+ ### 🐛 Bug fixes
45
+
46
+ - [Android] Eliminate unsupported types when processing notification intents from onCreate/onNewIntent. ([#30750](https://github.com/expo/expo/pull/30750) by [@douglowder](https://github.com/douglowder))
47
+
23
48
  ## 0.28.14 - 2024-07-30
24
49
 
25
50
  ### 🐛 Bug fixes
@@ -15,6 +15,7 @@ android {
15
15
  defaultConfig {
16
16
  versionCode 21
17
17
  versionName '0.28.3'
18
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
18
19
  }
19
20
 
20
21
  buildFeatures {
@@ -34,17 +35,19 @@ android {
34
35
  }
35
36
 
36
37
  dependencies {
37
- api 'androidx.core:core:1.5.0'
38
- api 'androidx.lifecycle:lifecycle-runtime:2.2.0'
39
- api 'androidx.lifecycle:lifecycle-process:2.2.0'
40
- api 'androidx.lifecycle:lifecycle-common-java8:2.2.0'
38
+ implementation 'androidx.core:core:1.6.0'
39
+ implementation 'androidx.lifecycle:lifecycle-runtime:2.2.0'
40
+ implementation 'androidx.lifecycle:lifecycle-process:2.2.0'
41
+ implementation 'androidx.lifecycle:lifecycle-common-java8:2.2.0'
42
+ implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3'
41
43
 
44
+ // release notes in https://firebase.google.com/support/release-notes/android - cmd + f "Cloud Messaging version"
45
+ implementation 'com.google.firebase:firebase-messaging:24.0.1'
42
46
 
43
- api 'com.google.firebase:firebase-messaging:22.0.0'
44
-
45
- api 'me.leolin:ShortcutBadger:1.1.22@aar'
47
+ implementation 'me.leolin:ShortcutBadger:1.1.22@aar'
46
48
 
47
49
  if (project.findProject(':expo-modules-test-core')) {
48
50
  testImplementation project(':expo-modules-test-core')
51
+ androidTestImplementation project(':expo-modules-test-core')
49
52
  }
50
53
  }
@@ -90,11 +90,11 @@ internal fun isValidJSONString(test: Any?): Boolean {
90
90
  when (test is String) {
91
91
  true -> {
92
92
  try {
93
- JSONObject(test as String)
93
+ JSONObject(test)
94
94
  return true
95
95
  } catch (objectEx: JSONException) {
96
96
  try {
97
- JSONArray(test as String)
97
+ JSONArray(test)
98
98
  return true
99
99
  } catch (arrayEx: JSONException) {
100
100
  return false
@@ -30,6 +30,10 @@ public class NotificationManager implements SingletonModule, expo.modules.notifi
30
30
  public NotificationManager() {
31
31
  mListenerReferenceMap = new WeakHashMap<>();
32
32
 
33
+ // TODO @vonovak there's a chain of listeners:
34
+ // ExpoHandlingDelegate -> NotificationManager -> NotificationsEmitter
35
+ // -> NotificationsHandler
36
+ // it seems it could be shorter?
33
37
  // Registers this singleton instance in static ExpoHandlingDelegate listeners collection.
34
38
  // Since it doesn't hold strong reference to the object this should be safe.
35
39
  ExpoHandlingDelegate.Companion.addListener(this);
@@ -81,6 +85,10 @@ public class NotificationManager implements SingletonModule, expo.modules.notifi
81
85
  * Calls {@link NotificationListener#onNotificationReceived(Notification)} on all values
82
86
  * of {@link NotificationManager#mListenerReferenceMap}.
83
87
  *
88
+ * In practice, that means calling {@link NotificationsEmitter} (just emits an event to JS) and
89
+ * {@link NotificationsHandler} which calls `handleNotification` in JS to determine the behavior.
90
+ * Then `SingleNotificationHandlerTask.processNotificationWithBehavior` may present it.
91
+ *
84
92
  * @param notification Notification received
85
93
  */
86
94
  public void onNotificationReceived(Notification notification) {
@@ -3,7 +3,6 @@ package expo.modules.notifications.notifications;
3
3
  import static expo.modules.notifications.UtilsKt.filteredBundleForJSTypeConverter;
4
4
  import static expo.modules.notifications.UtilsKt.isValidJSONString;
5
5
 
6
- import android.os.Build;
7
6
  import android.os.Bundle;
8
7
 
9
8
  import androidx.annotation.Nullable;
@@ -22,10 +21,10 @@ import java.util.List;
22
21
  import java.util.Map;
23
22
  import java.util.Set;
24
23
 
24
+ import expo.modules.notifications.notifications.interfaces.INotificationContent;
25
25
  import expo.modules.notifications.notifications.interfaces.NotificationTrigger;
26
26
  import expo.modules.notifications.notifications.interfaces.SchedulableNotificationTrigger;
27
27
  import expo.modules.notifications.notifications.model.Notification;
28
- import expo.modules.notifications.notifications.model.NotificationContent;
29
28
  import expo.modules.notifications.notifications.model.NotificationRequest;
30
29
  import expo.modules.notifications.notifications.model.NotificationResponse;
31
30
  import expo.modules.notifications.notifications.model.TextInputNotificationResponse;
@@ -33,6 +32,7 @@ import expo.modules.notifications.notifications.model.triggers.FirebaseNotificat
33
32
 
34
33
  import expo.modules.notifications.notifications.triggers.DailyTrigger;
35
34
  import expo.modules.notifications.notifications.triggers.DateTrigger;
35
+ import expo.modules.notifications.notifications.triggers.MonthlyTrigger;
36
36
  import expo.modules.notifications.notifications.triggers.TimeIntervalTrigger;
37
37
  import expo.modules.notifications.notifications.triggers.WeeklyTrigger;
38
38
  import expo.modules.notifications.notifications.triggers.YearlyTrigger;
@@ -51,7 +51,7 @@ public class NotificationSerializer {
51
51
  public static Bundle toBundle(Notification notification) {
52
52
  Bundle serializedNotification = new Bundle();
53
53
  serializedNotification.putBundle("request", toBundle(notification.getNotificationRequest()));
54
- serializedNotification.putLong("date", notification.getDate().getTime());
54
+ serializedNotification.putLong("date", notification.getOriginDate().getTime());
55
55
  return serializedNotification;
56
56
  }
57
57
 
@@ -99,10 +99,10 @@ public class NotificationSerializer {
99
99
  return result;
100
100
  }
101
101
 
102
- public static Bundle toBundle(NotificationContent content) {
102
+ public static Bundle toBundle(INotificationContent content) {
103
103
  Bundle serializedContent = new Bundle();
104
104
  serializedContent.putString("title", content.getTitle());
105
- serializedContent.putString("subtitle", content.getSubtitle());
105
+ serializedContent.putString("subtitle", content.getSubText());
106
106
  serializedContent.putString("body", content.getText());
107
107
  if (content.getColor() != null) {
108
108
  serializedContent.putString("color", String.format("#%08X", content.getColor().intValue()));
@@ -113,9 +113,9 @@ public class NotificationSerializer {
113
113
  } else {
114
114
  serializedContent.putString("badge", null);
115
115
  }
116
- if (content.shouldPlayDefaultSound()) {
116
+ if (content.getShouldPlayDefaultSound()) {
117
117
  serializedContent.putString("sound", "default");
118
- } else if (content.getSound() != null) {
118
+ } else if (content.getSoundName() != null) {
119
119
  serializedContent.putString("sound", "custom");
120
120
  } else {
121
121
  serializedContent.putString("sound", null);
@@ -212,6 +212,11 @@ public class NotificationSerializer {
212
212
  bundle.putInt("weekday", ((WeeklyTrigger) trigger).getWeekday());
213
213
  bundle.putInt("hour", ((WeeklyTrigger) trigger).getHour());
214
214
  bundle.putInt("minute", ((WeeklyTrigger) trigger).getMinute());
215
+ } else if (trigger instanceof MonthlyTrigger) {
216
+ bundle.putString("type", "monthly");
217
+ bundle.putInt("day", ((MonthlyTrigger) trigger).getDay());
218
+ bundle.putInt("hour", ((MonthlyTrigger) trigger).getHour());
219
+ bundle.putInt("minute", ((MonthlyTrigger) trigger).getMinute());
215
220
  } else if (trigger instanceof YearlyTrigger) {
216
221
  bundle.putString("type", "yearly");
217
222
  bundle.putInt("day", ((YearlyTrigger) trigger).getDay());
@@ -228,10 +233,7 @@ public class NotificationSerializer {
228
233
 
229
234
  @Nullable
230
235
  private static String getChannelId(NotificationTrigger trigger) {
231
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
232
- return trigger.getNotificationChannel();
233
- }
234
- return null;
236
+ return trigger.getNotificationChannel();
235
237
  }
236
238
 
237
239
  @NotNull
@@ -9,7 +9,7 @@ import androidx.annotation.Nullable;
9
9
 
10
10
  /**
11
11
  * A shared logic between ContentBuilders ({@link ArgumentsNotificationContentBuilder}
12
- * and {@link JSONNotificationContentBuilder}) for resolving sounds based on the "sound" property.
12
+ * and {@link RemoteNotificationContent}) for resolving sounds based on the "soundName" property.
13
13
  */
14
14
  public class SoundResolver {
15
15
  private Context mContext;
@@ -25,9 +25,10 @@ import expo.modules.interfaces.taskManager.TaskManagerUtilsInterface;
25
25
  /**
26
26
  * Represents a task to be run when the app is receives a remote push
27
27
  * notification. Map of current tasks is maintained in {@link FirebaseMessagingDelegate}.
28
+ *
29
+ * Instances are instantiated by expo task manager, after being registered in ExpoBackgroundNotificationTasksModule
28
30
  */
29
31
  public class BackgroundRemoteNotificationTaskConsumer extends TaskConsumer implements TaskConsumerInterface {
30
- private static final String TAG = BackgroundRemoteNotificationTaskConsumer.class.getSimpleName();
31
32
  private static final String NOTIFICATION_KEY = "notification";
32
33
 
33
34
  private TaskInterface mTask;
@@ -2,25 +2,13 @@ package expo.modules.notifications.notifications.channels;
2
2
 
3
3
  import android.content.Context;
4
4
 
5
- import expo.modules.core.ModuleRegistry;
6
5
  import expo.modules.core.interfaces.InternalModule;
7
6
 
8
7
  import java.util.Collections;
9
8
  import java.util.List;
10
9
 
11
- import expo.modules.notifications.notifications.channels.managers.NotificationsChannelGroupManager;
12
- import expo.modules.notifications.notifications.channels.managers.NotificationsChannelManager;
13
- import expo.modules.notifications.notifications.channels.serializers.NotificationsChannelGroupSerializer;
14
- import expo.modules.notifications.notifications.channels.serializers.NotificationsChannelSerializer;
15
-
16
10
  public abstract class AbstractNotificationsChannelsProvider implements NotificationsChannelsProvider, InternalModule {
17
11
  protected final Context mContext;
18
- private NotificationsChannelManager mChannelManager;
19
- private NotificationsChannelGroupManager mChannelGroupManager;
20
- private NotificationsChannelSerializer mChannelSerializer;
21
- private NotificationsChannelGroupSerializer mChannelGroupSerializer;
22
-
23
- private ModuleRegistry mModuleRegistry;
24
12
 
25
13
  public AbstractNotificationsChannelsProvider(Context context) {
26
14
  mContext = context;
@@ -30,52 +18,4 @@ public abstract class AbstractNotificationsChannelsProvider implements Notificat
30
18
  return Collections.singletonList(NotificationsChannelsProvider.class);
31
19
  }
32
20
 
33
- @Override
34
- public void onCreate(ModuleRegistry moduleRegistry) {
35
- mModuleRegistry = moduleRegistry;
36
- }
37
-
38
- public final ModuleRegistry getModuleRegistry() {
39
- return mModuleRegistry;
40
- }
41
-
42
- @Override
43
- public final NotificationsChannelManager getChannelManager() {
44
- if (mChannelManager == null) {
45
- mChannelManager = createChannelManager();
46
- }
47
- return mChannelManager;
48
- }
49
-
50
- @Override
51
- public final NotificationsChannelGroupManager getGroupManager() {
52
- if (mChannelGroupManager == null) {
53
- mChannelGroupManager = createChannelGroupManager();
54
- }
55
- return mChannelGroupManager;
56
- }
57
-
58
- @Override
59
- public final NotificationsChannelSerializer getChannelSerializer() {
60
- if (mChannelSerializer == null) {
61
- mChannelSerializer = createChannelSerializer();
62
- }
63
- return mChannelSerializer;
64
- }
65
-
66
- @Override
67
- public final NotificationsChannelGroupSerializer getGroupSerializer() {
68
- if (mChannelGroupSerializer == null) {
69
- mChannelGroupSerializer = createChannelGroupSerializer();
70
- }
71
- return mChannelGroupSerializer;
72
- }
73
-
74
- protected abstract NotificationsChannelManager createChannelManager();
75
-
76
- protected abstract NotificationsChannelGroupManager createChannelGroupManager();
77
-
78
- protected abstract NotificationsChannelSerializer createChannelSerializer();
79
-
80
- protected abstract NotificationsChannelGroupSerializer createChannelGroupSerializer();
81
21
  }
@@ -0,0 +1,26 @@
1
+ package expo.modules.notifications.notifications.channels
2
+
3
+ import android.content.Context
4
+ import expo.modules.notifications.notifications.channels.managers.AndroidXNotificationsChannelGroupManager
5
+ import expo.modules.notifications.notifications.channels.managers.AndroidXNotificationsChannelManager
6
+ import expo.modules.notifications.notifications.channels.serializers.ExpoNotificationsChannelGroupSerializer
7
+ import expo.modules.notifications.notifications.channels.serializers.ExpoNotificationsChannelSerializer
8
+
9
+ class AndroidXNotificationsChannelsProvider(context: Context) : AbstractNotificationsChannelsProvider(context) {
10
+
11
+ override val groupManager by lazy {
12
+ AndroidXNotificationsChannelGroupManager(context)
13
+ }
14
+
15
+ override val channelManager by lazy {
16
+ AndroidXNotificationsChannelManager(context, groupManager)
17
+ }
18
+
19
+ override val channelSerializer by lazy {
20
+ ExpoNotificationsChannelSerializer()
21
+ }
22
+
23
+ override val groupSerializer by lazy {
24
+ ExpoNotificationsChannelGroupSerializer(channelSerializer)
25
+ }
26
+ }
@@ -0,0 +1,13 @@
1
+ package expo.modules.notifications.notifications.channels
2
+
3
+ import expo.modules.notifications.notifications.channels.managers.NotificationsChannelGroupManager
4
+ import expo.modules.notifications.notifications.channels.managers.NotificationsChannelManager
5
+ import expo.modules.notifications.notifications.channels.serializers.NotificationsChannelGroupSerializer
6
+ import expo.modules.notifications.notifications.channels.serializers.NotificationsChannelSerializer
7
+
8
+ interface NotificationsChannelsProvider {
9
+ val channelManager: NotificationsChannelManager
10
+ val groupManager: NotificationsChannelGroupManager
11
+ val channelSerializer: NotificationsChannelSerializer
12
+ val groupSerializer: NotificationsChannelGroupSerializer
13
+ }
@@ -54,10 +54,9 @@ public class AndroidXNotificationsChannelGroupManager implements NotificationsCh
54
54
  // Processing options
55
55
  @RequiresApi(api = Build.VERSION_CODES.O)
56
56
  protected void configureGroupWithOptions(Object maybeGroup, ReadableArguments groupOptions) {
57
- if (!(maybeGroup instanceof NotificationChannelGroup)) {
57
+ if (!(maybeGroup instanceof NotificationChannelGroup group)) {
58
58
  return;
59
59
  }
60
- NotificationChannelGroup group = (NotificationChannelGroup) maybeGroup;
61
60
  if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
62
61
  if (groupOptions.containsKey(DESCRIPTION_KEY)) {
63
62
  group.setDescription(groupOptions.getString(DESCRIPTION_KEY));
@@ -61,7 +61,6 @@ object DebugLogging {
61
61
  Log.i("expo-notifications", logMessage)
62
62
  }
63
63
 
64
- @RequiresApi(Build.VERSION_CODES.O)
65
64
  fun logNotification(caller: String, notification: Notification) {
66
65
  if (!BuildConfig.DEBUG) {
67
66
  // Do not log for release/production builds
@@ -71,14 +70,13 @@ object DebugLogging {
71
70
  """
72
71
  $caller:
73
72
  notification.notificationRequest.content.title: ${notification.notificationRequest.content.title}
74
- notification.notificationRequest.content.subtitle: ${notification.notificationRequest.content.subtitle}
73
+ notification.notificationRequest.content.subText: ${notification.notificationRequest.content.subText}
75
74
  notification.notificationRequest.content.text: ${notification.notificationRequest.content.text}
76
- notification.notificationRequest.content.sound: ${notification.notificationRequest.content.sound}
75
+ notification.notificationRequest.content.sound: ${notification.notificationRequest.content.soundName}
77
76
  notification.notificationRequest.content.channelID: ${notification.notificationRequest.trigger.notificationChannel}
78
77
  notification.notificationRequest.content.body: ${notification.notificationRequest.content.body}
79
78
  notification.notificationRequest.content.color: ${notification.notificationRequest.content.color}
80
- notification.notificationRequest.content.vibrationPattern: ${notification.notificationRequest.content.vibrationPattern.contentToString()}
81
- notification.notificationRequest.trigger.notificationChannel: ${notification.notificationRequest.trigger.notificationChannel}
79
+ notification.notificationRequest.content.vibrationPattern: ${notification.notificationRequest.content.vibrationPattern?.contentToString()}
82
80
  notification.notificationRequest.identifier: ${notification.notificationRequest.identifier}
83
81
  """.trimIndent()
84
82
 
@@ -41,6 +41,11 @@ open class NotificationsEmitter : Module(), NotificationListener {
41
41
  AsyncFunction<Bundle?>("getLastNotificationResponseAsync") {
42
42
  lastNotificationResponseBundle
43
43
  }
44
+
45
+ AsyncFunction("clearLastNotificationResponseAsync") {
46
+ lastNotificationResponseBundle = null
47
+ null
48
+ }
44
49
  }
45
50
 
46
51
  /**
@@ -99,7 +99,7 @@ open class NotificationsHandler : Module(), NotificationListener {
99
99
  ?: throw NotificationWasAlreadyHandledException(identifier)
100
100
 
101
101
  with(behavior) {
102
- task.handleResponse(
102
+ task.processNotificationWithBehavior(
103
103
  NotificationBehavior(shouldShowAlert, shouldPlaySound, shouldSetBadge, priority),
104
104
  promise
105
105
  )
@@ -110,6 +110,8 @@ open class NotificationsHandler : Module(), NotificationListener {
110
110
  * Callback called by [NotificationManager] to inform its listeners of new messages.
111
111
  * Starts up a new [SingleNotificationHandlerTask] which will take it on from here.
112
112
  *
113
+ * SingleNotificationHandlerTask.processNotificationWithBehavior can then present it
114
+ *
113
115
  * @param notification Notification received
114
116
  */
115
117
  override fun onNotificationReceived(notification: Notification) {
@@ -34,7 +34,6 @@ public class SingleNotificationHandlerTask {
34
34
  private Handler mHandler;
35
35
  private EventEmitter mEventEmitter;
36
36
  private Notification mNotification;
37
- private NotificationBehavior mBehavior;
38
37
  private Context mContext;
39
38
  private NotificationsHandler mDelegate;
40
39
 
@@ -88,12 +87,11 @@ public class SingleNotificationHandlerTask {
88
87
  * @param behavior Behavior requested by the app
89
88
  * @param promise Promise to fulfill once the behavior is applied to the notification.
90
89
  */
91
- /* package */ void handleResponse(NotificationBehavior behavior, final Promise promise) {
92
- mBehavior = behavior;
90
+ /* package */ void processNotificationWithBehavior(final NotificationBehavior behavior, final Promise promise) {
93
91
  mHandler.post(new Runnable() {
94
92
  @Override
95
93
  public void run() {
96
- NotificationsService.Companion.present(mContext, mNotification, mBehavior, new ResultReceiver(mHandler) {
94
+ NotificationsService.Companion.present(mContext, mNotification, behavior, new ResultReceiver(mHandler) {
97
95
  @Override
98
96
  protected void onReceiveResult(int resultCode, Bundle resultData) {
99
97
  super.onReceiveResult(resultCode, resultData);
@@ -0,0 +1,38 @@
1
+ package expo.modules.notifications.notifications.interfaces
2
+
3
+ import android.content.Context
4
+ import android.graphics.Bitmap
5
+ import android.os.Parcelable
6
+ import expo.modules.notifications.notifications.enums.NotificationPriority
7
+ import org.json.JSONObject
8
+
9
+ /**
10
+ * This interface is implemented by classes representing notification content.
11
+ * I.e. local notifications [NotificationContent] and remote notifications [RemoteNotificationContent].
12
+ *
13
+ * The reason the two classes exist is that one is persisted locally in SharedPreferences, and the other is not.
14
+ * The first is therefore a bit "fragile" and harder to refactor, while the second is easier to change.
15
+ * This interface exists to provide a common API for both classes.
16
+ * */
17
+ interface INotificationContent : Parcelable {
18
+ val title: String?
19
+ val text: String?
20
+ val subText: String?
21
+ val badgeCount: Number?
22
+ val shouldPlayDefaultSound: Boolean
23
+
24
+ // soundName is better off as a string (was an Uri) because in RemoteNotification we can obtain the sound name
25
+ // in local notification we store the uri and derive the sound name from it
26
+ val soundName: String?
27
+ val shouldUseDefaultVibrationPattern: Boolean
28
+ val vibrationPattern: LongArray?
29
+ val body: JSONObject?
30
+ val priority: NotificationPriority?
31
+ val color: Number?
32
+ val isAutoDismiss: Boolean
33
+ val categoryId: String?
34
+ val isSticky: Boolean
35
+
36
+ fun containsImage(): Boolean
37
+ suspend fun getImage(context: Context): Bitmap?
38
+ }
@@ -0,0 +1,26 @@
1
+ package expo.modules.notifications.notifications.interfaces
2
+
3
+ import expo.modules.notifications.notifications.model.Notification
4
+ import expo.modules.notifications.notifications.model.NotificationBehavior
5
+
6
+ /**
7
+ * An object capable of building a [Notification] based
8
+ * on a [NotificationContent] spec.
9
+ */
10
+ interface NotificationBuilder {
11
+ /**
12
+ * Pass in a [NotificationBehavior] if you want to override the behavior
13
+ * of the notification, i.e. whether it should show a heads-up alert, set badge, etc.
14
+ *
15
+ * @param behavior [NotificationBehavior] to which the presentation effect should conform.
16
+ * @return The same instance of [NotificationBuilder] updated with the remote message.
17
+ */
18
+ fun setAllowedBehavior(behavior: NotificationBehavior?): NotificationBuilder
19
+
20
+ /**
21
+ * Builds the Android notification based on passed in data.
22
+ *
23
+ * @return Built notification.
24
+ */
25
+ suspend fun build(): android.app.Notification
26
+ }
@@ -13,7 +13,7 @@ import expo.modules.notifications.notifications.model.NotificationResponse;
13
13
  */
14
14
  public interface NotificationListener {
15
15
  /**
16
- * Callback called when new notification is received.
16
+ * Callback called when new notification is received while the app is in foreground.
17
17
  *
18
18
  * @param notification Notification received
19
19
  */
@@ -1,10 +1,8 @@
1
1
  package expo.modules.notifications.notifications.interfaces;
2
2
 
3
- import android.os.Build;
4
3
  import android.os.Parcelable;
5
4
 
6
5
  import androidx.annotation.Nullable;
7
- import androidx.annotation.RequiresApi;
8
6
 
9
7
  /**
10
8
  * An interface specifying source of the notification, to be implemented
@@ -12,7 +10,6 @@ import androidx.annotation.RequiresApi;
12
10
  */
13
11
  public interface NotificationTrigger extends Parcelable {
14
12
  @Nullable
15
- @RequiresApi(api = Build.VERSION_CODES.O)
16
13
  default String getNotificationChannel() {
17
14
  return null;
18
15
  }
@@ -6,11 +6,11 @@ import android.os.Parcelable;
6
6
  import java.util.Date;
7
7
 
8
8
  /**
9
- * A class representing a single notification received at a particular moment ({@link #mDate}).
9
+ * A class representing a single notification. Origin date ({@link #mOriginDate}) is time when it was sent (remote) or when it was posted (local).
10
10
  */
11
11
  public class Notification implements Parcelable {
12
12
  private NotificationRequest mRequest;
13
- private Date mDate;
13
+ private Date mOriginDate;
14
14
 
15
15
  public Notification(NotificationRequest request) {
16
16
  this(request, new Date());
@@ -18,16 +18,16 @@ public class Notification implements Parcelable {
18
18
 
19
19
  public Notification(NotificationRequest request, Date date) {
20
20
  mRequest = request;
21
- mDate = date;
21
+ mOriginDate = date;
22
22
  }
23
23
 
24
24
  protected Notification(Parcel in) {
25
25
  mRequest = in.readParcelable(getClass().getClassLoader());
26
- mDate = new Date(in.readLong());
26
+ mOriginDate = new Date(in.readLong());
27
27
  }
28
28
 
29
- public Date getDate() {
30
- return mDate;
29
+ public Date getOriginDate() {
30
+ return mOriginDate;
31
31
  }
32
32
 
33
33
  public NotificationRequest getNotificationRequest() {
@@ -54,6 +54,6 @@ public class Notification implements Parcelable {
54
54
  @Override
55
55
  public void writeToParcel(Parcel dest, int flags) {
56
56
  dest.writeParcelable(mRequest, 0);
57
- dest.writeLong(mDate.getTime());
57
+ dest.writeLong(mOriginDate.getTime());
58
58
  }
59
59
  }
@@ -7,6 +7,9 @@ import java.io.Serializable;
7
7
 
8
8
  /**
9
9
  * A class representing a single notification action button.
10
+ *
11
+ * TODO vonovak: no need to implement serializable, parcelable is enough for storing
12
+ *
10
13
  */
11
14
  public class NotificationAction implements Parcelable, Serializable {
12
15
  private final String mIdentifier;
@@ -9,6 +9,8 @@ import java.util.List;
9
9
 
10
10
  /**
11
11
  * A class representing a collection of notification actions.
12
+ *
13
+ * TODO vonovak: no need to implement serializable, parcelable is enough for storing
12
14
  */
13
15
  public class NotificationCategory implements Parcelable, Serializable {
14
16
  private final String mIdentifier;