react-native-notify-kit 9.1.21 → 9.2.0

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 (89) hide show
  1. package/README.md +6 -2
  2. package/RNNotifee.podspec +1 -0
  3. package/android/build.gradle +67 -35
  4. package/android/proguard-rules.pro +14 -1
  5. package/android/schemas/app.notifee.core.database.NotifeeCoreDatabase/1.json +44 -0
  6. package/android/schemas/app.notifee.core.database.NotifeeCoreDatabase/2.json +51 -0
  7. package/android/src/androidTest/java/app/notifee/core/ExampleInstrumentedTest.java +25 -0
  8. package/android/src/androidTest/java/app/notifee/core/database/NotifeeCoreDatabaseTest.java +55 -0
  9. package/android/src/main/AndroidManifest.xml +71 -4
  10. package/android/src/main/java/app/notifee/core/AlarmPermissionBroadcastReceiver.java +25 -0
  11. package/android/src/main/java/app/notifee/core/BlockStateBroadcastReceiver.java +164 -0
  12. package/android/src/main/java/app/notifee/core/ChannelManager.java +350 -0
  13. package/android/src/main/java/app/notifee/core/ContextHolder.java +33 -0
  14. package/android/src/main/java/app/notifee/core/EventBus.java +63 -0
  15. package/android/src/main/java/app/notifee/core/EventSubscriber.java +82 -0
  16. package/android/src/main/java/app/notifee/core/ForegroundService.java +347 -0
  17. package/android/src/main/java/app/notifee/core/InitProvider.java +93 -0
  18. package/android/src/main/java/app/notifee/core/KeepForSdk.java +26 -0
  19. package/android/src/main/java/app/notifee/core/Logger.java +68 -0
  20. package/android/src/main/java/app/notifee/core/Notifee.java +570 -0
  21. package/android/src/main/java/app/notifee/core/NotifeeAlarmManager.java +352 -0
  22. package/android/src/main/java/app/notifee/core/NotificationAlarmReceiver.java +42 -0
  23. package/android/src/main/java/app/notifee/core/NotificationManager.java +939 -0
  24. package/android/src/main/java/app/notifee/core/NotificationPendingIntent.java +191 -0
  25. package/android/src/main/java/app/notifee/core/NotificationReceiverActivity.java +39 -0
  26. package/android/src/main/java/app/notifee/core/NotificationReceiverHandler.java +144 -0
  27. package/android/src/main/java/app/notifee/core/Preferences.java +79 -0
  28. package/android/src/main/java/app/notifee/core/RebootBroadcastReceiver.java +39 -0
  29. package/android/src/main/java/app/notifee/core/ReceiverService.java +281 -0
  30. package/android/src/main/java/app/notifee/core/Worker.java +87 -0
  31. package/android/src/main/java/app/notifee/core/database/NotifeeCoreDatabase.java +77 -0
  32. package/android/src/main/java/app/notifee/core/database/WorkDataDao.java +52 -0
  33. package/android/src/main/java/app/notifee/core/database/WorkDataEntity.java +68 -0
  34. package/android/src/main/java/app/notifee/core/database/WorkDataRepository.java +107 -0
  35. package/android/src/main/java/app/notifee/core/event/BlockStateEvent.java +102 -0
  36. package/android/src/main/java/app/notifee/core/event/ForegroundServiceEvent.java +48 -0
  37. package/android/src/main/java/app/notifee/core/event/InitialNotificationEvent.java +50 -0
  38. package/android/src/main/java/app/notifee/core/event/LogEvent.java +74 -0
  39. package/android/src/main/java/app/notifee/core/event/MainComponentEvent.java +33 -0
  40. package/android/src/main/java/app/notifee/core/event/NotificationEvent.java +107 -0
  41. package/android/src/main/java/app/notifee/core/interfaces/EventListener.java +39 -0
  42. package/android/src/main/java/app/notifee/core/interfaces/MethodCallResult.java +27 -0
  43. package/android/src/main/java/app/notifee/core/model/ChannelGroupModel.java +48 -0
  44. package/android/src/main/java/app/notifee/core/model/ChannelModel.java +126 -0
  45. package/android/src/main/java/app/notifee/core/model/IntervalTriggerModel.java +63 -0
  46. package/android/src/main/java/app/notifee/core/model/NotificationAndroidActionModel.java +125 -0
  47. package/android/src/main/java/app/notifee/core/model/NotificationAndroidModel.java +688 -0
  48. package/android/src/main/java/app/notifee/core/model/NotificationAndroidPressActionModel.java +150 -0
  49. package/android/src/main/java/app/notifee/core/model/NotificationAndroidStyleModel.java +336 -0
  50. package/android/src/main/java/app/notifee/core/model/NotificationModel.java +72 -0
  51. package/android/src/main/java/app/notifee/core/model/TimestampTriggerModel.java +206 -0
  52. package/android/src/main/java/app/notifee/core/model/package-info.java +4 -0
  53. package/android/src/main/java/app/notifee/core/utility/AlarmUtils.java +52 -0
  54. package/android/src/main/java/app/notifee/core/utility/Callbackable.java +12 -0
  55. package/android/src/main/java/app/notifee/core/utility/ColorUtils.java +62 -0
  56. package/android/src/main/java/app/notifee/core/utility/ExtendedListenableFuture.java +84 -0
  57. package/android/src/main/java/app/notifee/core/utility/IntentUtils.java +146 -0
  58. package/android/src/main/java/app/notifee/core/utility/ObjectUtils.java +191 -0
  59. package/android/src/main/java/app/notifee/core/utility/PowerManagerUtils.java +338 -0
  60. package/android/src/main/java/app/notifee/core/utility/ResourceUtils.java +308 -0
  61. package/android/src/main/java/app/notifee/core/utility/TextUtils.java +28 -0
  62. package/android/src/main/java/app/notifee/core/utility/package-info.java +4 -0
  63. package/android/src/test/java/app/notifee/core/model/NotificationAndroidPressActionModelTest.java +56 -0
  64. package/android/src/test/java/app/notifee/core/model/TimestampTriggerModelTest.java +44 -0
  65. package/dist/version.d.ts +1 -1
  66. package/dist/version.js +1 -1
  67. package/dist/version.js.map +1 -1
  68. package/package.json +2 -2
  69. package/src/version.ts +1 -1
  70. package/android/libs/app/notifee/core/202108261754/core-202108261754.aar +0 -0
  71. package/android/libs/app/notifee/core/202108261754/core-202108261754.aar.md5 +0 -1
  72. package/android/libs/app/notifee/core/202108261754/core-202108261754.aar.sha1 +0 -1
  73. package/android/libs/app/notifee/core/202108261754/core-202108261754.aar.sha256 +0 -1
  74. package/android/libs/app/notifee/core/202108261754/core-202108261754.aar.sha512 +0 -1
  75. package/android/libs/app/notifee/core/202108261754/core-202108261754.module +0 -146
  76. package/android/libs/app/notifee/core/202108261754/core-202108261754.module.md5 +0 -1
  77. package/android/libs/app/notifee/core/202108261754/core-202108261754.module.sha1 +0 -1
  78. package/android/libs/app/notifee/core/202108261754/core-202108261754.module.sha256 +0 -1
  79. package/android/libs/app/notifee/core/202108261754/core-202108261754.module.sha512 +0 -1
  80. package/android/libs/app/notifee/core/202108261754/core-202108261754.pom +0 -64
  81. package/android/libs/app/notifee/core/202108261754/core-202108261754.pom.md5 +0 -1
  82. package/android/libs/app/notifee/core/202108261754/core-202108261754.pom.sha1 +0 -1
  83. package/android/libs/app/notifee/core/202108261754/core-202108261754.pom.sha256 +0 -1
  84. package/android/libs/app/notifee/core/202108261754/core-202108261754.pom.sha512 +0 -1
  85. package/android/libs/app/notifee/core/maven-metadata.xml +0 -13
  86. package/android/libs/app/notifee/core/maven-metadata.xml.md5 +0 -1
  87. package/android/libs/app/notifee/core/maven-metadata.xml.sha1 +0 -1
  88. package/android/libs/app/notifee/core/maven-metadata.xml.sha256 +0 -1
  89. package/android/libs/app/notifee/core/maven-metadata.xml.sha512 +0 -1
