cordova-plugin-local-notifications-continued 1.2.4

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 (67) hide show
  1. package/.github/FUNDING.yml +1 -0
  2. package/.github/ISSUE_TEMPLATE/report_issue.yml +126 -0
  3. package/CHANGELOG.md +358 -0
  4. package/LICENSE +202 -0
  5. package/README.md +1531 -0
  6. package/images/android-actions-with-input-clicked.png +0 -0
  7. package/images/android-actions-with-input-not-clicked.png +0 -0
  8. package/images/android-actions.png +0 -0
  9. package/images/android-alarms-and-reminders-in-app-settings.png +0 -0
  10. package/images/android-alarms-and-reminders-setting.png +0 -0
  11. package/images/android-app-hibernation-notification.png +0 -0
  12. package/images/android-app-hibernation-settings-android-12.png +0 -0
  13. package/images/android-app-hibernation-settings-android-13-14.png +0 -0
  14. package/images/android-app-hibernation-settings-android-15.png +0 -0
  15. package/images/android-attachments-image-folded.png +0 -0
  16. package/images/android-attachments-image-unfolded.png +0 -0
  17. package/images/android-chat.png +0 -0
  18. package/images/android-icon.svg +19 -0
  19. package/images/android-inbox.png +0 -0
  20. package/images/android-notification-example.png +0 -0
  21. package/images/android-progress.png +0 -0
  22. package/images/android-request-permission.png +0 -0
  23. package/images/android-stack.png +0 -0
  24. package/images/apple-icon.svg +1 -0
  25. package/images/cordova-app-notified-logo.png +0 -0
  26. package/images/ios-actions-with-input.png +0 -0
  27. package/images/ios-actions.png +0 -0
  28. package/images/ios-attachments-image-folded.png +0 -0
  29. package/images/ios-attachments-image-unfolded.png +0 -0
  30. package/images/ios-notification.png +0 -0
  31. package/images/ios-request-permission.png +0 -0
  32. package/images/logo.png +0 -0
  33. package/package.json +53 -0
  34. package/plugin.xml +266 -0
  35. package/src/android/ClickActivity.java +72 -0
  36. package/src/android/LocalNotification.java +779 -0
  37. package/src/android/Manager.java +327 -0
  38. package/src/android/Notification.java +844 -0
  39. package/src/android/Options.java +956 -0
  40. package/src/android/OptionsTrigger.java +104 -0
  41. package/src/android/action/Action.java +214 -0
  42. package/src/android/action/ActionGroup.java +135 -0
  43. package/src/android/build/localnotification.gradle +29 -0
  44. package/src/android/receiver/ClearReceiver.java +61 -0
  45. package/src/android/receiver/RestoreReceiver.java +70 -0
  46. package/src/android/receiver/TriggerReceiver.java +70 -0
  47. package/src/android/trigger/TriggerHandler.java +195 -0
  48. package/src/android/trigger/TriggerHandlerAt.java +63 -0
  49. package/src/android/trigger/TriggerHandlerEvery.java +257 -0
  50. package/src/android/trigger/TriggerHandlerIn.java +69 -0
  51. package/src/android/util/AssetUtil.java +385 -0
  52. package/src/android/util/CallbackContextUtil.java +88 -0
  53. package/src/android/util/PluginFileProvider.java +34 -0
  54. package/src/android/xml/shared_files_provider_paths.xml +38 -0
  55. package/src/ios/APPLocalNotification.h +56 -0
  56. package/src/ios/APPLocalNotification.m +650 -0
  57. package/src/ios/APPNotificationCategory.h +28 -0
  58. package/src/ios/APPNotificationCategory.m +107 -0
  59. package/src/ios/APPNotificationContent.h +32 -0
  60. package/src/ios/APPNotificationContent.m +122 -0
  61. package/src/ios/APPNotificationOptions.h +42 -0
  62. package/src/ios/APPNotificationOptions.m +689 -0
  63. package/src/ios/UNNotificationRequest+APPLocalNotification.h +32 -0
  64. package/src/ios/UNNotificationRequest+APPLocalNotification.m +100 -0
  65. package/src/ios/UNUserNotificationCenter+APPLocalNotification.h +60 -0
  66. package/src/ios/UNUserNotificationCenter+APPLocalNotification.m +344 -0
  67. package/www/local-notification.js +1104 -0
@@ -0,0 +1,779 @@
1
+ /*
2
+ * Apache 2.0 License
3
+ *
4
+ * Copyright (c) Sebastian Katzer 2017
5
+ * Copyright (c) Manuel Beck 2024
6
+ *
7
+ * This file contains Original Code and/or Modifications of Original Code
8
+ * as defined in and that are subject to the Apache License
9
+ * Version 2.0 (the 'License'). You may not use this file except in
10
+ * compliance with the License. Please obtain a copy of the License at
11
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
12
+ * file.
13
+ *
14
+ * The Original Code and all software distributed under the License are
15
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
16
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
17
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
18
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
19
+ * Please see the License for the specific language governing rights and
20
+ * limitations under the License.
21
+ */
22
+
23
+ // codebeat:disable[TOO_MANY_FUNCTIONS]
24
+
25
+ package de.appplant.cordova.plugin.localnotification;
26
+
27
+ import android.annotation.SuppressLint;
28
+ import android.app.Activity;
29
+ import android.app.KeyguardManager;
30
+ import android.content.Context;
31
+ import android.util.Pair;
32
+ import android.view.View;
33
+ import android.Manifest;
34
+ import android.content.pm.PackageManager;
35
+ import android.util.Log;
36
+ import android.content.Intent;
37
+ import android.provider.Settings;
38
+ import android.net.Uri;
39
+ import android.os.Build;
40
+ import android.content.IntentFilter;
41
+ import androidx.core.app.NotificationManagerCompat;
42
+
43
+ import androidx.core.content.ContextCompat;
44
+ import androidx.core.content.IntentCompat;
45
+ import androidx.core.content.PackageManagerCompat;
46
+ import androidx.core.content.UnusedAppRestrictionsConstants;
47
+
48
+ import org.apache.cordova.CallbackContext;
49
+ import org.apache.cordova.CordovaInterface;
50
+ import org.apache.cordova.CordovaPlugin;
51
+ import org.apache.cordova.CordovaWebView;
52
+ import org.apache.cordova.PluginResult;
53
+ import org.json.JSONArray;
54
+ import org.json.JSONException;
55
+ import org.json.JSONObject;
56
+
57
+ import java.lang.ref.WeakReference;
58
+ import java.util.ArrayList;
59
+ import java.util.Arrays;
60
+ import java.util.List;
61
+
62
+ import de.appplant.cordova.plugin.localnotification.Manager;
63
+ import de.appplant.cordova.plugin.localnotification.Notification;
64
+ import de.appplant.cordova.plugin.localnotification.Options;
65
+ import de.appplant.cordova.plugin.localnotification.action.ActionGroup;
66
+ import de.appplant.cordova.plugin.localnotification.util.AssetUtil;
67
+ import de.appplant.cordova.plugin.localnotification.util.CallbackContextUtil;
68
+
69
+ import com.google.common.util.concurrent.ListenableFuture;
70
+
71
+ import static de.appplant.cordova.plugin.localnotification.Notification.Type.SCHEDULED;
72
+ import static de.appplant.cordova.plugin.localnotification.Notification.Type.TRIGGERED;
73
+
74
+ /**
75
+ * This plugin utilizes the Android AlarmManager in combination with local
76
+ * notifications. When a local notification is scheduled the alarm manager takes
77
+ * care of firing the event. When the event is processed, a notification is put
78
+ * in the Android notification center and status bar.
79
+ */
80
+ @SuppressWarnings({"Convert2Diamond", "Convert2Lambda"})
81
+ public class LocalNotification extends CordovaPlugin {
82
+
83
+ public static final String TAG = "LocalNotification";
84
+
85
+ // Reference to the web view for static access
86
+ private static WeakReference<CordovaWebView> weakReferenceCordovaWebView = null;
87
+
88
+ // Indicates if the device is ready (to receive events)
89
+ private static Boolean deviceready = false;
90
+
91
+ // Queues all events before deviceready
92
+ private static ArrayList<String> eventQueue = new ArrayList<String>();
93
+
94
+ // Launch details
95
+ private static Pair<Integer, String> launchDetails;
96
+
97
+ private static int REQUEST_CODE_MANAGE_UNUSED_APP_RESTRICTIONS = 1005;
98
+
99
+ /**
100
+ * Called after plugin construction and fields have been initialized.
101
+ */
102
+ @Override
103
+ protected void pluginInitialize() {
104
+ LocalNotification.weakReferenceCordovaWebView = new WeakReference<CordovaWebView>(webView);
105
+ // Create shared direcotry for assets
106
+ new AssetUtil(getContext()).getSharedDirectory().mkdir();
107
+ }
108
+
109
+ /**
110
+ * Called when the activity will start interacting with the user.
111
+ *
112
+ * @param multitasking Flag indicating if multitasking is turned on for app.
113
+ */
114
+ @Override
115
+ public void onResume(boolean multitasking) {
116
+ super.onResume(multitasking);
117
+ Log.d(TAG, "onResume");
118
+ deviceready();
119
+ }
120
+
121
+ /**
122
+ * The final call you receive before your activity is destroyed.
123
+ */
124
+ @Override
125
+ public void onDestroy() {
126
+ super.onDestroy();
127
+ Log.d(TAG, "onDestroy");
128
+ deviceready = false;
129
+ }
130
+
131
+ /**
132
+ * Executes the request.
133
+ *
134
+ * This method is called from the WebView thread. To do a non-trivial
135
+ * amount of work, use:
136
+ * cordova.getThreadPool().execute(runnable);
137
+ *
138
+ * To run on the UI thread, use:
139
+ * cordova.getActivity().runOnUiThread(runnable);
140
+ *
141
+ * @param action The action to execute.
142
+ * @param args The exec() arguments in JSON form.
143
+ * @param callbackContext The callback context used when calling back into JavaScript.
144
+ *
145
+ * @return Whether the action was valid.
146
+ */
147
+ @Override
148
+ public boolean execute(final String action, final JSONArray args, final CallbackContext callbackContext) throws JSONException {
149
+ Log.d(TAG, "execute, action=" + action + ", args=" + args);
150
+
151
+ if (action.equals("launch")) {
152
+ launch(callbackContext);
153
+ return true;
154
+ }
155
+
156
+ cordova.getThreadPool().execute(new Runnable() {
157
+ public void run() {
158
+ if (action.equals("ready")) {
159
+ deviceready();
160
+ } else if (action.equals("createChannel")) {
161
+ createChannel(args, callbackContext);
162
+ } else if (action.equals("deleteChannel")) {
163
+ deleteChannel(args, callbackContext);
164
+ } else if (action.equals("hasPermission")) {
165
+ hasPermission(callbackContext);
166
+ } else if (action.equals("requestPermission")) {
167
+ requestPermission(callbackContext);
168
+ } else if (action.equals("actions")) {
169
+ actions(args, callbackContext);
170
+ } else if (action.equals("schedule")) {
171
+ schedule(args, callbackContext);
172
+ } else if (action.equals("update")) {
173
+ update(args, callbackContext);
174
+ } else if (action.equals("cancel")) {
175
+ cancel(args, callbackContext);
176
+ } else if (action.equals("cancelAll")) {
177
+ cancelAll(callbackContext);
178
+ } else if (action.equals("clear")) {
179
+ clear(args, callbackContext);
180
+ } else if (action.equals("clearAll")) {
181
+ clearAll(callbackContext);
182
+ } else if (action.equals("type")) {
183
+ type(args, callbackContext);
184
+ } else if (action.equals("ids")) {
185
+ ids(args, callbackContext);
186
+ } else if (action.equals("notification")) {
187
+ notification(args, callbackContext);
188
+ } else if (action.equals("notifications")) {
189
+ notifications(args, callbackContext);
190
+ } else if (action.equals("canScheduleExactAlarms")) {
191
+ canScheduleExactAlarms(callbackContext);
192
+ } else if (action.equals("openNotificationSettings")) {
193
+ openNotificationSettings(callbackContext);
194
+ } else if (action.equals("openAlarmSettings")) {
195
+ openAlarmSettings(callbackContext);
196
+ } else if (action.equals("getUnusedAppRestrictionsStatus")) {
197
+ getUnusedAppRestrictionsStatus(callbackContext);
198
+ } else if (action.equals("openManageUnusedAppRestrictions")) {
199
+ openManageUnusedAppRestrictions(callbackContext);
200
+ }
201
+ }
202
+ });
203
+
204
+ return true; // Action was found
205
+ }
206
+
207
+ /**
208
+ * Set launchDetails object.
209
+ */
210
+ @SuppressLint("DefaultLocale")
211
+ private void launch(CallbackContext callbackContext) {
212
+ if (launchDetails == null) return;
213
+
214
+ JSONObject details = new JSONObject();
215
+
216
+ try {
217
+ details.put("id", launchDetails.first);
218
+ details.put("action", launchDetails.second);
219
+ } catch (JSONException e) {
220
+ e.printStackTrace();
221
+ }
222
+
223
+ callbackContext.success(details);
224
+
225
+ launchDetails = null;
226
+ }
227
+
228
+ /**
229
+ * Ask if user has enabled permission to post notifications.
230
+ */
231
+ private void hasPermission(CallbackContext callbackContext) {
232
+ successBoolean(callbackContext, NotificationManagerCompat.from(getContext()).areNotificationsEnabled());
233
+ }
234
+
235
+ /**
236
+ * Ask if if the setting to schedule exact alarms is enabled.
237
+ */
238
+ private void canScheduleExactAlarms(CallbackContext callbackContext) {
239
+ successBoolean(callbackContext, Manager.canScheduleExactAlarms(getContext()));
240
+ }
241
+
242
+ /**
243
+ * Request permission for local notifications.
244
+ * @param callbackContext The callback context used when calling back into JavaScript.
245
+ */
246
+ private void requestPermission(CallbackContext callbackContext) {
247
+ // Permission is granted.
248
+ if (NotificationManagerCompat.from(getContext()).areNotificationsEnabled()) {
249
+ successBoolean(callbackContext, true);
250
+ return;
251
+ }
252
+
253
+ // If Notifications are disabled and POST_NOTIFICATIONS runtime permission is not supported
254
+ // we can't ask the user to enable notifications, so we return false.
255
+ if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) {
256
+ successBoolean(callbackContext, false);
257
+ return;
258
+ }
259
+
260
+ // Store the callback context for later use in onRequestPermissionResult
261
+ // and get a random request code to identify the context later
262
+ int randomRequestCode = CallbackContextUtil.storeContext(callbackContext);
263
+
264
+ // Request the runtime permission.
265
+ cordova.requestPermission(this, randomRequestCode, Manifest.permission.POST_NOTIFICATIONS);
266
+ }
267
+
268
+ /**
269
+ * Called by {@link CordovaActivity#onRequestPermissionsResult} when the user grants permissions, which
270
+ * was called by Android.
271
+ *
272
+ * @deprecated In the future {@link #onRequestPermissionsResult} should be used, but cordova calls still the old
273
+ * method: https://github.com/apache/cordova-android/issues/1388
274
+ * @see Android method onRequestPermissionsResult: https://developer.android.com/reference/android/app/Activity#onRequestPermissionsResult(int,%20java.lang.String[],%20int[])
275
+ */
276
+ @Override
277
+ @Deprecated
278
+ public void onRequestPermissionResult(int requestCode, String[] permissions, int[] grantResults) {
279
+ Log.d(TAG, "onRequestPermissionResult" +
280
+ ", requestCode=" + requestCode +
281
+ ", permissions=" + Arrays.toString(permissions) +
282
+ ", grantResults=" + Arrays.toString(grantResults));
283
+
284
+ // It is possible that the permissions request interaction with the user is interrupted.
285
+ // In this case the permissions and grantResults array is empty, which should be treated as a cancellation.
286
+ boolean permissionGranted = grantResults.length > 0 ? grantResults[0] == PackageManager.PERMISSION_GRANTED : false;
287
+ CallbackContext callbackContext = CallbackContextUtil.getCallbackContext(requestCode);
288
+
289
+ if (callbackContext != null) successBoolean(callbackContext, permissionGranted);
290
+
291
+ // Remove the saved context
292
+ CallbackContextUtil.clearContext(requestCode);
293
+ }
294
+
295
+ /**
296
+ * Register, removes or checks for an action group
297
+ * @param args The exec() arguments in JSON form.
298
+ * @param callbackContext The callback context used when calling back into JavaScript.
299
+ */
300
+ private void actions(JSONArray args, CallbackContext callbackContext) {
301
+ String actionGroupId = args.optString(1);
302
+
303
+ // The first agrument defines, which method was called
304
+ switch (args.optInt(0)) {
305
+ // addActions was called
306
+ case 0:
307
+ new ActionGroup(getContext(), actionGroupId, args.optJSONArray(2)).store();
308
+ callbackContext.success();
309
+ break;
310
+ // removeActions was called
311
+ case 1:
312
+ ActionGroup.remove(getContext(), actionGroupId);
313
+ callbackContext.success();
314
+ break;
315
+ // hasActions was called
316
+ case 2:
317
+ successBoolean(callbackContext, ActionGroup.get(getContext(), actionGroupId) != null);
318
+ break;
319
+ }
320
+ }
321
+
322
+ /**
323
+ * Schedule one or multiple local notifications
324
+ * @param optionsJSONList The notifications to schedule.
325
+ */
326
+ private void schedule(JSONArray optionsJSONList, CallbackContext callbackContext) {
327
+ for (int index = 0; index < optionsJSONList.length(); index++) {
328
+ Notification notification = new Notification(getContext(), optionsJSONList.optJSONObject(index));
329
+ if (notification.scheduleNext()) fireEvent("add", notification);
330
+ }
331
+
332
+ hasPermission(callbackContext);
333
+ }
334
+
335
+ /**
336
+ * Create Notification channel with options.
337
+ *
338
+ * @param args The channel options.
339
+ * @param callbackContext The callback context used when calling back into
340
+ * JavaScript.
341
+ */
342
+ private void createChannel(JSONArray args, CallbackContext callbackContext) {
343
+ Manager.createChannel(getContext(), new Options(getContext(), args.optJSONObject(0)));
344
+ callbackContext.success();
345
+ }
346
+
347
+ /**
348
+ * Deletes a notification channel by an id.
349
+ * @param args Contains the channel id as a String.
350
+ */
351
+ private void deleteChannel(JSONArray args, CallbackContext callbackContext) {
352
+ getManager().deleteChannel(args.optString(0));
353
+ callbackContext.success();
354
+ }
355
+
356
+ /**
357
+ * Update multiple notifications.
358
+ * @param optionsList Notification properties including their IDs.
359
+ * @param callbackContext
360
+ */
361
+ private void update(JSONArray optionsList, CallbackContext callbackContext) {
362
+ for (int index = 0; index < optionsList.length(); index++) {
363
+
364
+ JSONObject updateOptions = optionsList.optJSONObject(index);
365
+ int notificationId = updateOptions.optInt("id", 0);
366
+ Notification notification = getManager().update(notificationId, updateOptions);
367
+
368
+ // Notification didn't exist and couldn't be updated
369
+ if (notification == null) continue;
370
+
371
+ // Inform webView about the update
372
+ fireEvent("update", notification);
373
+ }
374
+
375
+ hasPermission(callbackContext);
376
+ }
377
+
378
+ /**
379
+ * Cancel multiple local notifications.
380
+ */
381
+ private void cancel(JSONArray args, CallbackContext callbackContext) {
382
+ for (int argsIndex = 0; argsIndex < args.length(); argsIndex++) {
383
+ Notification notification = Notification.getFromSharedPreferences(getContext(), args.optInt(argsIndex, 0));
384
+ if (notification != null) notification.cancel();
385
+ }
386
+
387
+ callbackContext.success();
388
+ }
389
+
390
+ /**
391
+ * Cancel all scheduled notifications.
392
+ */
393
+ private void cancelAll(CallbackContext callbackContext) {
394
+ getManager().cancelAll();
395
+ fireEvent("cancelall");
396
+ callbackContext.success();
397
+ }
398
+
399
+ /**
400
+ * Clear multiple local notifications without canceling them.
401
+ * @param args Set of local notification IDs.
402
+ */
403
+ private void clear(JSONArray args, CallbackContext callbackContext) {
404
+ for (int argsIndex = 0; argsIndex < args.length(); argsIndex++) {
405
+ Notification notification = Notification.getFromSharedPreferences(getContext(), args.optInt(argsIndex, 0));
406
+ if (notification != null) notification.clear();
407
+ }
408
+
409
+ callbackContext.success();
410
+ }
411
+
412
+ /**
413
+ * Clear all triggered notifications without canceling them.
414
+ */
415
+ private void clearAll(CallbackContext callbackContext) {
416
+ getManager().clearAll();
417
+ fireEvent("clearall");
418
+ callbackContext.success();
419
+ }
420
+
421
+ /**
422
+ * Get the type of the notification (unknown, scheduled, triggered).
423
+ */
424
+ private void type(JSONArray args, CallbackContext callbackContext) {
425
+ Notification notification = Notification.getFromSharedPreferences(getContext(), args.optInt(0));
426
+
427
+ if (notification == null) {
428
+ callbackContext.success("unknown");
429
+ return;
430
+ }
431
+
432
+ switch (notification.getType()) {
433
+ case SCHEDULED:
434
+ callbackContext.success("scheduled");
435
+ break;
436
+ case TRIGGERED:
437
+ callbackContext.success("triggered");
438
+ break;
439
+ default:
440
+ callbackContext.success("unknown");
441
+ break;
442
+ }
443
+ }
444
+
445
+ /**
446
+ * Set of IDs from all existent notifications.
447
+ * @param args Type of notifications to get IDs from.
448
+ */
449
+ private void ids(JSONArray args, CallbackContext callbackContext) {
450
+ int type = args.optInt(0);
451
+ Manager mgr = getManager();
452
+ List<Integer> ids;
453
+
454
+ switch (type) {
455
+ case 0:
456
+ ids = mgr.getNotificationIds();
457
+ break;
458
+ case 1:
459
+ ids = mgr.getNotificationIdsByType(SCHEDULED);
460
+ break;
461
+ case 2:
462
+ ids = mgr.getNotificationIdsByType(TRIGGERED);
463
+ break;
464
+ default:
465
+ ids = new ArrayList<Integer>(0);
466
+ break;
467
+ }
468
+
469
+ callbackContext.success(new JSONArray(ids));
470
+ }
471
+
472
+ /**
473
+ * Sends options from a notification to WebView
474
+ */
475
+ private void notification(JSONArray args, CallbackContext callbackContext) {
476
+ Notification notification = Notification.getFromSharedPreferences(getContext(), args.optInt(0));
477
+
478
+ if (notification != null) {
479
+ callbackContext.success(notification.getOptions().getJSON());
480
+ } else {
481
+ callbackContext.success();
482
+ }
483
+ }
484
+
485
+ /**
486
+ * Set of options from local notification.
487
+ */
488
+ private void notifications(JSONArray args, CallbackContext callbackContext) {
489
+ int type = args.optInt(0);
490
+ JSONArray ids = args.optJSONArray(1);
491
+ List<Notification> notifications = new ArrayList<Notification>();
492
+
493
+ switch (type) {
494
+ case 0:
495
+ notifications = getManager().getNotificationsFromSharedPreferences();
496
+ break;
497
+ case 1:
498
+ notifications = getManager().getByType(SCHEDULED);
499
+ break;
500
+ case 2:
501
+ notifications = getManager().getByType(TRIGGERED);
502
+ break;
503
+ case 3:
504
+ notifications = getManager().getNotificationsFromSharedPreferences(toList(ids));
505
+ break;
506
+ }
507
+
508
+ ArrayList<JSONObject> options = new ArrayList<JSONObject>();
509
+
510
+ for (Notification notification : notifications) {
511
+ options.add(notification.getOptions().getJSON());
512
+ }
513
+
514
+ callbackContext.success(new JSONArray(options));
515
+ }
516
+ /**
517
+ * Open the Android Notification settings for current app.
518
+ */
519
+ private void openNotificationSettings(CallbackContext callbackContext) {
520
+ String packageName = cordova.getActivity().getPackageName();
521
+ Intent intent = new Intent();
522
+
523
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
524
+ intent.setAction(Settings.ACTION_APP_NOTIFICATION_SETTINGS);
525
+ intent.putExtra(Settings.EXTRA_APP_PACKAGE, packageName);
526
+ } else {
527
+ // In old Android versions it's not possible to view notification settings, open app settings.
528
+ intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
529
+ intent.setData(Uri.parse("package:" + packageName));
530
+ }
531
+
532
+ cordova.getActivity().startActivity(intent);
533
+ callbackContext.success();
534
+ }
535
+
536
+ /**
537
+ * Open the Alarms & Reminders setting for the current app.
538
+ * This setting is available since Android 12 (SDK 31). If this method is called on
539
+ * Android 11 (SDK 30) or older, the method will just call callbackContext.success().
540
+ */
541
+ private void openAlarmSettings(CallbackContext callbackContext) {
542
+ // Setting available since Android 12 (SDK 31)
543
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
544
+ cordova.getActivity().startActivity(new Intent(
545
+ Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM,
546
+ Uri.parse("package:" + cordova.getActivity().getPackageName())));
547
+ }
548
+
549
+ callbackContext.success();
550
+ }
551
+
552
+ /**
553
+ * Returns the status of Unused App Restrictions, which was introduced in Android 11 and
554
+ * backported to Android 6 to 10 through the Google Play Store.
555
+ * @return int @see UnusedAppRestrictionsConstants
556
+ * @see https://developer.android.com/topic/performance/app-hibernation
557
+ */
558
+ private void getUnusedAppRestrictionsStatus(CallbackContext callbackContext) {
559
+ ListenableFuture<Integer> listenableFuture = PackageManagerCompat.getUnusedAppRestrictionsStatus(getContext());
560
+ listenableFuture.addListener(new Runnable() {
561
+ public void run() {
562
+ try {
563
+ callbackContext.success(listenableFuture.get());
564
+ } catch (Exception exception) {
565
+ callbackContext.success(UnusedAppRestrictionsConstants.ERROR);
566
+ }
567
+ }
568
+ }, ContextCompat.getMainExecutor(getContext()));
569
+ }
570
+
571
+ /**
572
+ * Starts an Intent to redirect the user to manage their unused app restriction settings.
573
+ */
574
+ private void openManageUnusedAppRestrictions(CallbackContext callbackContext) {
575
+ Intent intent = IntentCompat.createManageUnusedAppRestrictionsIntent(
576
+ getContext(), cordova.getActivity().getApplicationContext().getPackageName());
577
+
578
+ // Store the callback context for later use in onActivityResult to inform the webview
579
+ CallbackContextUtil.storeContext(callbackContext, REQUEST_CODE_MANAGE_UNUSED_APP_RESTRICTIONS);
580
+
581
+ // Start the activity
582
+ this.cordova.startActivityForResult(this, intent, REQUEST_CODE_MANAGE_UNUSED_APP_RESTRICTIONS);
583
+ }
584
+
585
+ /**
586
+ * Called when an activity launched exits, giving the requestCode started it with,
587
+ * the resultCode it returned, and any additional data from it.
588
+ * @param requestCode The request code originally supplied to startActivityForResult(), allowing you to
589
+ * identify who this result came from.
590
+ * @param resultCode The integer result code returned by the child activity through its setResult().
591
+ * @param intent An Intent, which can return result data to the caller (various data can be attached to Intent "extras").
592
+ */
593
+ @Override
594
+ public void onActivityResult(int requestCode, int resultCode, Intent intent) {
595
+ Log.d(TAG, "onActivityResult" +
596
+ ", requestCode=" + requestCode +
597
+ ", resultCode=" + resultCode +
598
+ ", intent=" + intent);
599
+
600
+ // Get the saved CallbackContext for the request code
601
+ CallbackContext callbackContext = CallbackContextUtil.getCallbackContext(requestCode);
602
+
603
+ if (callbackContext != null) callbackContext.success(resultCode);
604
+
605
+ // Remove the saved CallbackContext
606
+ CallbackContextUtil.clearContext(requestCode);
607
+ }
608
+
609
+ /**
610
+ * Call all pending callbacks after the deviceready event has been fired.
611
+ */
612
+ private static synchronized void deviceready() {
613
+ deviceready = true;
614
+
615
+ for (String js : eventQueue) {
616
+ sendJavascript(js);
617
+ }
618
+
619
+ eventQueue.clear();
620
+ }
621
+
622
+ /**
623
+ * Helper method to invoke the {@link CallbackContext} with a boolean argument,
624
+ * because there does not exists a success method with a boolean in {@link CallbackContext}.
625
+ */
626
+ private void successBoolean(CallbackContext callbackContext, boolean success) {
627
+ callbackContext.sendPluginResult(new PluginResult(PluginResult.Status.OK, success));
628
+ }
629
+
630
+ /**
631
+ * Fire given event on JS side. Does inform all event listeners.
632
+ *
633
+ * @param event The event name.
634
+ */
635
+ private void fireEvent(String event) {
636
+ fireEvent(event, null, null);
637
+ }
638
+
639
+ /**
640
+ * Fire given event on JS side. Does inform all event listeners.
641
+ *
642
+ * @param event The event name.
643
+ * @param notification Optional notification to pass with.
644
+ */
645
+ public static void fireEvent(String event, Notification notification) {
646
+ fireEvent(event, notification, null);
647
+ }
648
+
649
+ /**
650
+ * Fire given event on JS side. Does inform all event listeners.
651
+ *
652
+ * @param event The event name.
653
+ * @param notification Optional notification to pass with.
654
+ * @param eventData Event object with additional data.
655
+ */
656
+ public static void fireEvent(String event, Notification notification, JSONObject eventData) {
657
+ if (eventData == null) eventData = new JSONObject();
658
+
659
+ try {
660
+ eventData.put("event", event);
661
+ eventData.put("foreground", isInForeground());
662
+ eventData.put("queued", !deviceready);
663
+ // Set notification id
664
+ if (notification != null) eventData.put("notification", notification.getId());
665
+ } catch (JSONException exception) {
666
+ exception.printStackTrace();
667
+ }
668
+
669
+ if (launchDetails == null && !deviceready && notification != null) {
670
+ launchDetails = new Pair<Integer, String>(notification.getId(), event);
671
+ }
672
+
673
+ sendJavascript(String.format(
674
+ "cordova.plugins.notification.local.fireEvent('%s', %s)",
675
+ event,
676
+ // params
677
+ // notification
678
+ (notification != null ? notification.getOptions().toString() + ", " : "")
679
+ // event data
680
+ + eventData.toString()));
681
+ }
682
+
683
+ /**
684
+ * Use this instead of deprecated sendJavascript
685
+ *
686
+ * @param js JS code snippet as string.
687
+ */
688
+ private static synchronized void sendJavascript(final String js) {
689
+
690
+ if (!deviceready || weakReferenceCordovaWebView == null) {
691
+ eventQueue.add(js);
692
+ return;
693
+ }
694
+
695
+ final CordovaWebView cordovaWebView = weakReferenceCordovaWebView.get();
696
+
697
+ ((Activity)(cordovaWebView.getContext())).runOnUiThread(new Runnable() {
698
+ public void run() {
699
+ cordovaWebView.loadUrl("javascript:" + js);
700
+ }
701
+ });
702
+ }
703
+
704
+ /**
705
+ * If the app is running in foreground.
706
+ */
707
+ private static boolean isInForeground() {
708
+ if (!deviceready || weakReferenceCordovaWebView == null) return false;
709
+
710
+ CordovaWebView cordovaWebView = weakReferenceCordovaWebView.get();
711
+
712
+ // Class to manage and query the state of the lock screen (also known as Keyguard).
713
+ KeyguardManager km = (KeyguardManager) cordovaWebView.getContext().getSystemService(Context.KEYGUARD_SERVICE);
714
+
715
+ // - km can be null if running as an instant app
716
+ // - Only true, if lock screen is not visible and the app is visible.
717
+ return (km == null || (km != null && !km.isKeyguardLocked())) && cordovaWebView.getView().getWindowVisibility() == View.VISIBLE;
718
+ }
719
+
720
+ /**
721
+ * If the app is running.
722
+ */
723
+ public static boolean isAppRunning() {
724
+ return weakReferenceCordovaWebView != null;
725
+ }
726
+
727
+ /**
728
+ * Launch main intent from package.
729
+ */
730
+ public static void launchApp(Context context) {
731
+ // Returns a "good" intent to launch a front-door activity in a package.
732
+ // The current implementation looks first for a main activity in the category
733
+ // Intent.CATEGORY_INFO, and next for a main activity
734
+ // in the category Intent.CATEGORY_LAUNCHER.
735
+ // Returns null if neither are found.
736
+ Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(context.getPackageName());
737
+ if (launchIntent == null) {
738
+ Log.e(TAG, "Could not launch app, launch intent not found for package: " + context.getPackageName());
739
+ return;
740
+ }
741
+ launchIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_SINGLE_TOP);
742
+ Log.d(TAG, "Launching app");
743
+ context.startActivity(launchIntent);
744
+ }
745
+
746
+ /**
747
+ * Get the app name.
748
+ * @return String App name.
749
+ */
750
+ public static String getAppName(Context context) {
751
+ return (String) context.getPackageManager().getApplicationLabel(context.getApplicationInfo());
752
+ }
753
+
754
+ /**
755
+ * Convert JSON array of integers to List.
756
+ *
757
+ * @param jsonArray Array of integers.
758
+ */
759
+ private List<Integer> toList(JSONArray jsonArray) {
760
+ List<Integer> list = new ArrayList<Integer>();
761
+
762
+ for (int index = 0; index < jsonArray.length(); index++) {
763
+ list.add(jsonArray.optInt(index));
764
+ }
765
+
766
+ return list;
767
+ }
768
+
769
+ /**
770
+ * Notification manager instance.
771
+ */
772
+ private Manager getManager() {
773
+ return new Manager(getContext());
774
+ }
775
+
776
+ private Context getContext() {
777
+ return cordova.getActivity();
778
+ }
779
+ }