@@ -0,0 +1,352 @@
1
+ package app.notifee.core;
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ import static app.notifee.core.ContextHolder.getApplicationContext;
21
+
22
+ import android.app.AlarmManager;
23
+ import android.app.PendingIntent;
24
+ import android.content.BroadcastReceiver;
25
+ import android.content.Context;
26
+ import android.content.Intent;
27
+ import android.os.Build;
28
+ import android.os.Bundle;
29
+ import androidx.annotation.Nullable;
30
+ import androidx.core.app.AlarmManagerCompat;
31
+ import app.notifee.core.database.WorkDataEntity;
32
+ import app.notifee.core.database.WorkDataRepository;
33
+ import app.notifee.core.model.NotificationModel;
34
+ import app.notifee.core.model.TimestampTriggerModel;
35
+ import app.notifee.core.utility.AlarmUtils;
36
+ import app.notifee.core.utility.ExtendedListenableFuture;
37
+ import app.notifee.core.utility.ObjectUtils;
38
+ import com.google.common.util.concurrent.FutureCallback;
39
+ import com.google.common.util.concurrent.Futures;
40
+ import com.google.common.util.concurrent.ListenableFuture;
41
+ import com.google.common.util.concurrent.ListeningExecutorService;
42
+ import com.google.common.util.concurrent.MoreExecutors;
43
+ import java.util.Arrays;
44
+ import java.util.List;
45
+ import java.util.concurrent.ExecutorService;
46
+ import java.util.concurrent.Executors;
47
+
48
+ class NotifeeAlarmManager {
49
+ private static final String TAG = "NotifeeAlarmManager";
50
+ private static final String NOTIFICATION_ID_INTENT_KEY = "notificationId";
51
+ private static final ExecutorService alarmManagerExecutor = Executors.newCachedThreadPool();
52
+ private static final ListeningExecutorService alarmManagerListeningExecutor =
53
+ MoreExecutors.listeningDecorator(alarmManagerExecutor);
54
+
55
+ static void displayScheduledNotification(
56
+ Bundle alarmManagerNotification, @Nullable BroadcastReceiver.PendingResult pendingResult) {
57
+ if (alarmManagerNotification == null) {
58
+ if (pendingResult != null) {
59
+ pendingResult.finish();
60
+ }
61
+ return;
62
+ }
63
+ String id = alarmManagerNotification.getString(NOTIFICATION_ID_INTENT_KEY);
64
+
65
+ if (id == null) {
66
+ if (pendingResult != null) {
67
+ pendingResult.finish();
68
+ }
69
+ return;
70
+ }
71
+
72
+ WorkDataRepository workDataRepository = new WorkDataRepository(getApplicationContext());
73
+
74
+ ListenableFuture<?> displayFuture =
75
+ new ExtendedListenableFuture<>(workDataRepository.getWorkDataById(id))
76
+ .continueWith(
77
+ workDataEntity -> {
78
+ Bundle notificationBundle;
79
+
80
+ Bundle triggerBundle;
81
+
82
+ if (workDataEntity == null
83
+ || workDataEntity.getNotification() == null
84
+ || workDataEntity.getTrigger() == null) {
85
+ // check if notification bundle is stored with Work Manager
86
+ Logger.w(
87
+ TAG,
88
+ "Attempted to handle doScheduledWork but no notification data was found.");
89
+ return Futures.immediateFuture(null);
90
+ } else {
91
+ triggerBundle = ObjectUtils.bytesToBundle(workDataEntity.getTrigger());
92
+ notificationBundle =
93
+ ObjectUtils.bytesToBundle(workDataEntity.getNotification());
94
+ }
95
+
96
+ NotificationModel notificationModel =
97
+ NotificationModel.fromBundle(notificationBundle);
98
+
99
+ return new ExtendedListenableFuture<>(
100
+ NotificationManager.displayNotification(notificationModel, triggerBundle))
101
+ .continueWith(
102
+ voidDisplayedNotification -> {
103
+ if (triggerBundle.containsKey("repeatFrequency")
104
+ && ObjectUtils.getInt(triggerBundle.get("repeatFrequency")) != -1) {
105
+ TimestampTriggerModel trigger =
106
+ TimestampTriggerModel.fromBundle(triggerBundle);
107
+ // scheduleTimestampTriggerNotification() calls setNextTimestamp()
108
+ // internally, so we must NOT call it here to avoid double-advancing
109
+ scheduleTimestampTriggerNotification(notificationModel, trigger);
110
+ WorkDataRepository.getInstance(getApplicationContext())
111
+ .update(
112
+ new WorkDataEntity(
113
+ id,
114
+ workDataEntity.getNotification(),
115
+ ObjectUtils.bundleToBytes(trigger.toBundle()),
116
+ true));
117
+ } else {
118
+ // not repeating, delete database entry if work is a one-time request
119
+ WorkDataRepository.getInstance(getApplicationContext())
120
+ .deleteById(id);
121
+ }
122
+ return Futures.immediateFuture(null);
123
+ },
124
+ alarmManagerExecutor);
125
+ },
126
+ alarmManagerExecutor)
127
+ .addOnCompleteListener(
128
+ (e, result) -> {
129
+ try {
130
+ if (e != null) {
131
+ Logger.e(TAG, "Failed to display notification", e);
132
+ }
133
+ } finally {
134
+ if (pendingResult != null) {
135
+ pendingResult.finish();
136
+ }
137
+ }
138
+ },
139
+ alarmManagerExecutor);
140
+ }
141
+
142
+ public static PendingIntent getAlarmManagerIntentForNotification(String notificationId) {
143
+ try {
144
+ Context context = getApplicationContext();
145
+ Intent notificationIntent = new Intent(context, NotificationAlarmReceiver.class);
146
+ notificationIntent.putExtra(NOTIFICATION_ID_INTENT_KEY, notificationId);
147
+ return PendingIntent.getBroadcast(
148
+ context,
149
+ notificationId.hashCode(),
150
+ notificationIntent,
151
+ PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
152
+
153
+ } catch (Exception e) {
154
+ Logger.e(TAG, "Unable to create AlarmManager intent", e);
155
+ }
156
+
157
+ return null;
158
+ }
159
+
160
+ static void scheduleTimestampTriggerNotification(
161
+ NotificationModel notificationModel, TimestampTriggerModel timestampTrigger) {
162
+
163
+ PendingIntent pendingIntent = getAlarmManagerIntentForNotification(notificationModel.getId());
164
+
165
+ if (pendingIntent == null) {
166
+ Logger.w(
167
+ TAG, "Failed to create PendingIntent for notification: " + notificationModel.getId());
168
+ return;
169
+ }
170
+
171
+ AlarmManager alarmManager = AlarmUtils.getAlarmManager();
172
+
173
+ TimestampTriggerModel.AlarmType alarmType = timestampTrigger.getAlarmType();
174
+
175
+ // Verify we can call setExact APIs to avoid a crash, but it requires an Android S+ symbol
176
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
177
+
178
+ // Check whether the alarmType is the exact alarm
179
+ boolean isExactAlarm =
180
+ Arrays.asList(
181
+ TimestampTriggerModel.AlarmType.SET_EXACT,
182
+ TimestampTriggerModel.AlarmType.SET_EXACT_AND_ALLOW_WHILE_IDLE,
183
+ TimestampTriggerModel.AlarmType.SET_ALARM_CLOCK)
184
+ .contains(alarmType);
185
+ if (isExactAlarm && !alarmManager.canScheduleExactAlarms()) {
186
+ Logger.w(
187
+ TAG, "SCHEDULE_EXACT_ALARM permission not granted. Falling back to inexact alarm.");
188
+ timestampTrigger.setNextTimestamp();
189
+ AlarmManagerCompat.setAndAllowWhileIdle(
190
+ alarmManager, AlarmManager.RTC_WAKEUP, timestampTrigger.getTimestamp(), pendingIntent);
191
+ return;
192
+ }
193
+ }
194
+
195
+ // Ensure timestamp is always in the future when scheduling the alarm
196
+ timestampTrigger.setNextTimestamp();
197
+
198
+ try {
199
+ switch (alarmType) {
200
+ case SET:
201
+ alarmManager.set(AlarmManager.RTC_WAKEUP, timestampTrigger.getTimestamp(), pendingIntent);
202
+ break;
203
+ case SET_AND_ALLOW_WHILE_IDLE:
204
+ AlarmManagerCompat.setAndAllowWhileIdle(
205
+ alarmManager,
206
+ AlarmManager.RTC_WAKEUP,
207
+ timestampTrigger.getTimestamp(),
208
+ pendingIntent);
209
+ break;
210
+ case SET_EXACT:
211
+ AlarmManagerCompat.setExact(
212
+ alarmManager,
213
+ AlarmManager.RTC_WAKEUP,
214
+ timestampTrigger.getTimestamp(),
215
+ pendingIntent);
216
+ break;
217
+ case SET_EXACT_AND_ALLOW_WHILE_IDLE:
218
+ AlarmManagerCompat.setExactAndAllowWhileIdle(
219
+ alarmManager,
220
+ AlarmManager.RTC_WAKEUP,
221
+ timestampTrigger.getTimestamp(),
222
+ pendingIntent);
223
+ break;
224
+ case SET_ALARM_CLOCK:
225
+ int mutabilityFlag = PendingIntent.FLAG_UPDATE_CURRENT;
226
+ if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
227
+ mutabilityFlag = PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_UPDATE_CURRENT;
228
+ }
229
+
230
+ Context context = getApplicationContext();
231
+ Intent launchActivityIntent =
232
+ context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
233
+
234
+ PendingIntent pendingLaunchIntent =
235
+ PendingIntent.getActivity(
236
+ context,
237
+ notificationModel.getId().hashCode(),
238
+ launchActivityIntent,
239
+ mutabilityFlag);
240
+ AlarmManagerCompat.setAlarmClock(
241
+ alarmManager, timestampTrigger.getTimestamp(), pendingLaunchIntent, pendingIntent);
242
+ break;
243
+ }
244
+ } catch (SecurityException e) {
245
+ Logger.w(
246
+ TAG,
247
+ "SecurityException scheduling exact alarm, falling back to inexact: " + e.getMessage());
248
+ try {
249
+ AlarmManagerCompat.setAndAllowWhileIdle(
250
+ alarmManager, AlarmManager.RTC_WAKEUP, timestampTrigger.getTimestamp(), pendingIntent);
251
+ } catch (SecurityException e2) {
252
+ Logger.e(TAG, "Failed to schedule even inexact alarm", e2);
253
+ }
254
+ }
255
+ }
256
+
257
+ ListenableFuture<List<WorkDataEntity>> getScheduledNotifications() {
258
+ WorkDataRepository workDataRepository = new WorkDataRepository(getApplicationContext());
259
+ return workDataRepository.getAllWithAlarmManager(true);
260
+ }
261
+
262
+ public static void cancelNotification(String notificationId) {
263
+ PendingIntent pendingIntent = getAlarmManagerIntentForNotification(notificationId);
264
+ AlarmManager alarmManager = AlarmUtils.getAlarmManager();
265
+ if (pendingIntent != null) {
266
+ alarmManager.cancel(pendingIntent);
267
+ }
268
+ }
269
+
270
+ public static ListenableFuture<Void> cancelAllNotifications() {
271
+ WorkDataRepository workDataRepository = WorkDataRepository.getInstance(getApplicationContext());
272
+
273
+ return new ExtendedListenableFuture<>(workDataRepository.getAllWithAlarmManager(true))
274
+ .continueWith(
275
+ workDataEntities -> {
276
+ if (workDataEntities != null) {
277
+ for (WorkDataEntity workDataEntity : workDataEntities) {
278
+ NotifeeAlarmManager.cancelNotification(workDataEntity.getId());
279
+ }
280
+ }
281
+ return Futures.immediateFuture(null);
282
+ },
283
+ alarmManagerListeningExecutor);
284
+ }
285
+
286
+ /* On reboot, reschedule trigger notifications created via alarm manager */
287
+ void rescheduleNotification(WorkDataEntity workDataEntity) {
288
+ if (workDataEntity.getNotification() == null || workDataEntity.getTrigger() == null) {
289
+ return;
290
+ }
291
+
292
+ byte[] notificationBytes = workDataEntity.getNotification();
293
+ byte[] triggerBytes = workDataEntity.getTrigger();
294
+ Bundle triggerBundle = ObjectUtils.bytesToBundle(triggerBytes);
295
+
296
+ NotificationModel notificationModel =
297
+ NotificationModel.fromBundle(ObjectUtils.bytesToBundle(notificationBytes));
298
+
299
+ int triggerType = ObjectUtils.getInt(triggerBundle.get("type"));
300
+
301
+ switch (triggerType) {
302
+ case 0:
303
+ TimestampTriggerModel trigger = TimestampTriggerModel.fromBundle(triggerBundle);
304
+ if (!trigger.getWithAlarmManager()) {
305
+ return;
306
+ }
307
+
308
+ scheduleTimestampTriggerNotification(notificationModel, trigger);
309
+ // Persist updated timestamp so next reboot starts from the correct anchor
310
+ WorkDataRepository.getInstance(getApplicationContext())
311
+ .update(
312
+ new WorkDataEntity(
313
+ workDataEntity.getId(),
314
+ workDataEntity.getNotification(),
315
+ ObjectUtils.bundleToBytes(trigger.toBundle()),
316
+ workDataEntity.getWithAlarmManager()));
317
+ break;
318
+ case 1:
319
+ // TODO: support interval triggers with alarm manager
320
+ break;
321
+ }
322
+ }
323
+
324
+ void rescheduleNotifications(@Nullable BroadcastReceiver.PendingResult pendingResult) {
325
+ Logger.d(TAG, "Reschedule Notifications on reboot");
326
+ Futures.addCallback(
327
+ getScheduledNotifications(),
328
+ new FutureCallback<List<WorkDataEntity>>() {
329
+ @Override
330
+ public void onSuccess(List<WorkDataEntity> workDataEntities) {
331
+ try {
332
+ for (WorkDataEntity workDataEntity : workDataEntities) {
333
+ rescheduleNotification(workDataEntity);
334
+ }
335
+ } finally {
336
+ if (pendingResult != null) {
337
+ pendingResult.finish();
338
+ }
339
+ }
340
+ }
341
+
342
+ @Override
343
+ public void onFailure(Throwable t) {
344
+ Logger.e(TAG, "Failed to reschedule notifications", new Exception(t));
345
+ if (pendingResult != null) {
346
+ pendingResult.finish();
347
+ }
348
+ }
349
+ },
350
+ alarmManagerListeningExecutor);
351
+ }
352
+ }
@@ -0,0 +1,42 @@
1
+ package app.notifee.core;
2
+
3
+ /*
4
+ * Copyright (c) 2016-present Invertase Limited & Contributors
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this library except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ import android.content.BroadcastReceiver;
21
+ import android.content.Context;
22
+ import android.content.Intent;
23
+
24
+ /*
25
+ * This is invoked by the Alarm Manager when it is time to display a scheduled notification.
26
+ *
27
+ * goAsync() is used to extend the receiver's lifetime (~30s instead of ~10s),
28
+ * preventing Android from killing the process before the async notification
29
+ * display chain completes. This is critical on Android 14+ when the app is killed.
30
+ */
31
+ public class NotificationAlarmReceiver extends BroadcastReceiver {
32
+ @Override
33
+ public void onReceive(Context context, Intent intent) {
34
+ PendingResult pendingResult = goAsync();
35
+
36
+ if (ContextHolder.getApplicationContext() == null) {
37
+ ContextHolder.setApplicationContext(context.getApplicationContext());
38
+ }
39
+
40
+ NotifeeAlarmManager.displayScheduledNotification(intent.getExtras(), pendingResult);
41
+ }
42
+ }