├── .DS_Store ├── .gitignore ├── CHANGELOG.md ├── ISSUE_TEMPLATE.md ├── LICENSE ├── README.md ├── images ├── android-actions.png ├── android-chat.png ├── android-inbox.png ├── android-progress.png ├── android-reply-2.png ├── android-reply.png ├── android-stack.png ├── ios-actions.png ├── ios-basic.png ├── ios-permission.png ├── logo.png └── windows-actions.png ├── package.json ├── plugin.xml ├── src ├── android │ ├── ClearReceiver.java │ ├── ClickReceiver.java │ ├── LocalNotification.java │ ├── RestoreReceiver.java │ ├── TriggerReceiver.java │ ├── build │ │ └── localnotification.gradle │ ├── notification │ │ ├── Builder.java │ │ ├── Manager.java │ │ ├── Notification.java │ │ ├── NotificationVolumeManager.java │ │ ├── Options.java │ │ ├── Request.java │ │ ├── action │ │ │ ├── Action.java │ │ │ └── ActionGroup.java │ │ ├── receiver │ │ │ ├── AbstractClearReceiver.java │ │ │ ├── AbstractClickReceiver.java │ │ │ ├── AbstractNotificationReceiver.java │ │ │ ├── AbstractRestoreReceiver.java │ │ │ └── AbstractTriggerReceiver.java │ │ ├── trigger │ │ │ ├── DateTrigger.java │ │ │ ├── IntervalTrigger.java │ │ │ └── MatchTrigger.java │ │ └── util │ │ │ ├── AssetProvider.java │ │ │ ├── AssetUtil.java │ │ │ └── LaunchUtils.java │ └── xml │ │ └── localnotification_provider_paths.xml ├── ios │ ├── APPLocalNotification.h │ ├── APPLocalNotification.m │ ├── APPNotificationCategory.h │ ├── APPNotificationCategory.m │ ├── APPNotificationContent.h │ ├── APPNotificationContent.m │ ├── APPNotificationOptions.h │ ├── APPNotificationOptions.m │ ├── UNNotificationRequest+APPLocalNotification.h │ ├── UNNotificationRequest+APPLocalNotification.m │ ├── UNUserNotificationCenter+APPLocalNotification.h │ └── UNUserNotificationCenter+APPLocalNotification.m └── windows │ ├── LocalNotificationProxy.js │ ├── LocalNotificationProxy │ ├── .vs │ │ └── LocalNotificationProxy │ │ │ └── v15 │ │ │ └── .suo │ ├── LocalNotificationProxy.sln │ └── LocalNotificationProxy │ │ ├── LocalNotification │ │ ├── ActionGroup.cs │ │ ├── Builder.cs │ │ ├── Manager.cs │ │ ├── Notification.cs │ │ ├── Options.cs │ │ ├── Request.cs │ │ ├── Toast │ │ │ ├── Button.cs │ │ │ ├── Every.cs │ │ │ ├── IAction.cs │ │ │ ├── Input.cs │ │ │ ├── ProgressBar.cs │ │ │ └── Trigger.cs │ │ └── Trigger │ │ │ ├── DateTrigger.cs │ │ │ ├── IntervalTrigger.cs │ │ │ └── MatchTrigger.cs │ │ ├── LocalNotificationProxy.cs │ │ ├── LocalNotificationProxy.csproj │ │ └── Properties │ │ └── AssemblyInfo.cs │ └── lib.UW │ ├── ARM │ ├── LocalNotificationProxy.winmd │ └── Microsoft.Toolkit.Uwp.Notifications.dll │ ├── x64 │ ├── LocalNotificationProxy.winmd │ └── Microsoft.Toolkit.Uwp.Notifications.dll │ └── x86 │ ├── LocalNotificationProxy.winmd │ └── Microsoft.Toolkit.Uwp.Notifications.dll └── www └── local-notification.js /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /src/windows.old 2 | /src/windows/Microsoft.Toolkit.Uwp.Notifications.* 3 | /src/windows/**/.vs 4 | /src/windows/**/bin 5 | /src/windows/**/obj -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ChangeLog 2 | --------- 3 | 4 | #### Version 0.9.0-beta.4 5 | - Platform enhancements 6 | - Android 8-10 device support 7 | - Android 10 SDK support (using androidx libraries rather than support libraries) 8 | - Note: If you are not building with API 29 on Android, you can use https://www.npmjs.com/package/cordova-plugin-androidx for backwards compatibility. 9 | - Enhancements (Android) 10 | - Adjusted high priority notifications to fire at more exact time. 11 | - use setAlarmClock() rather than setExactAndAllowWhileIdle(). 12 | - New `autoLaunch` attribute. 13 | - Notification launches application if closed (Android <= 9). 14 | - App has the option to run some logic and schedule (or not schedule) an immediate alarm. 15 | - Note, this will be overridden if fullScreenIntent is true. Doing that will use the fullScreenIntent behavior and not always autoLaunch. 16 | - Also note, this feature can cause alarms to not always fire on time. 17 | - New `alarmVolume` attribute. Can force application to increase device notification volume prior to playing sound. 18 | - New `resetDelay` attribute. Delay to reset alarmVolume on the device back to its original settings 19 | - New `wakeLockTimeout` attribute. Can be used to extend the wakelock to keep the device awake longer (in case an autoLaunch application trigger takes a while). 20 | - New `triggerInApp` attribute. 21 | - If set to true, notification will not fire. Instead it will fire a trigger event that can be listened to in the app. 22 | - This allows you to evaluate the notification in the application, and if you decide to fire it, you can remove the trigger, remove triggerInApp, and schedule it. (It should fire immediately). 23 | - This was previously coupled with autoLaunch, but I split it out for more flexibility. 24 | - Listening to the event can be done as follows: 25 | 26 | `window.cordova.plugins.notification.local.on('trigger', (notification) => { 27 | // do something with notification 28 | });` 29 | 30 | - Note: this functionality will be skipped (alarms will fire immediately with no trigger method) if any of the following are true: 31 | - Android 8+ is asleep and the app is not running (even if autoLaunch is true). As a timely execution of the app code can't be guaranteed in this state, the notification will fire immediately. 32 | - The app is not running and autoLaunch is false (any Android version). If the app is not running, we can't execute its code, so fire immediately. 33 | - New `fullScreenIntent` attribute. 34 | - If set to true, will use fullScreenIntent in AlarmManager to launch application. 35 | - Setting this to true will negate autoLaunch, and is the only way to automatically launch the app on Android 10+. 36 | - Note: OS/manufacturer has some options for how to deal with this configuration. It will not always launch the activity, but typically will launch it if the device is asleep and show a heads-up notification if it is not. 37 | - **Android Channel Support** 38 | - New `channelName` attribute for the name of the notification channel to use 39 | - New `channelId` attribute. If passed in, a notification channel will be created (using volume and vibration settings to determine importance) 40 | - Android: Support for excluding an application from battery optimization settings. 41 | - Android: Support for allowing an application permissions to override Do Not Disturb. 42 | - iOS: No longer remove notification from notification bar when alarms are rescheduled. Call cancel() explicitly to retain this behavior. 43 | 44 | --- 45 | 46 | Please also read the [Upgrade Guide](https://github.com/katzer/cordova-plugin-local-notifications/wiki/Upgrade-Guide) for more information. 47 | 48 | #### Version 0.8.5 (22.05.2017) 49 | - iOS 10 50 | 51 | #### Version 0.8.4 (04.01.2016) 52 | - Bug fixes 53 | - SyntaxError: missing ) after argument list 54 | 55 | #### Version 0.8.3 (03.01.2016) 56 | - Platform enhancements 57 | - Support for the `Crosswalk Engine` 58 | - Support for `cordova-ios@4` and the `WKWebView Engine` 59 | - Support for `cordova-windows@4` and `Windows 10` without using hooks 60 | - Enhancements 61 | - New `color` attribute for Android (Thanks to @Eusebius1920) 62 | - New `quarter` intervall for iOS & Android 63 | - `smallIcon` is optional (Android) 64 | - `update` checks for permission like _schedule_ 65 | - Decreased time-frame for trigger event (iOS) 66 | - Force `every:` to be a string on iOS 67 | - Bug fixes 68 | - Fixed #634 option to skip permission check 69 | - Fixed #588 crash when basename & extension can't be extracted (Android) 70 | - Fixed #732 loop between update and trigger (Android) 71 | - Fixed #710 crash due to >500 notifications (Android) 72 | - Fixed #682 crash while resuming app from notification (Android 6) 73 | - Fixed #612 cannot update icon or sound (Android) 74 | - Fixed crashing get(ID) if notification doesn't exist 75 | - Fixed #569 getScheduled returns two items per notification 76 | - Fixed #700 notifications appears on bootup 77 | 78 | #### Version 0.8.2 (08.11.2015) 79 | - Submitted to npm 80 | - Initial support for the `windows` platform 81 | - Re-add autoCancel option on Android 82 | - Warn about unknown properties 83 | - Fix crash on iOS 9 84 | - Fixed webView-Problems with cordova-android 4.0 85 | - Fix get* with single id 86 | - Fix issue when passing data in milliseconds 87 | - Update device plugin id 88 | - Several other fixes 89 | 90 | #### Version 0.8.1 (08.03.2015) 91 | 92 | - Fix incompatibility with cordova version 3.5-3.0 93 | - Fire `clear` instead of `cancel` event when clicked on repeating notifications 94 | - Do not fire `clear` or `cancel` event when clicked on persistent notifications 95 | 96 | ### Version 0.8.0 (05.03.2015) 97 | 98 | - Support for iOS 8, Android 2 (SDK >= 7) and Android 5 99 | - Windows Phone 8.1 will be added soon 100 | - New interfaces to ask for / register permissions required to schedule local notifications 101 | - `hasPermission()` and `registerPermission()` 102 | - _schedule()_ will register the permission automatically and schedule the notification if granted. 103 | - New interface to update already scheduled|triggered local notifications 104 | - `update()` 105 | - New interfaces to clear the notification center 106 | - `clear()` and `clearAll()` 107 | - New interfaces to query for local notifications, their properties, their IDs and their existence depend on their state 108 | - `isPresent()`, `isScheduled()`, `isTriggered()` 109 | - `getIds()`, `getAllIds()`, `getScheduledIds()`, `getTriggeredIds()` 110 | - `get()`, `getAll()`, `getScheduled()`, `getTriggered()` 111 | - Schedule multiple local notifications at once 112 | - `schedule( [{...},{...}] )` 113 | - Update multiple local notifications at once 114 | - `update( [{...},{...}] )` 115 | - Clear multiple local notifications at once 116 | - `clear( [1, 2] )` 117 | - Cancel multiple local notifications at once 118 | - `cancel( [1, 2] )` 119 | - New URI format to specify sound and image resources 120 | - `http(s):` for remote resources _(Android)_ 121 | - `file:` for local resources relative to the _www_ folder 122 | - `res:` for native resources 123 | - New events 124 | - `schedule`, `update`, `clear`, `clearall` and `cancelall` 125 | - Enhanced event informations 126 | - Listener will get called with the local notification object instead of only the ID 127 | - Multiple listener for one event 128 | - `on(event, callback, scope)` 129 | - Unregister event listener 130 | - `un(event, callback)` 131 | - New Android specific properties 132 | - `led` properties 133 | - `sound` and `image` accepts remote resources 134 | - Callback function and scope for all interface methods 135 | - `schedule( notification, callback, scope )` 136 | - Renamed `add()` to `schedule()` 137 | - `autoCancel` property has been removed 138 | - Use `ongoing: true` for persistent local notifications on Android 139 | - Renamed repeat intervals 140 | - `second`, `minute`, `hour`, `day`, `week`, `month` and `year` 141 | - Renamed some local notification properties 142 | - `date`, `json`, `message` and `repeat` 143 | - Scheduling local notifications with the deprecated properties is still possible 144 | - [Kitchen Sink sample app](https://github.com/katzer/cordova-plugin-local-notifications/tree/example) 145 | - [Wiki](https://github.com/katzer/cordova-plugin-local-notifications/wiki) 146 | -------------------------------------------------------------------------------- /ISSUE_TEMPLATE.md: -------------------------------------------------------------------------------- 1 | **WARNING: IF YOU IGNORE THIS TEMPLATE, WE'LL IGNORE YOUR ISSUE. YOU MUST FILL THIS IN!** 2 | 3 | Provide a general summary of the issue. 4 | 5 | ## Your Environment 6 | 7 | * Plugin version: 8 | * Platform: 9 | * OS version: 10 | * Device manufacturer / model: 11 | * Cordova version (```cordova -v```): 12 | * Cordova platform version (```cordova platform ls```): 13 | * Plugin config 14 | * Ionic Version (if using Ionic) 15 | 16 | ## Expected Behavior 17 | 18 | _Tell us what should happen_ 19 | 20 | ## Actual Behavior 21 | 22 | _Tell us what happens instead_ 23 | 24 | ## Steps to Reproduce 25 | 26 | _Reproduce this issue; include code to reproduce, if relevant_ 27 | 28 | 1. ... 29 | 2. ... 30 | 3. ... 31 | 4. .... 32 | 33 | ## Context 34 | 35 | _What were you trying to do?_ 36 | 37 | ## Debug logs 38 | 39 | _Include iOS / Android logs_ 40 | 41 | * ios XCode logs 42 | * Android: $ adb logcat 43 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright 2013 appPlant GmbH 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. -------------------------------------------------------------------------------- /images/android-actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/images/android-actions.png -------------------------------------------------------------------------------- /images/android-chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/images/android-chat.png -------------------------------------------------------------------------------- /images/android-inbox.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/images/android-inbox.png -------------------------------------------------------------------------------- /images/android-progress.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/images/android-progress.png -------------------------------------------------------------------------------- /images/android-reply-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/images/android-reply-2.png -------------------------------------------------------------------------------- /images/android-reply.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/images/android-reply.png -------------------------------------------------------------------------------- /images/android-stack.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/images/android-stack.png -------------------------------------------------------------------------------- /images/ios-actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/images/ios-actions.png -------------------------------------------------------------------------------- /images/ios-basic.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/images/ios-basic.png -------------------------------------------------------------------------------- /images/ios-permission.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/images/ios-permission.png -------------------------------------------------------------------------------- /images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/images/logo.png -------------------------------------------------------------------------------- /images/windows-actions.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/images/windows-actions.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cordova-plugin-local-notification", 3 | "version": "0.9.0-beta.4", 4 | "description": "Schedules and queries for local notifications", 5 | "cordova": { 6 | "id": "cordova-plugin-local-notification", 7 | "platforms": [ 8 | "android", 9 | "ios", 10 | "windows" 11 | ] 12 | }, 13 | "repository": { 14 | "type": "git", 15 | "url": "git+https://github.com/katzer/cordova-plugin-local-notifications.git" 16 | }, 17 | "keywords": [ 18 | "appplant", 19 | "notification", 20 | "local notification", 21 | "user notification", 22 | "ecosystem:cordova", 23 | "cordova-ios", 24 | "cordova-android", 25 | "cordova-windows" 26 | ], 27 | "engines": [ 28 | { 29 | "name": "cordova", 30 | "version": ">=3.6.0" 31 | }, 32 | { 33 | "name": "cordova-android", 34 | "version": ">=6.0.0" 35 | }, 36 | { 37 | "name": "cordova-windows", 38 | "version": ">=4.2.0" 39 | }, 40 | { 41 | "name": "android-sdk", 42 | "version": ">=26" 43 | }, 44 | { 45 | "name": "apple-ios", 46 | "version": ">=10.0.0" 47 | } 48 | ], 49 | "author": "Sebastián Katzer", 50 | "license": "Apache 2.0", 51 | "bugs": { 52 | "url": "https://github.com/katzer/cordova-plugin-local-notifications/issues" 53 | }, 54 | "homepage": "https://github.com/katzer/cordova-plugin-local-notifications#readme" 55 | } 56 | -------------------------------------------------------------------------------- /plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 23 | 24 | 28 | 29 | LocalNotification 30 | 31 | Schedules and queries for local notifications 32 | 33 | https://github.com/katzer/cordova-plugin-local-notifications.git 34 | 35 | appplant, notification, local notification, user notification 36 | 37 | Apache 2.0 38 | 39 | Sebastián Katzer 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 109 | 112 | 113 | 114 | 117 | 118 | 121 | 122 | 125 | 126 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 146 | 147 | 150 | 151 | 154 | 155 | 158 | 159 | 162 | 163 | 166 | 167 | 170 | 171 | 174 | 175 | 178 | 179 | 182 | 183 | 186 | 187 | 190 | 191 | 194 | 195 | 198 | 199 | 202 | 203 | 206 | 207 | 210 | 211 | 214 | 215 | 218 | 219 | 222 | 223 | 226 | 227 | 230 | 231 | 234 | 235 | 238 | 239 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255 | 256 | 257 | 258 | 259 | 260 | 261 | -------------------------------------------------------------------------------- /src/android/ClearReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | package de.appplant.cordova.plugin.localnotification; 23 | 24 | import android.os.Bundle; 25 | 26 | import de.appplant.cordova.plugin.notification.Notification; 27 | import de.appplant.cordova.plugin.notification.receiver.AbstractClearReceiver; 28 | 29 | import static de.appplant.cordova.plugin.localnotification.LocalNotification.fireEvent; 30 | import static de.appplant.cordova.plugin.localnotification.LocalNotification.isAppRunning; 31 | import static de.appplant.cordova.plugin.notification.Request.EXTRA_LAST; 32 | 33 | /** 34 | * The clear intent receiver is triggered when the user clears a 35 | * notification manually. It un-persists the cleared notification from the 36 | * shared preferences. 37 | */ 38 | public class ClearReceiver extends AbstractClearReceiver { 39 | 40 | /** 41 | * Called when a local notification was cleared from outside of the app. 42 | * 43 | * @param notification Wrapper around the local notification. 44 | * @param bundle The bundled extras. 45 | */ 46 | @Override 47 | public void onClear (Notification notification, Bundle bundle) { 48 | boolean isLast = bundle.getBoolean(EXTRA_LAST, false); 49 | 50 | if (isLast) { 51 | notification.cancel(); 52 | } else { 53 | notification.clear(); 54 | } 55 | 56 | if (isAppRunning()) { 57 | fireEvent("clear", notification); 58 | } 59 | } 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/android/ClickReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | package de.appplant.cordova.plugin.localnotification; 23 | 24 | import android.os.Bundle; 25 | import androidx.core.app.RemoteInput; 26 | 27 | import org.json.JSONException; 28 | import org.json.JSONObject; 29 | 30 | import de.appplant.cordova.plugin.notification.Notification; 31 | import de.appplant.cordova.plugin.notification.receiver.AbstractClickReceiver; 32 | import de.appplant.cordova.plugin.notification.util.LaunchUtils; 33 | 34 | import static de.appplant.cordova.plugin.localnotification.LocalNotification.fireEvent; 35 | import static de.appplant.cordova.plugin.notification.Options.EXTRA_LAUNCH; 36 | import static de.appplant.cordova.plugin.notification.Request.EXTRA_LAST; 37 | 38 | /** 39 | * The receiver activity is triggered when a notification is clicked by a user. 40 | * The activity calls the background callback and brings the launch intent 41 | * up to foreground. 42 | */ 43 | public class ClickReceiver extends AbstractClickReceiver { 44 | 45 | /** 46 | * Called when local notification was clicked by the user. 47 | * 48 | * @param notification Wrapper around the local notification. 49 | * @param bundle The bundled extras. 50 | */ 51 | @Override 52 | public void onClick(Notification notification, Bundle bundle) { 53 | String action = getAction(); 54 | JSONObject data = new JSONObject(); 55 | 56 | setTextInput(action, data); 57 | launchAppIf(); 58 | 59 | fireEvent(action, notification, data); 60 | 61 | if (notification.getOptions().isSticky()) 62 | return; 63 | 64 | if (isLast()) { 65 | notification.cancel(); 66 | } else { 67 | notification.clear(); 68 | } 69 | } 70 | 71 | /** 72 | * Set the text if any remote input is given. 73 | * 74 | * @param action The action where to look for. 75 | * @param data The object to extend. 76 | */ 77 | private void setTextInput(String action, JSONObject data) { 78 | Bundle input = RemoteInput.getResultsFromIntent(getIntent()); 79 | 80 | if (input == null) 81 | return; 82 | 83 | try { 84 | data.put("text", input.getCharSequence(action)); 85 | } catch (JSONException e) { 86 | e.printStackTrace(); 87 | } 88 | } 89 | 90 | /** 91 | * Launch app if requested by user. 92 | */ 93 | private void launchAppIf() { 94 | boolean doLaunch = getIntent().getBooleanExtra(EXTRA_LAUNCH, true); 95 | 96 | if (!doLaunch) 97 | return; 98 | 99 | LaunchUtils.launchApp(getApplicationContext()); 100 | } 101 | 102 | /** 103 | * If the notification was the last scheduled one by request. 104 | */ 105 | private boolean isLast() { 106 | return getIntent().getBooleanExtra(EXTRA_LAST, false); 107 | } 108 | 109 | } 110 | -------------------------------------------------------------------------------- /src/android/RestoreReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2015 by appPlant UG. All rights reserved. 3 | * 4 | * @APPPLANT_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPPLANT_LICENSE_HEADER_END@ 22 | */ 23 | 24 | package de.appplant.cordova.plugin.localnotification; 25 | 26 | import android.content.Context; 27 | import android.util.Log; 28 | 29 | import java.util.Date; 30 | 31 | import de.appplant.cordova.plugin.notification.Builder; 32 | import de.appplant.cordova.plugin.notification.Manager; 33 | import de.appplant.cordova.plugin.notification.Notification; 34 | import de.appplant.cordova.plugin.notification.Request; 35 | import de.appplant.cordova.plugin.notification.receiver.AbstractRestoreReceiver; 36 | 37 | import static de.appplant.cordova.plugin.localnotification.LocalNotification.fireEvent; 38 | import static de.appplant.cordova.plugin.localnotification.LocalNotification.isAppRunning; 39 | import static de.appplant.cordova.plugin.localnotification.LocalNotification.isInForeground; 40 | 41 | /** 42 | * This class is triggered upon reboot of the device. It needs to re-register 43 | * the alarms with the AlarmManager since these alarms are lost in case of 44 | * reboot. 45 | */ 46 | public class RestoreReceiver extends AbstractRestoreReceiver { 47 | /** 48 | * Called when a local notification need to be restored. 49 | * 50 | * @param request Set of notification options. 51 | * @param toast Wrapper around the local notification. 52 | */ 53 | @Override 54 | public void onRestore (Request request, Notification toast) { 55 | Date date = request.getTriggerDate(); 56 | boolean after = date != null && date.after(new Date()); 57 | 58 | if (!after && toast.isHighPrio()) { 59 | performNotification(toast); 60 | } else { 61 | // reschedule if we aren't firing here. 62 | // If we do fire, performNotification takes care of 63 | // next schedule. 64 | 65 | Context ctx = toast.getContext(); 66 | Manager mgr = Manager.getInstance(ctx); 67 | 68 | if (after || toast.isRepeating()) { 69 | mgr.schedule(request, TriggerReceiver.class); 70 | } 71 | } 72 | } 73 | 74 | @Override 75 | public void dispatchAppEvent(String key, Notification notification) { 76 | fireEvent(key, notification); 77 | } 78 | 79 | @Override 80 | public boolean checkAppRunning() { 81 | return isAppRunning(); 82 | } 83 | 84 | /** 85 | * Build notification specified by options. 86 | * 87 | * @param builder Notification builder. 88 | */ 89 | @Override 90 | public Notification buildNotification (Builder builder) { 91 | return builder 92 | .setClickActivity(ClickReceiver.class) 93 | .setClearReceiver(ClearReceiver.class) 94 | .build(); 95 | } 96 | 97 | } 98 | -------------------------------------------------------------------------------- /src/android/TriggerReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | package de.appplant.cordova.plugin.localnotification; 23 | 24 | import android.content.Context; 25 | import android.os.Bundle; 26 | import android.os.PowerManager; 27 | 28 | import java.util.Calendar; 29 | 30 | import de.appplant.cordova.plugin.notification.Builder; 31 | import de.appplant.cordova.plugin.notification.Manager; 32 | import de.appplant.cordova.plugin.notification.Notification; 33 | import de.appplant.cordova.plugin.notification.Options; 34 | import de.appplant.cordova.plugin.notification.Request; 35 | import de.appplant.cordova.plugin.notification.receiver.AbstractTriggerReceiver; 36 | import de.appplant.cordova.plugin.notification.util.LaunchUtils; 37 | 38 | import static android.content.Context.POWER_SERVICE; 39 | import static android.os.Build.VERSION.SDK_INT; 40 | import static android.os.Build.VERSION_CODES.LOLLIPOP; 41 | import static android.os.Build.VERSION_CODES.O; 42 | import static de.appplant.cordova.plugin.localnotification.LocalNotification.fireEvent; 43 | import static de.appplant.cordova.plugin.localnotification.LocalNotification.isAppRunning; 44 | import static de.appplant.cordova.plugin.localnotification.LocalNotification.isInForeground; 45 | import static java.util.Calendar.MINUTE; 46 | 47 | import static android.os.Build.VERSION_CODES.P; 48 | 49 | /** 50 | * The alarm receiver is triggered when a scheduled alarm is fired. This class 51 | * reads the information in the intent and displays this information in the 52 | * Android notification bar. The notification uses the default notification 53 | * sound and it vibrates the phone. 54 | */ 55 | public class TriggerReceiver extends AbstractTriggerReceiver { 56 | 57 | /** 58 | * Called when a local notification was triggered. Does present the local 59 | * notification, re-schedule the alarm if necessary and fire trigger event. 60 | * 61 | * @param notification Wrapper around the local notification. 62 | * @param bundle The bundled extras. 63 | */ 64 | @Override 65 | public void onTrigger(Notification notification, Bundle bundle) { 66 | performNotification(notification); 67 | } 68 | 69 | @Override 70 | public void dispatchAppEvent(String key, Notification notification) { 71 | fireEvent(key, notification); 72 | } 73 | 74 | @Override 75 | public boolean checkAppRunning() { 76 | return isAppRunning(); 77 | } 78 | 79 | /** 80 | * Build notification specified by options. 81 | * 82 | * @param builder Notification builder. 83 | * @param bundle The bundled extras. 84 | */ 85 | @Override 86 | public Notification buildNotification(Builder builder, Bundle bundle) { 87 | return builder.setClickActivity(ClickReceiver.class).setClearReceiver(ClearReceiver.class).setExtras(bundle) 88 | .build(); 89 | } 90 | 91 | } 92 | -------------------------------------------------------------------------------- /src/android/build/localnotification.gradle: -------------------------------------------------------------------------------- 1 | /* 2 | * This file contains Original Code and/or Modifications of Original Code 3 | * as defined in and that are subject to the Apache License 4 | * Version 2.0 (the 'License'). You may not use this file except in 5 | * compliance with the License. Please obtain a copy of the License at 6 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 7 | * file. 8 | * 9 | * The Original Code and all software distributed under the License are 10 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 11 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 12 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 13 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 14 | * Please see the License for the specific language governing rights and 15 | * limitations under the License. 16 | */ 17 | 18 | repositories { 19 | mavenCentral() 20 | jcenter() 21 | maven { 22 | url "https://maven.google.com" 23 | } 24 | } 25 | 26 | if (!project.ext.has('appShortcutBadgerVersion')) { 27 | ext.appShortcutBadgerVersion = '1.1.19' 28 | } 29 | 30 | dependencies { 31 | compile "me.leolin:ShortcutBadger:${appShortcutBadgerVersion}@aar" 32 | } 33 | -------------------------------------------------------------------------------- /src/android/notification/NotificationVolumeManager.java: -------------------------------------------------------------------------------- 1 | package de.appplant.cordova.plugin.notification; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.NotificationManager; 5 | import android.content.Context; 6 | import android.content.SharedPreferences; 7 | import android.media.AudioManager; 8 | import android.util.Log; 9 | 10 | import java.util.Timer; 11 | import java.util.TimerTask; 12 | 13 | import static android.os.Build.VERSION.SDK_INT; 14 | import static android.os.Build.VERSION_CODES.M; 15 | import static java.lang.Thread.sleep; 16 | 17 | /** 18 | * Class to handle all notification volume changes 19 | */ 20 | public class NotificationVolumeManager { 21 | /** 22 | * Amount of time to sleep while polling to see if all volume writers are closed. 23 | */ 24 | final private int VOLUME_WRITER_POLLING_DURATION = 200; 25 | 26 | /** 27 | * Key for volume writer counter in shared preferences 28 | */ 29 | final private String VOLUME_CONFIG_WRITER_COUNT_KEY = "volumeConfigWriterCount"; 30 | 31 | /** 32 | * Tag for logs 33 | */ 34 | final String TAG = "NotificationVolumeMgr"; 35 | 36 | /** 37 | * Notification manager 38 | */ 39 | private NotificationManager notificationManager; 40 | 41 | /** 42 | * Audio Manager 43 | */ 44 | private AudioManager audioManager; 45 | 46 | /** 47 | * Shared preferences, used to store settings across processes 48 | */ 49 | private SharedPreferences settings; 50 | 51 | /** 52 | * Options for the notification 53 | */ 54 | private Options options; 55 | 56 | /** 57 | * Initialize the NotificationVolumeManager 58 | * @param context Application context 59 | */ 60 | public NotificationVolumeManager (Context context, Options options) { 61 | this.settings = context.getSharedPreferences(context.getPackageName(), Context.MODE_PRIVATE); 62 | this.notificationManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE); 63 | this.audioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE); 64 | this.options = options; 65 | } 66 | 67 | /** 68 | * Ensure that this is the only volume writer. 69 | * Wait until others have closed. 70 | * TODO: Better locking mechanism to ensure concurrency (file lock?) 71 | * @throws InterruptedException Throws an interrupted exception, required by sleep call. 72 | */ 73 | @SuppressLint("ApplySharedPref") 74 | private void ensureOnlyVolumeWriter () throws InterruptedException { 75 | int writerCount = settings.getInt(VOLUME_CONFIG_WRITER_COUNT_KEY, 0) + 1; 76 | settings.edit().putInt(VOLUME_CONFIG_WRITER_COUNT_KEY, writerCount).commit(); 77 | 78 | int resetDelay = options.getResetDelay(); 79 | if (resetDelay == 0) { 80 | resetDelay = Options.DEFAULT_RESET_DELAY; 81 | } 82 | 83 | int resetDelayMs = resetDelay * 1000; 84 | int sleepTotal = 0; 85 | 86 | // Wait until we are the only writer left. 87 | while(writerCount > 1) { 88 | if (sleepTotal > resetDelayMs) { 89 | throw new InterruptedException("Volume writer timeout exceeded reset delay." + 90 | "Something must have gone wrong. Reset volume writer counts to 0 " + 91 | "and reset volume settings to user settings."); 92 | } 93 | 94 | sleep(VOLUME_WRITER_POLLING_DURATION); 95 | sleepTotal += VOLUME_WRITER_POLLING_DURATION; 96 | 97 | writerCount = settings.getInt(VOLUME_CONFIG_WRITER_COUNT_KEY, 0); 98 | } 99 | } 100 | 101 | /** 102 | * Remove one count from active volume writers. Used when writer is finished. 103 | */ 104 | @SuppressLint("ApplySharedPref") 105 | private void decrementVolumeWriter () { 106 | int writerCount = settings.getInt(VOLUME_CONFIG_WRITER_COUNT_KEY, 0) - 1; 107 | settings.edit().putInt(VOLUME_CONFIG_WRITER_COUNT_KEY, Math.max(writerCount, 0)).commit(); 108 | } 109 | 110 | /** 111 | * Reset volume writer counts to 0. To be used in error conditions. 112 | */ 113 | @SuppressLint("ApplySharedPref") 114 | private void resetVolumeWriter () { 115 | settings.edit().putInt(VOLUME_CONFIG_WRITER_COUNT_KEY, 0).commit(); 116 | } 117 | 118 | /** 119 | * Set the volume for our ringer 120 | * @param ringerMode ringer mode enum. Normal ringer or vibration. 121 | * @param volume volume. 122 | */ 123 | private void setVolume (int ringerMode, int volume) { 124 | // After delay, user could have set phone to do not disturb. 125 | // If so and we can't change the ringer, quit so we don't create an error condition 126 | if (canChangeRinger()) { 127 | // Change ringer mode 128 | audioManager.setRingerMode(ringerMode); 129 | 130 | // Change to new Volume 131 | audioManager.setStreamVolume(AudioManager.STREAM_NOTIFICATION, volume, AudioManager.FLAG_REMOVE_SOUND_AND_VIBRATE); 132 | } 133 | } 134 | 135 | /** 136 | * Set the volume to the last user settings from shared preferences. 137 | */ 138 | private void setVolumeToUserSettings () { 139 | int ringMode = settings.getInt("userRingerMode", -1); 140 | int volume = settings.getInt("userVolume", -1); 141 | 142 | setVolume(ringMode, volume); 143 | } 144 | 145 | /** 146 | * Figure out if we can change the ringer. 147 | * In Android M+, we can't change out of do not disturb if we don't have explicit permission. 148 | * @return whether or not we can change the ringer. 149 | */ 150 | private boolean canChangeRinger() { 151 | return SDK_INT < M || notificationManager.isNotificationPolicyAccessGranted() 152 | || audioManager.getRingerMode() != AudioManager.RINGER_MODE_SILENT; 153 | } 154 | 155 | /** 156 | * Adjusts alarm Volume 157 | * Options object. Contains our volume, reset and vibration settings. 158 | */ 159 | @SuppressLint("ApplySharedPref") 160 | public void adjustAlarmVolume () { 161 | Integer volume = options.getVolume(); 162 | 163 | if (volume.equals(Options.VOLUME_NOT_SET) || !canChangeRinger()) { 164 | return; 165 | } 166 | 167 | try { 168 | ensureOnlyVolumeWriter(); 169 | 170 | boolean vibrate = options.isWithVibration(); 171 | 172 | int delay = options.getResetDelay(); 173 | 174 | if (delay <= 0) { 175 | delay = Options.DEFAULT_RESET_DELAY; 176 | } 177 | 178 | // Count of all alarms currently sounding 179 | Integer count = settings.getInt("alarmCount", 0); 180 | settings.edit().putInt("alarmCount", count + 1).commit(); 181 | 182 | // Get current phone volume 183 | int userVolume = audioManager.getStreamVolume(AudioManager.STREAM_NOTIFICATION); 184 | 185 | // Get Ringer mode 186 | int userRingerMode = audioManager.getRingerMode(); 187 | 188 | // If this is the first alarm store the users ringer and volume settings 189 | if (count.equals(0)) { 190 | settings.edit().putInt("userVolume", userVolume).apply(); 191 | settings.edit().putInt("userRingerMode", userRingerMode).apply(); 192 | } 193 | 194 | // Calculates a new volume based on the study configure volume percentage and the devices max volume integer 195 | if (volume > 0) { 196 | // Gets devices max volume integer 197 | int maxVolume = audioManager.getStreamMaxVolume(AudioManager.STREAM_NOTIFICATION); 198 | 199 | // Calculates new volume based on devices max volume 200 | double newVolume = Math.ceil(maxVolume * (volume / 100.00)); 201 | 202 | setVolume(AudioManager.RINGER_MODE_NORMAL, (int) newVolume); 203 | } else { 204 | // Volume of 0 205 | if (vibrate) { 206 | // Change mode to vibrate 207 | setVolume(AudioManager.RINGER_MODE_VIBRATE, 0); 208 | } 209 | } 210 | 211 | // Timer to change users sound back 212 | Timer timer = new Timer(); 213 | timer.schedule(new TimerTask() { 214 | public void run() { 215 | int currentCount = settings.getInt("alarmCount", 0); 216 | currentCount = Math.max(currentCount - 1, 0); 217 | settings.edit().putInt("alarmCount", currentCount).apply(); 218 | 219 | if (currentCount == 0) { 220 | setVolumeToUserSettings(); 221 | } 222 | } 223 | }, delay * 1000); 224 | } catch (InterruptedException e) { 225 | Log.e(TAG, "interrupted waiting for volume set. " 226 | + "Reset to user setting, and set counts to 0: " + e.toString()); 227 | resetVolumeWriter(); 228 | setVolumeToUserSettings(); 229 | } finally { 230 | decrementVolumeWriter(); 231 | } 232 | } 233 | } 234 | -------------------------------------------------------------------------------- /src/android/notification/Request.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2015 by appPlant UG. All rights reserved. 3 | * 4 | * @APPPLANT_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPPLANT_LICENSE_HEADER_END@ 22 | */ 23 | 24 | package de.appplant.cordova.plugin.notification; 25 | 26 | import org.json.JSONObject; 27 | 28 | import java.util.Arrays; 29 | import java.util.Calendar; 30 | import java.util.Date; 31 | import java.util.List; 32 | 33 | import de.appplant.cordova.plugin.notification.trigger.DateTrigger; 34 | import de.appplant.cordova.plugin.notification.trigger.IntervalTrigger; 35 | import de.appplant.cordova.plugin.notification.trigger.MatchTrigger; 36 | 37 | import static de.appplant.cordova.plugin.notification.trigger.IntervalTrigger.Unit; 38 | 39 | /** 40 | * An object you use to specify a notification’s content and the condition 41 | * that triggers its delivery. 42 | */ 43 | public final class Request { 44 | 45 | // Key name for bundled extras 46 | static final String EXTRA_OCCURRENCE = "NOTIFICATION_OCCURRENCE"; 47 | 48 | // Key name for bundled extras 49 | public static final String EXTRA_LAST = "NOTIFICATION_LAST"; 50 | 51 | // The options spec 52 | private final Options options; 53 | 54 | // The right trigger for the options 55 | private final DateTrigger trigger; 56 | 57 | // How often the trigger shall occur 58 | private final int count; 59 | 60 | // The trigger spec 61 | private final JSONObject spec; 62 | 63 | // The current trigger date 64 | private Date triggerDate; 65 | 66 | /** 67 | * Create a request with a base date specified through the passed options. 68 | * 69 | * @param options The options spec. 70 | */ 71 | public Request(Options options) { 72 | this.options = options; 73 | this.spec = options.getTrigger(); 74 | this.count = Math.max(spec.optInt("count"), 1); 75 | this.trigger = buildTrigger(); 76 | this.triggerDate = trigger.getNextTriggerDate(getBaseDate()); 77 | } 78 | 79 | /** 80 | * Create a request with a base date specified via base argument. 81 | * 82 | * @param options The options spec. 83 | * @param base The base date from where to calculate the next trigger. 84 | */ 85 | public Request(Options options, Date base) { 86 | this.options = options; 87 | this.spec = options.getTrigger(); 88 | this.count = Math.max(spec.optInt("count"), 1); 89 | this.trigger = buildTrigger(); 90 | this.triggerDate = trigger.getNextTriggerDate(base); 91 | } 92 | 93 | /** 94 | * Gets the options spec. 95 | */ 96 | public Options getOptions() { 97 | return options; 98 | } 99 | 100 | /** 101 | * The identifier for the request. 102 | * 103 | * @return The notification ID as the string 104 | */ 105 | String getIdentifier() { 106 | return options.getId().toString() + "-" + getOccurrence(); 107 | } 108 | 109 | /** 110 | * The value of the internal occurrence counter. 111 | */ 112 | int getOccurrence() { 113 | return trigger.getOccurrence(); 114 | } 115 | 116 | /** 117 | * If there's one more trigger date to calculate. 118 | */ 119 | private boolean hasNext() { 120 | return triggerDate != null && getOccurrence() <= count; 121 | } 122 | 123 | /** 124 | * Moves the internal occurrence counter by one. 125 | */ 126 | boolean moveNext() { 127 | if (hasNext()) { 128 | triggerDate = getNextTriggerDate(); 129 | } else { 130 | triggerDate = null; 131 | } 132 | 133 | return this.triggerDate != null; 134 | } 135 | 136 | /** 137 | * Gets the current trigger date. 138 | * 139 | * @return null if there's no trigger date. 140 | */ 141 | public Date getTriggerDate() { 142 | Calendar now = Calendar.getInstance(); 143 | 144 | if (triggerDate == null) 145 | return null; 146 | 147 | long time = triggerDate.getTime(); 148 | 149 | if ((now.getTimeInMillis() - time) > 60000) 150 | return null; 151 | 152 | if (time >= spec.optLong("before", time + 1)) 153 | return null; 154 | 155 | return triggerDate; 156 | } 157 | 158 | /** 159 | * Gets the next trigger date based on the current trigger date. 160 | */ 161 | private Date getNextTriggerDate() { 162 | return trigger.getNextTriggerDate(triggerDate); 163 | } 164 | 165 | /** 166 | * Build the trigger specified in options. 167 | */ 168 | private DateTrigger buildTrigger() { 169 | Object every = spec.opt("every"); 170 | 171 | if (every instanceof JSONObject) { 172 | List cmp1 = getMatchingComponents(); 173 | List cmp2 = getSpecialMatchingComponents(); 174 | 175 | return new MatchTrigger(cmp1, cmp2); 176 | } 177 | 178 | Unit unit = getUnit(); 179 | int ticks = getTicks(); 180 | 181 | return new IntervalTrigger(ticks, unit); 182 | } 183 | 184 | /** 185 | * Gets the unit value. 186 | */ 187 | private Unit getUnit() { 188 | Object every = spec.opt("every"); 189 | String unit = "SECOND"; 190 | 191 | if (spec.has("unit")) { 192 | unit = spec.optString("unit", "second"); 193 | } else 194 | if (every instanceof String) { 195 | unit = spec.optString("every", "second"); 196 | } 197 | 198 | return Unit.valueOf(unit.toUpperCase()); 199 | } 200 | 201 | /** 202 | * Gets the tick value. 203 | */ 204 | private int getTicks() { 205 | Object every = spec.opt("every"); 206 | int ticks = 0; 207 | 208 | if (spec.has("at")) { 209 | ticks = 0; 210 | } else 211 | if (spec.has("in")) { 212 | ticks = spec.optInt("in", 0); 213 | } else 214 | if (every instanceof String) { 215 | ticks = 1; 216 | } else 217 | if (!(every instanceof JSONObject)) { 218 | ticks = spec.optInt("every", 0); 219 | } 220 | 221 | return ticks; 222 | } 223 | 224 | /** 225 | * Gets an array of all date parts to construct a datetime instance. 226 | * 227 | * @return [min, hour, day, month, year] 228 | */ 229 | private List getMatchingComponents() { 230 | JSONObject every = spec.optJSONObject("every"); 231 | 232 | return Arrays.asList( 233 | (Integer) every.opt("minute"), 234 | (Integer) every.opt("hour"), 235 | (Integer) every.opt("day"), 236 | (Integer) every.opt("month"), 237 | (Integer) every.opt("year") 238 | ); 239 | } 240 | 241 | /** 242 | * Gets an array of all date parts to construct a datetime instance. 243 | * 244 | * @return [min, hour, day, month, year] 245 | */ 246 | private List getSpecialMatchingComponents() { 247 | JSONObject every = spec.optJSONObject("every"); 248 | 249 | return Arrays.asList( 250 | (Integer) every.opt("weekday"), 251 | (Integer) every.opt("weekdayOrdinal"), 252 | (Integer) every.opt("weekOfMonth"), 253 | (Integer) every.opt("quarter") 254 | ); 255 | } 256 | 257 | /** 258 | * Gets the base date from where to calculate the next trigger date. 259 | */ 260 | private Date getBaseDate() { 261 | if (spec.has("requestBaseDate")) { 262 | return new Date(spec.optLong("requestBaseDate")); 263 | } else 264 | if (spec.has("at")) { 265 | return new Date(spec.optLong("at", 0)); 266 | } else 267 | if (spec.has("firstAt")) { 268 | return new Date(spec.optLong("firstAt", 0)); 269 | } else 270 | if (spec.has("after")) { 271 | return new Date(spec.optLong("after", 0)); 272 | } else { 273 | return new Date(); 274 | } 275 | } 276 | 277 | } 278 | -------------------------------------------------------------------------------- /src/android/notification/action/Action.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | package de.appplant.cordova.plugin.notification.action; 23 | 24 | import android.content.Context; 25 | import androidx.core.app.RemoteInput; 26 | 27 | import org.json.JSONArray; 28 | import org.json.JSONObject; 29 | 30 | import de.appplant.cordova.plugin.notification.util.AssetUtil; 31 | 32 | /** 33 | * Holds the icon and title components that would be used in a 34 | * NotificationCompat.Action object. Does not include the PendingIntent so 35 | * that it may be generated each time the notification is built. Necessary to 36 | * compensate for missing functionality in the support library. 37 | */ 38 | public final class Action { 39 | 40 | // Key name for bundled extras 41 | public static final String EXTRA_ID = "NOTIFICATION_ACTION_ID"; 42 | 43 | // The id for the click action 44 | public static final String CLICK_ACTION_ID = "click"; 45 | 46 | // The application context 47 | private final Context context; 48 | 49 | // The action spec 50 | private final JSONObject options; 51 | 52 | /** 53 | * Structure to encapsulate a named action that can be shown as part of 54 | * this notification. 55 | * 56 | * @param context The application context. 57 | * @param options The action options. 58 | */ 59 | Action (Context context, JSONObject options) { 60 | this.context = context; 61 | this.options = options; 62 | } 63 | 64 | /** 65 | * Gets the ID for the action. 66 | */ 67 | public String getId() { 68 | return options.optString("id", getTitle()); 69 | } 70 | 71 | /** 72 | * Gets the Title for the action. 73 | */ 74 | public String getTitle() { 75 | return options.optString("title", "unknown"); 76 | } 77 | 78 | /** 79 | * Gets the icon for the action. 80 | */ 81 | public int getIcon() { 82 | AssetUtil assets = AssetUtil.getInstance(context); 83 | String resPath = options.optString("icon"); 84 | int resId = assets.getResId(resPath); 85 | 86 | if (resId == 0) { 87 | resId = android.R.drawable.screen_background_dark; 88 | } 89 | 90 | return resId; 91 | } 92 | 93 | /** 94 | * Gets the value of the launch flag. 95 | */ 96 | public boolean isLaunchingApp() { 97 | return options.optBoolean("launch", false); 98 | } 99 | 100 | /** 101 | * Gets the type for the action. 102 | */ 103 | public boolean isWithInput() { 104 | String type = options.optString("type"); 105 | return type.equals("input"); 106 | } 107 | 108 | /** 109 | * Gets the input config in case of the action is of type input. 110 | */ 111 | public RemoteInput getInput() { 112 | return new RemoteInput.Builder(getId()) 113 | .setLabel(options.optString("emptyText")) 114 | .setAllowFreeFormInput(options.optBoolean("editable", true)) 115 | .setChoices(getChoices()) 116 | .build(); 117 | } 118 | 119 | /** 120 | * List of possible choices for input actions. 121 | */ 122 | private String[] getChoices() { 123 | JSONArray opts = options.optJSONArray("choices"); 124 | 125 | if (opts == null) 126 | return null; 127 | 128 | String[] choices = new String[opts.length()]; 129 | 130 | for (int i = 0; i < choices.length; i++) { 131 | choices[i] = opts.optString(i); 132 | } 133 | 134 | return choices; 135 | } 136 | 137 | } 138 | -------------------------------------------------------------------------------- /src/android/notification/action/ActionGroup.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | package de.appplant.cordova.plugin.notification.action; 23 | 24 | import android.content.Context; 25 | import android.util.Log; 26 | 27 | import org.json.JSONArray; 28 | import org.json.JSONObject; 29 | 30 | import java.util.ArrayList; 31 | import java.util.HashMap; 32 | import java.util.List; 33 | import java.util.Map; 34 | 35 | import static android.os.Build.VERSION.SDK_INT; 36 | import static android.os.Build.VERSION_CODES.N; 37 | 38 | public final class ActionGroup { 39 | 40 | // Saves all groups for later lookup. 41 | private static final Map groups = new HashMap(); 42 | 43 | // The ID of the action group. 44 | private final String id; 45 | 46 | // List of actions 47 | private final Action[] actions; 48 | 49 | /** 50 | * Lookup the action groups with the specified group id. 51 | * 52 | * @param id The ID of the action group to find. 53 | * 54 | * @return Null if no group was found. 55 | */ 56 | public static ActionGroup lookup(String id) { 57 | return groups.get(id); 58 | } 59 | 60 | /** 61 | * Register the action group for later lookup. 62 | * 63 | * @param group The action group to register. 64 | */ 65 | public static void register (ActionGroup group) { 66 | groups.put(group.getId(), group); 67 | } 68 | 69 | /** 70 | * Unregister the action group. 71 | * 72 | * @param id The id of the action group to remove. 73 | */ 74 | public static void unregister (String id) { 75 | groups.remove(id); 76 | } 77 | 78 | /** 79 | * Check if a action group with that id is registered. 80 | * 81 | * @param id The id of the action group to check for. 82 | */ 83 | public static boolean isRegistered (String id) { 84 | return groups.containsKey(id); 85 | } 86 | 87 | /** 88 | * Creates an action group by parsing the specified action specs. 89 | * 90 | * @param list The list of actions. 91 | * 92 | * @return A new action group. 93 | */ 94 | public static ActionGroup parse (Context context, JSONArray list) { 95 | return parse(context, null, list); 96 | } 97 | 98 | /** 99 | * Creates an action group by parsing the specified action specs. 100 | * 101 | * @param id The id for the action group. 102 | * @param list The list of actions. 103 | * 104 | * @return A new action group. 105 | */ 106 | public static ActionGroup parse (Context context, String id, JSONArray list) { 107 | List actions = new ArrayList(list.length()); 108 | 109 | for (int i = 0; i < list.length(); i++) { 110 | JSONObject opts = list.optJSONObject(i); 111 | String type = opts.optString("type", "button"); 112 | 113 | if (type.equals("input") && SDK_INT < N) { 114 | Log.w("Action", "Type input is not supported"); 115 | continue; 116 | } 117 | 118 | if (!(type.equals("button") || type.equals("input"))) { 119 | Log.w("Action", "Unknown type: " + type); 120 | continue; 121 | } 122 | 123 | actions.add(new Action(context, opts)); 124 | } 125 | 126 | return new ActionGroup(id, actions.toArray(new Action[actions.size()])); 127 | } 128 | 129 | /** 130 | * Creates an action group. 131 | * 132 | * @param id The ID of the group. 133 | * @param actions The list of actions. 134 | */ 135 | private ActionGroup(String id, Action[] actions) { 136 | this.id = id; 137 | this.actions = actions; 138 | } 139 | 140 | /** 141 | * Gets the action group id. 142 | */ 143 | public String getId() { 144 | return id; 145 | } 146 | 147 | /** 148 | * Gets the action list. 149 | */ 150 | public Action[] getActions() { 151 | return actions; 152 | } 153 | 154 | } -------------------------------------------------------------------------------- /src/android/notification/receiver/AbstractClearReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | package de.appplant.cordova.plugin.notification.receiver; 23 | 24 | import android.content.BroadcastReceiver; 25 | import android.content.Context; 26 | import android.content.Intent; 27 | import android.os.Bundle; 28 | 29 | import de.appplant.cordova.plugin.notification.Manager; 30 | import de.appplant.cordova.plugin.notification.Notification; 31 | 32 | /** 33 | * Abstract delete receiver for local notifications. Creates the local 34 | * notification and calls the event functions for further proceeding. 35 | */ 36 | abstract public class AbstractClearReceiver extends BroadcastReceiver { 37 | 38 | /** 39 | * Called when the notification was cleared from the notification center. 40 | * 41 | * @param context Application context 42 | * @param intent Received intent with content data 43 | */ 44 | @Override 45 | public void onReceive(Context context, Intent intent) { 46 | Bundle bundle = intent.getExtras(); 47 | 48 | if (bundle == null) 49 | return; 50 | 51 | int toastId = bundle.getInt(Notification.EXTRA_ID); 52 | Notification toast = Manager.getInstance(context).get(toastId); 53 | 54 | if (toast == null) 55 | return; 56 | 57 | onClear(toast, bundle); 58 | } 59 | 60 | /** 61 | * Called when a local notification was cleared from outside of the app. 62 | * 63 | * @param notification Wrapper around the local notification. 64 | * @param bundle The bundled extras. 65 | */ 66 | abstract public void onClear (Notification notification, Bundle bundle); 67 | 68 | } 69 | -------------------------------------------------------------------------------- /src/android/notification/receiver/AbstractClickReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | package de.appplant.cordova.plugin.notification.receiver; 23 | 24 | import android.app.IntentService; 25 | import android.content.Context; 26 | import android.content.Intent; 27 | import android.os.Bundle; 28 | 29 | import de.appplant.cordova.plugin.notification.Manager; 30 | import de.appplant.cordova.plugin.notification.Notification; 31 | 32 | import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT; 33 | import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; 34 | import static de.appplant.cordova.plugin.notification.action.Action.CLICK_ACTION_ID; 35 | import static de.appplant.cordova.plugin.notification.action.Action.EXTRA_ID; 36 | 37 | /** 38 | * Abstract content receiver activity for local notifications. Creates the 39 | * local notification and calls the event functions for further proceeding. 40 | */ 41 | abstract public class AbstractClickReceiver extends IntentService { 42 | 43 | // Holds a reference to the intent to handle. 44 | private Intent intent; 45 | 46 | public AbstractClickReceiver() { 47 | super("LocalNotificationClickReceiver"); 48 | } 49 | 50 | /** 51 | * Called when local notification was clicked to launch the main intent. 52 | */ 53 | @Override 54 | protected void onHandleIntent(Intent intent) { 55 | this.intent = intent; 56 | 57 | if (intent == null) 58 | return; 59 | 60 | Bundle bundle = intent.getExtras(); 61 | Context context = getApplicationContext(); 62 | 63 | if (bundle == null) 64 | return; 65 | 66 | int toastId = bundle.getInt(Notification.EXTRA_ID); 67 | Notification toast = Manager.getInstance(context).get(toastId); 68 | 69 | if (toast == null) 70 | return; 71 | 72 | onClick(toast, bundle); 73 | this.intent = null; 74 | } 75 | 76 | /** 77 | * Called when local notification was clicked by the user. 78 | * 79 | * @param notification Wrapper around the local notification. 80 | * @param bundle The bundled extras. 81 | */ 82 | abstract public void onClick (Notification notification, Bundle bundle); 83 | 84 | /** 85 | * The invoked action. 86 | */ 87 | protected String getAction() { 88 | return getIntent().getExtras().getString(EXTRA_ID, CLICK_ACTION_ID); 89 | } 90 | 91 | /** 92 | * Getter for the received intent. 93 | */ 94 | protected Intent getIntent() { 95 | return intent; 96 | } 97 | } 98 | -------------------------------------------------------------------------------- /src/android/notification/receiver/AbstractNotificationReceiver.java: -------------------------------------------------------------------------------- 1 | package de.appplant.cordova.plugin.notification.receiver; 2 | 3 | import android.content.BroadcastReceiver; 4 | import android.content.Context; 5 | import android.os.PowerManager; 6 | import android.util.Log; 7 | 8 | import org.json.JSONException; 9 | import org.json.JSONObject; 10 | 11 | import java.util.Calendar; 12 | 13 | import de.appplant.cordova.plugin.notification.Manager; 14 | import de.appplant.cordova.plugin.notification.Notification; 15 | import de.appplant.cordova.plugin.notification.Options; 16 | import de.appplant.cordova.plugin.notification.Request; 17 | import de.appplant.cordova.plugin.notification.util.LaunchUtils; 18 | 19 | import static android.content.Context.POWER_SERVICE; 20 | import static android.os.Build.VERSION.SDK_INT; 21 | import static android.os.Build.VERSION_CODES.O; 22 | import static android.os.Build.VERSION_CODES.P; 23 | import static java.util.Calendar.MINUTE; 24 | 25 | /** 26 | * The base class for any receiver that is trying to display a notification. 27 | */ 28 | abstract public class AbstractNotificationReceiver extends BroadcastReceiver { 29 | private final String TAG = "AbstractNotification"; 30 | 31 | /** 32 | * Perform a notification. All notification logic is here. 33 | * Determines whether to dispatch events, autoLaunch the app, use fullScreenIntents, etc. 34 | * @param notification reference to the notification to be fired 35 | */ 36 | public void performNotification(Notification notification) { 37 | Context context = notification.getContext(); 38 | Options options = notification.getOptions(); 39 | Manager manager = Manager.getInstance(context); 40 | PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE); 41 | boolean autoLaunch = options.isAutoLaunchingApp() && SDK_INT <= P && !options.useFullScreenIntent(); 42 | 43 | int badge = options.getBadgeNumber(); 44 | 45 | if (badge > 0) { 46 | manager.setBadge(badge); 47 | } 48 | 49 | if (options.shallWakeUp()) { 50 | wakeUp(notification); 51 | } 52 | 53 | if (autoLaunch) { 54 | LaunchUtils.launchApp(context); 55 | } 56 | 57 | // Show notification if we should (triggerInApp is false) 58 | // or if we can't trigger in the app due to: 59 | // 1. No autoLaunch configured/supported and app is not running. 60 | // 2. Any SDK >= Oreo is asleep (must be triggered here) 61 | boolean didShowNotification = false; 62 | if (!options.triggerInApp() || 63 | (!autoLaunch && !checkAppRunning()) 64 | ) { 65 | didShowNotification = true; 66 | notification.show(); 67 | } 68 | 69 | // run trigger function if triggerInApp() is true 70 | // and we did not send a notification. 71 | if (options.triggerInApp() && !didShowNotification) { 72 | // wake up even if we didn't set it to 73 | if (!options.shallWakeUp()) { 74 | wakeUp(notification); 75 | } 76 | 77 | dispatchAppEvent("trigger", notification); 78 | } 79 | 80 | if (!options.isInfiniteTrigger()) 81 | return; 82 | 83 | Calendar cal = Calendar.getInstance(); 84 | cal.add(MINUTE, 1); 85 | 86 | Request req = new Request( 87 | getOptionsWithBaseDate(options, cal.getTimeInMillis()), 88 | cal.getTime() 89 | ); 90 | 91 | manager.schedule(req, this.getClass()); 92 | } 93 | 94 | /** 95 | * Clone options with base date attached to trigger. 96 | * Used so that persisted objects know the last execution time. 97 | * @param baseDateMillis base date represented in milliseconds 98 | * @return new Options object with base time set in requestBaseDate. 99 | */ 100 | private Options getOptionsWithBaseDate(Options options, long baseDateMillis) { 101 | JSONObject optionsDict = options.getDict(); 102 | try { 103 | JSONObject triggerDict = optionsDict.getJSONObject("trigger"); 104 | triggerDict.put("requestBaseDate", baseDateMillis); 105 | optionsDict.remove("trigger"); 106 | optionsDict.put("trigger", triggerDict); 107 | } catch (JSONException e) { 108 | Log.e(TAG, "Unexpected error adding requestBaseDate to JSON structure: " + e.toString()); 109 | } 110 | return new Options(optionsDict); 111 | } 112 | 113 | /** 114 | * Send the application an event using our notification 115 | * @param key key for our event in the app 116 | * @param notification reference to the notification 117 | */ 118 | abstract public void dispatchAppEvent(String key, Notification notification); 119 | 120 | /** 121 | * Check if the application is running. 122 | * Should be developed in local class, which has access to things needed for this. 123 | * @return whether or not app is running 124 | */ 125 | abstract public boolean checkAppRunning(); 126 | 127 | /** 128 | * Wakeup the device. 129 | * 130 | * @param notification The notification used to wakeup the device. 131 | * contains context and timeout. 132 | */ 133 | private void wakeUp(Notification notification) { 134 | Context context = notification.getContext(); 135 | Options options = notification.getOptions(); 136 | String wakeLockTag = context.getApplicationInfo().name + ":LocalNotification"; 137 | PowerManager pm = (PowerManager) context.getSystemService(POWER_SERVICE); 138 | 139 | if (pm == null) 140 | return; 141 | 142 | int level = PowerManager.FULL_WAKE_LOCK | PowerManager.ACQUIRE_CAUSES_WAKEUP | PowerManager.ON_AFTER_RELEASE; 143 | 144 | PowerManager.WakeLock wakeLock = pm.newWakeLock(level, wakeLockTag); 145 | 146 | wakeLock.setReferenceCounted(false); 147 | wakeLock.acquire(options.getWakeLockTimeout()); 148 | } 149 | } 150 | -------------------------------------------------------------------------------- /src/android/notification/receiver/AbstractRestoreReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c) 2014-2015 by appPlant UG. All rights reserved. 3 | * 4 | * @APPPLANT_LICENSE_HEADER_START@ 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | * 21 | * @APPPLANT_LICENSE_HEADER_END@ 22 | */ 23 | 24 | package de.appplant.cordova.plugin.notification.receiver; 25 | 26 | import android.content.BroadcastReceiver; 27 | import android.content.Context; 28 | import android.content.Intent; 29 | import android.os.UserManager; 30 | 31 | import org.json.JSONObject; 32 | 33 | import java.util.List; 34 | 35 | import de.appplant.cordova.plugin.notification.Builder; 36 | import de.appplant.cordova.plugin.notification.Manager; 37 | import de.appplant.cordova.plugin.notification.Notification; 38 | import de.appplant.cordova.plugin.notification.Options; 39 | import de.appplant.cordova.plugin.notification.Request; 40 | 41 | import static android.content.Intent.ACTION_BOOT_COMPLETED; 42 | import static android.os.Build.VERSION.SDK_INT; 43 | 44 | /** 45 | * This class is triggered upon reboot of the device. It needs to re-register 46 | * the alarms with the AlarmManager since these alarms are lost in case of 47 | * reboot. 48 | */ 49 | abstract public class AbstractRestoreReceiver extends AbstractNotificationReceiver { 50 | 51 | /** 52 | * Called on device reboot. 53 | * 54 | * @param context Application context 55 | * @param intent Received intent with content data 56 | */ 57 | @Override 58 | public void onReceive (Context context, Intent intent) { 59 | String action = intent.getAction(); 60 | 61 | if (SDK_INT >= 24) { 62 | UserManager um = (UserManager) context.getSystemService(UserManager.class); 63 | if (um == null || um.isUserUnlocked() == false) return; 64 | } 65 | 66 | Manager mgr = Manager.getInstance(context); 67 | List toasts = mgr.getOptions(); 68 | 69 | for (JSONObject data : toasts) { 70 | Options options = new Options(context, data); 71 | Request request = new Request(options); 72 | Builder builder = new Builder(options); 73 | Notification toast = buildNotification(builder); 74 | 75 | onRestore(request, toast); 76 | } 77 | } 78 | 79 | /** 80 | * Called when a local notification need to be restored. 81 | * 82 | * @param request Set of notification options. 83 | * @param toast Wrapper around the local notification. 84 | */ 85 | abstract public void onRestore (Request request, Notification toast); 86 | 87 | /** 88 | * Build notification specified by options. 89 | * 90 | * @param builder Notification builder. 91 | */ 92 | abstract public Notification buildNotification (Builder builder); 93 | 94 | } 95 | -------------------------------------------------------------------------------- /src/android/notification/receiver/AbstractTriggerReceiver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | package de.appplant.cordova.plugin.notification.receiver; 23 | 24 | import android.content.BroadcastReceiver; 25 | import android.content.Context; 26 | import android.content.Intent; 27 | import android.os.Bundle; 28 | 29 | import de.appplant.cordova.plugin.notification.Builder; 30 | import de.appplant.cordova.plugin.notification.Manager; 31 | import de.appplant.cordova.plugin.notification.Notification; 32 | import de.appplant.cordova.plugin.notification.Options; 33 | 34 | /** 35 | * Abstract broadcast receiver for local notifications. Creates the 36 | * notification options and calls the event functions for further proceeding. 37 | */ 38 | abstract public class AbstractTriggerReceiver extends AbstractNotificationReceiver { 39 | 40 | /** 41 | * Called when an alarm was triggered. 42 | * 43 | * @param context Application context 44 | * @param intent Received intent with content data 45 | */ 46 | @Override 47 | public void onReceive(Context context, Intent intent) { 48 | Bundle bundle = intent.getExtras(); 49 | 50 | if (bundle == null) 51 | return; 52 | 53 | int toastId = bundle.getInt(Notification.EXTRA_ID, 0); 54 | Options options = Manager.getInstance(context).getOptions(toastId); 55 | 56 | if (options == null) 57 | return; 58 | 59 | Builder builder = new Builder(options); 60 | Notification toast = buildNotification(builder, bundle); 61 | 62 | if (toast == null) 63 | return; 64 | 65 | onTrigger(toast, bundle); 66 | } 67 | 68 | /** 69 | * Called when a local notification was triggered. 70 | * 71 | * @param notification Wrapper around the local notification. 72 | * @param bundle The bundled extras. 73 | */ 74 | abstract public void onTrigger (Notification notification, Bundle bundle); 75 | 76 | /** 77 | * Build notification specified by options. 78 | * 79 | * @param builder Notification builder. 80 | * @param bundle The bundled extras. 81 | */ 82 | abstract public Notification buildNotification (Builder builder, 83 | Bundle bundle); 84 | 85 | } 86 | -------------------------------------------------------------------------------- /src/android/notification/trigger/DateTrigger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | package de.appplant.cordova.plugin.notification.trigger; 23 | 24 | import java.util.Calendar; 25 | import java.util.Date; 26 | 27 | abstract public class DateTrigger { 28 | 29 | // Default unit is SECOND 30 | public enum Unit { SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, YEAR } 31 | 32 | // Internal counter 33 | private int occurrence = 1; 34 | 35 | /** 36 | * Gets the next trigger date. 37 | * 38 | * @param base The date from where to calculate the trigger date. 39 | * 40 | * @return null if there's none next trigger date. 41 | */ 42 | abstract public Date getNextTriggerDate(Date base); 43 | 44 | /** 45 | * The value of the occurrence. 46 | */ 47 | public int getOccurrence() { 48 | return occurrence; 49 | } 50 | 51 | /** 52 | * Increase the occurrence by 1. 53 | */ 54 | void incOccurrence() { 55 | occurrence += 1; 56 | } 57 | 58 | /** 59 | * Gets a calendar instance pointing to the specified date. 60 | * 61 | * @param date The date to point. 62 | */ 63 | Calendar getCal (Date date) { 64 | Calendar cal = Calendar.getInstance(); 65 | cal.setTime(date); 66 | 67 | return cal; 68 | } 69 | 70 | } -------------------------------------------------------------------------------- /src/android/notification/trigger/IntervalTrigger.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | package de.appplant.cordova.plugin.notification.trigger; 23 | 24 | import java.util.Calendar; 25 | import java.util.Date; 26 | 27 | /** 28 | * Trigger class for interval based notification. Trigger by a fixed interval 29 | * from now. 30 | */ 31 | public class IntervalTrigger extends DateTrigger { 32 | 33 | // The number of ticks per interval 34 | private final int ticks; 35 | 36 | // The unit of the ticks 37 | final Unit unit; 38 | 39 | /** 40 | * Interval trigger based from now. 41 | * 42 | * @param ticks The number of ticks per interval. 43 | * @param unit The unit of the ticks. 44 | */ 45 | public IntervalTrigger(int ticks, Unit unit) { 46 | this.ticks = ticks; 47 | this.unit = unit; 48 | } 49 | 50 | /** 51 | * Gets the next trigger date. 52 | * 53 | * @param base The date from where to calculate the trigger date. 54 | * 55 | * @return null if there's none next trigger date. 56 | */ 57 | @Override 58 | public Date getNextTriggerDate(Date base) { 59 | Calendar cal = getCal(base); 60 | 61 | addInterval(cal); 62 | incOccurrence(); 63 | 64 | return cal.getTime(); 65 | } 66 | 67 | /** 68 | * Adds the amount of ticks to the calendar. 69 | * 70 | * @param cal The calendar to manipulate. 71 | */ 72 | void addInterval(Calendar cal) { 73 | switch (unit) { 74 | case SECOND: 75 | cal.add(Calendar.SECOND, ticks); 76 | break; 77 | case MINUTE: 78 | cal.add(Calendar.MINUTE, ticks); 79 | break; 80 | case HOUR: 81 | cal.add(Calendar.HOUR_OF_DAY, ticks); 82 | break; 83 | case DAY: 84 | cal.add(Calendar.DAY_OF_YEAR, ticks); 85 | break; 86 | case WEEK: 87 | cal.add(Calendar.WEEK_OF_YEAR, ticks); 88 | break; 89 | case MONTH: 90 | cal.add(Calendar.MONTH, ticks); 91 | break; 92 | case QUARTER: 93 | cal.add(Calendar.MONTH, ticks * 3); 94 | break; 95 | case YEAR: 96 | cal.add(Calendar.YEAR, ticks); 97 | break; 98 | } 99 | } 100 | 101 | } -------------------------------------------------------------------------------- /src/android/notification/util/AssetProvider.java: -------------------------------------------------------------------------------- 1 | /* 2 | Licensed to the Apache Software Foundation (ASF) under one 3 | or more contributor license agreements. See the NOTICE file 4 | distributed with this work for additional information 5 | regarding copyright ownership. The ASF licenses this file 6 | to you under the Apache License, Version 2.0 (the 7 | "License"); you may not use this file except in compliance 8 | with the License. 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, 13 | software distributed under the License is distributed on an 14 | "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 15 | KIND, either express or implied. See the License for the 16 | specific language governing permissions and limitations 17 | under the License. 18 | */ 19 | 20 | package de.appplant.cordova.plugin.notification.util; 21 | 22 | import androidx.core.content.FileProvider; 23 | 24 | public class AssetProvider extends FileProvider { 25 | // Nothing to do here 26 | } 27 | -------------------------------------------------------------------------------- /src/android/notification/util/LaunchUtils.java: -------------------------------------------------------------------------------- 1 | package de.appplant.cordova.plugin.notification.util; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | 6 | import static android.content.Intent.FLAG_ACTIVITY_REORDER_TO_FRONT; 7 | import static android.content.Intent.FLAG_ACTIVITY_SINGLE_TOP; 8 | import static android.content.Intent.FLAG_ACTIVITY_NEW_TASK; 9 | 10 | public final class LaunchUtils { 11 | 12 | /*** 13 | * Launch main intent from package. 14 | */ 15 | public static void launchApp(Context context) { 16 | String pkgName = context.getPackageName(); 17 | 18 | Intent intent = context 19 | .getPackageManager() 20 | .getLaunchIntentForPackage(pkgName); 21 | 22 | if (intent == null) 23 | return; 24 | 25 | intent.addFlags( 26 | FLAG_ACTIVITY_REORDER_TO_FRONT 27 | | FLAG_ACTIVITY_SINGLE_TOP 28 | | FLAG_ACTIVITY_NEW_TASK 29 | ); 30 | 31 | context.startActivity(intent); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/android/xml/localnotification_provider_paths.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /src/ios/APPLocalNotification.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | #import 23 | 24 | @import UserNotifications; 25 | 26 | @interface APPLocalNotification : CDVPlugin 27 | 28 | - (void) launch:(CDVInvokedUrlCommand*)command; 29 | - (void) ready:(CDVInvokedUrlCommand*)command; 30 | 31 | - (void) actions:(CDVInvokedUrlCommand*)command; 32 | 33 | - (void) check:(CDVInvokedUrlCommand*)command; 34 | - (void) request:(CDVInvokedUrlCommand*)command; 35 | 36 | - (void) schedule:(CDVInvokedUrlCommand*)command; 37 | - (void) update:(CDVInvokedUrlCommand*)command; 38 | 39 | - (void) clear:(CDVInvokedUrlCommand*)command; 40 | - (void) clearAll:(CDVInvokedUrlCommand*)command; 41 | 42 | - (void) cancel:(CDVInvokedUrlCommand*)command; 43 | - (void) cancelAll:(CDVInvokedUrlCommand*)command; 44 | 45 | - (void) type:(CDVInvokedUrlCommand*)command; 46 | 47 | - (void) ids:(CDVInvokedUrlCommand*)command; 48 | 49 | - (void) notification:(CDVInvokedUrlCommand*)command; 50 | - (void) notifications:(CDVInvokedUrlCommand*)command; 51 | 52 | @end 53 | -------------------------------------------------------------------------------- /src/ios/APPNotificationCategory.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | @import UserNotifications; 23 | 24 | @interface APPNotificationCategory : NSObject 25 | 26 | + (UNNotificationCategory*) parse:(NSArray*)list withId:(NSString*)groupId; 27 | 28 | @end 29 | -------------------------------------------------------------------------------- /src/ios/APPNotificationCategory.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | #import "APPNotificationCategory.h" 23 | 24 | @import UserNotifications; 25 | 26 | @implementation APPNotificationCategory : NSObject 27 | 28 | #pragma mark - 29 | #pragma mark Public 30 | 31 | /** 32 | * Parse the provided spec map into an action group. 33 | * 34 | * @param [ NSDictionary* ] spec A key-value property map. 35 | * Must contain an id and a list of actions. 36 | * 37 | * @return [ UNNotificationCategory* ] 38 | */ 39 | + (UNNotificationCategory*) parse:(NSArray*)list withId:(NSString*)groupId 40 | { 41 | NSArray* actions = [self parseActions:list]; 42 | 43 | return [UNNotificationCategory categoryWithIdentifier:groupId 44 | actions:actions 45 | intentIdentifiers:@[] 46 | options:UNNotificationCategoryOptionCustomDismissAction]; 47 | } 48 | 49 | #pragma mark - 50 | #pragma mark Private 51 | 52 | /** 53 | * The actions of the action group. 54 | * 55 | * @return [ NSArray* ] 56 | */ 57 | + (NSArray *) parseActions:(NSArray*)items 58 | { 59 | NSMutableArray* actions = [[NSMutableArray alloc] init]; 60 | 61 | for (NSDictionary* item in items) { 62 | NSString* id = item[@"id"]; 63 | NSString* title = item[@"title"]; 64 | NSString* type = item[@"type"]; 65 | 66 | UNNotificationActionOptions options = UNNotificationActionOptionNone; 67 | UNNotificationAction* action; 68 | 69 | if ([item[@"launch"] boolValue]) { 70 | options = UNNotificationActionOptionForeground; 71 | } 72 | 73 | if ([item[@"ui"] isEqualToString:@"decline"]) { 74 | options = options | UNNotificationActionOptionDestructive; 75 | } 76 | 77 | if ([item[@"needsAuth"] boolValue]) { 78 | options = options | UNNotificationActionOptionAuthenticationRequired; 79 | } 80 | 81 | if ([type isEqualToString:@"input"]) { 82 | NSString* submitTitle = item[@"submitTitle"]; 83 | NSString* placeholder = item[@"emptyText"]; 84 | 85 | if (!submitTitle.length) { 86 | submitTitle = @"Submit"; 87 | } 88 | 89 | action = [UNTextInputNotificationAction actionWithIdentifier:id 90 | title:title 91 | options:options 92 | textInputButtonTitle:submitTitle 93 | textInputPlaceholder:placeholder]; 94 | } else 95 | if (!type.length || [type isEqualToString:@"button"]) { 96 | action = [UNNotificationAction actionWithIdentifier:id 97 | title:title 98 | options:options]; 99 | } else { 100 | NSLog(@"Unknown action type: %@", type); 101 | } 102 | 103 | if (action) { 104 | [actions addObject:action]; 105 | } 106 | } 107 | 108 | return actions; 109 | } 110 | 111 | @end 112 | -------------------------------------------------------------------------------- /src/ios/APPNotificationContent.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | #import "APPNotificationOptions.h" 23 | 24 | @import UserNotifications; 25 | 26 | @interface APPNotificationContent : UNMutableNotificationContent 27 | 28 | - (id) initWithOptions:(NSDictionary*)dict; 29 | - (APPNotificationOptions*) options; 30 | - (UNNotificationRequest*) request; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /src/ios/APPNotificationContent.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | #import "APPNotificationContent.h" 23 | #import "APPNotificationOptions.h" 24 | #import 25 | 26 | @import UserNotifications; 27 | 28 | static char optionsKey; 29 | 30 | @implementation APPNotificationContent : UNMutableNotificationContent 31 | 32 | #pragma mark - 33 | #pragma mark Init 34 | 35 | /** 36 | * Initialize a notification with the given options. 37 | * 38 | * @param [ NSDictionary* ] dict A key-value property map. 39 | * 40 | * @return [ UNMutableNotificationContent ] 41 | */ 42 | - (id) initWithOptions:(NSDictionary*)dict 43 | { 44 | self = [self init]; 45 | 46 | [self setUserInfo:dict]; 47 | [self __init]; 48 | 49 | return self; 50 | } 51 | 52 | /** 53 | * Initialize a notification by using the options found under userInfo. 54 | * 55 | * @return [ Void ] 56 | */ 57 | - (void) __init 58 | { 59 | APPNotificationOptions* options = self.options; 60 | 61 | self.title = options.title; 62 | self.subtitle = options.subtitle; 63 | self.body = options.text; 64 | self.sound = options.sound; 65 | self.badge = options.badge; 66 | self.attachments = options.attachments; 67 | self.categoryIdentifier = options.actionGroupId; 68 | } 69 | 70 | #pragma mark - 71 | #pragma mark Public 72 | 73 | /** 74 | * The options used to initialize the notification. 75 | * 76 | * @return [ APPNotificationOptions* ] options 77 | */ 78 | - (APPNotificationOptions*) options 79 | { 80 | APPNotificationOptions* options = [self getOptions]; 81 | 82 | if (!options) { 83 | options = [[APPNotificationOptions alloc] 84 | initWithDict:[self userInfo]]; 85 | 86 | [self setOptions:options]; 87 | } 88 | 89 | return options; 90 | } 91 | 92 | /** 93 | * The notifcations request ready to add to the notification center including 94 | * all informations about trigger behavior. 95 | * 96 | * @return [ UNNotificationRequest* ] 97 | */ 98 | - (UNNotificationRequest*) request 99 | { 100 | APPNotificationOptions* opts = [self getOptions]; 101 | 102 | return [UNNotificationRequest requestWithIdentifier:opts.identifier 103 | content:self 104 | trigger:opts.trigger]; 105 | } 106 | 107 | #pragma mark - 108 | #pragma mark Private 109 | 110 | /** 111 | * The options used to initialize the notification. 112 | * 113 | * @return [ APPNotificationOptions* ] 114 | */ 115 | - (APPNotificationOptions*) getOptions 116 | { 117 | return objc_getAssociatedObject(self, &optionsKey); 118 | } 119 | 120 | /** 121 | * Set the options used to initialize the notification. 122 | * 123 | * @param [ NSDictionary* ] dict A key-value property map. 124 | * 125 | * @return [ Void ] 126 | */ 127 | - (void) setOptions:(APPNotificationOptions*)options 128 | { 129 | objc_setAssociatedObject(self, &optionsKey, 130 | options, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 131 | } 132 | 133 | @end 134 | -------------------------------------------------------------------------------- /src/ios/APPNotificationOptions.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | @import UserNotifications; 23 | 24 | @interface APPNotificationOptions : NSObject 25 | 26 | @property (readonly, getter=id) NSNumber* id; 27 | @property (readonly, getter=identifier) NSString* identifier; 28 | @property (readonly, getter=actionGroupId) NSString* actionGroupId; 29 | @property (readonly, getter=title) NSString* title; 30 | @property (readonly, getter=subtitle) NSString* subtitle; 31 | @property (readonly, getter=badge) NSNumber* badge; 32 | @property (readonly, getter=text) NSString* text; 33 | @property (readonly, getter=silent) BOOL silent; 34 | @property (readonly, getter=priority) int priority; 35 | @property (readonly, getter=sound) UNNotificationSound* sound; 36 | @property (readonly, getter=userInfo) NSDictionary* userInfo; 37 | @property (readonly, getter=attachments) NSArray*attachments; 38 | 39 | - (id) initWithDict:(NSDictionary*) dict; 40 | - (UNNotificationTrigger*) trigger; 41 | 42 | @end 43 | -------------------------------------------------------------------------------- /src/ios/UNNotificationRequest+APPLocalNotification.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | #import "APPNotificationOptions.h" 23 | 24 | @import UserNotifications; 25 | 26 | @interface UNNotificationRequest (APPLocalNotification) 27 | 28 | - (APPNotificationOptions*) options; 29 | - (BOOL) wasUpdated; 30 | - (NSString*) encodeToJSON; 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /src/ios/UNNotificationRequest+APPLocalNotification.m: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | #import "APPNotificationOptions.h" 23 | #import "UNNotificationRequest+APPLocalNotification.h" 24 | #import "APPNotificationContent.h" 25 | #import 26 | 27 | @import UserNotifications; 28 | 29 | static char optionsKey; 30 | 31 | @implementation UNNotificationRequest (APPLocalNotification) 32 | 33 | /** 34 | * Get associated option object 35 | */ 36 | - (APPNotificationOptions*) getOptions 37 | { 38 | return objc_getAssociatedObject(self, &optionsKey); 39 | } 40 | 41 | /** 42 | * Set associated option object 43 | */ 44 | - (void) setOptions:(APPNotificationOptions*)options 45 | { 46 | objc_setAssociatedObject(self, &optionsKey, 47 | options, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 48 | } 49 | 50 | /** 51 | * The options provided by the plug-in. 52 | */ 53 | - (APPNotificationOptions*) options 54 | { 55 | APPNotificationOptions* options = [self getOptions]; 56 | 57 | if (!options) { 58 | options = [[APPNotificationOptions alloc] 59 | initWithDict:[self.content userInfo]]; 60 | 61 | [self setOptions:options]; 62 | } 63 | 64 | return options; 65 | } 66 | 67 | /** 68 | * If the notification was updated. 69 | * 70 | * @return [ BOOL ] 71 | */ 72 | - (BOOL) wasUpdated 73 | { 74 | return [self.content userInfo][@"updatedAt"] != NULL; 75 | } 76 | 77 | /** 78 | * Encode the user info dict to JSON. 79 | */ 80 | - (NSString*) encodeToJSON 81 | { 82 | NSString* json; 83 | NSData* data; 84 | NSMutableDictionary* obj = [self.content.userInfo mutableCopy]; 85 | 86 | [obj removeObjectForKey:@"updatedAt"]; 87 | 88 | if (obj == NULL || obj.count == 0) 89 | return json; 90 | 91 | data = [NSJSONSerialization dataWithJSONObject:obj 92 | options:NSJSONWritingPrettyPrinted 93 | error:NULL]; 94 | 95 | json = [[NSString alloc] initWithData:data 96 | encoding:NSUTF8StringEncoding]; 97 | 98 | return [json stringByReplacingOccurrencesOfString:@"\n" 99 | withString:@""]; 100 | } 101 | 102 | @end 103 | -------------------------------------------------------------------------------- /src/ios/UNUserNotificationCenter+APPLocalNotification.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | #import "APPNotificationContent.h" 23 | 24 | @interface UNUserNotificationCenter (APPLocalNotification) 25 | 26 | extern NSString * const kAPPGeneralCategory; 27 | 28 | typedef NS_ENUM(NSUInteger, APPNotificationType) { 29 | NotifcationTypeAll = 0, 30 | NotifcationTypeScheduled = 1, 31 | NotifcationTypeTriggered = 2, 32 | NotifcationTypeUnknown = 3 33 | }; 34 | 35 | #define APPNotificationType_DEFINED 36 | 37 | @property (readonly, getter=getNotifications) NSArray* localNotifications; 38 | @property (readonly, getter=getNotificationIds) NSArray* localNotificationIds; 39 | 40 | - (void) registerGeneralNotificationCategory; 41 | - (void) addActionGroup:(UNNotificationCategory*)category; 42 | - (void) removeActionGroup:(NSString*)identifier; 43 | - (BOOL) hasActionGroup:(NSString*)identifier; 44 | 45 | - (NSArray*) getNotificationIdsByType:(APPNotificationType)type; 46 | 47 | - (UNNotificationRequest*) getNotificationWithId:(NSNumber*)id; 48 | - (APPNotificationType) getTypeOfNotificationWithId:(NSNumber*)id; 49 | 50 | - (NSArray*) getNotificationOptions; 51 | - (NSArray*) getNotificationOptionsById:(NSArray*)ids; 52 | - (NSArray*) getNotificationOptionsByType:(APPNotificationType)type; 53 | 54 | - (void) clearNotification:(UNNotificationRequest*)notification; 55 | - (void) clearNotifications; 56 | 57 | - (void) cancelNotification:(UNNotificationRequest*)notification; 58 | - (void) cancelNotifications; 59 | 60 | @end 61 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/.vs/LocalNotificationProxy/v15/.suo: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/src/windows/LocalNotificationProxy/.vs/LocalNotificationProxy/v15/.suo -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 15 4 | VisualStudioVersion = 15.0.26430.14 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "LocalNotificationProxy", "LocalNotificationProxy\LocalNotificationProxy.csproj", "{F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|Any CPU = Debug|Any CPU 11 | Debug|ARM = Debug|ARM 12 | Debug|x64 = Debug|x64 13 | Debug|x86 = Debug|x86 14 | Release|Any CPU = Release|Any CPU 15 | Release|ARM = Release|ARM 16 | Release|x64 = Release|x64 17 | Release|x86 = Release|x86 18 | EndGlobalSection 19 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 20 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 21 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Debug|Any CPU.Build.0 = Debug|Any CPU 22 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Debug|ARM.ActiveCfg = Debug|ARM 23 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Debug|ARM.Build.0 = Debug|ARM 24 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Debug|x64.ActiveCfg = Debug|x64 25 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Debug|x64.Build.0 = Debug|x64 26 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Debug|x86.ActiveCfg = Debug|x86 27 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Debug|x86.Build.0 = Debug|x86 28 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Release|Any CPU.ActiveCfg = Release|Any CPU 29 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Release|Any CPU.Build.0 = Release|Any CPU 30 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Release|ARM.ActiveCfg = Release|ARM 31 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Release|ARM.Build.0 = Release|ARM 32 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Release|x64.ActiveCfg = Release|x64 33 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Release|x64.Build.0 = Release|x64 34 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Release|x86.ActiveCfg = Release|x86 35 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1}.Release|x86.Build.0 = Release|x86 36 | EndGlobalSection 37 | GlobalSection(SolutionProperties) = preSolution 38 | HideSolutionNode = FALSE 39 | EndGlobalSection 40 | EndGlobal 41 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/ActionGroup.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification 23 | { 24 | using System.Collections.Generic; 25 | using System.Runtime.InteropServices.WindowsRuntime; 26 | using global::LocalNotificationProxy.LocalNotification.Toast; 27 | 28 | public sealed class ActionGroup 29 | { 30 | /// 31 | /// Saves all groups for later lookup. 32 | /// 33 | private static Dictionary groups = new Dictionary(); 34 | 35 | /// 36 | /// Initializes a new instance of the class. 37 | /// 38 | /// The ID of the action group. 39 | /// The list of actions to group for. 40 | public ActionGroup(string id, [ReadOnlyArray] IAction[] actions) 41 | { 42 | this.Id = id; 43 | this.Actions = actions; 44 | } 45 | 46 | /// 47 | /// Gets or sets the action group ID. 48 | /// 49 | public string Id { get; set; } 50 | 51 | /// 52 | /// Gets or sets the notification actions. 53 | /// 54 | public IAction[] Actions { get; set; } 55 | 56 | /// 57 | /// Lookup the action groups with the specified group id. 58 | /// 59 | /// The ID of the action group to find. 60 | /// Null if no group was found. 61 | public static ActionGroup Lookup(string id) 62 | { 63 | return groups[id]; 64 | } 65 | 66 | /// 67 | /// Register the provided set of actions under the specified group id. 68 | /// 69 | /// The action group to register. 70 | public static void Register(ActionGroup group) 71 | { 72 | groups.Add(group.Id, group); 73 | } 74 | 75 | /// 76 | /// Unregister the action group. 77 | /// 78 | /// The id of the action group to remove. 79 | public static void Unregister(string id) 80 | { 81 | groups.Remove(id); 82 | } 83 | 84 | /// 85 | /// Check if a action group with that id is registered. 86 | /// 87 | /// The id of the action group to check for. 88 | /// True if a group with the ID could be found. 89 | public static bool IsRegistered(string id) 90 | { 91 | return groups.ContainsKey(id); 92 | } 93 | } 94 | } 95 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/Builder.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification 23 | { 24 | using System.Diagnostics; 25 | using Microsoft.Toolkit.Uwp.Notifications; 26 | using Windows.UI.Notifications; 27 | 28 | internal class Builder 29 | { 30 | /// 31 | /// The provided trigger request. 32 | /// 33 | private readonly Request request; 34 | 35 | /// 36 | /// Initializes a new instance of the class. 37 | /// 38 | /// Trigger request. 39 | public Builder(Request request) 40 | { 41 | this.request = request; 42 | this.Content = new Notification(request.Options); 43 | } 44 | 45 | /// 46 | /// Gets the content. 47 | /// 48 | public Notification Content { get; private set; } 49 | 50 | /// 51 | /// Gets the options. 52 | /// 53 | private Options Options { get => this.Content.Options; } 54 | 55 | /// 56 | /// Build a toast notification specified by the options. 57 | /// 58 | /// A fully configured toast notification instance. 59 | public ScheduledToastNotification Build() 60 | { 61 | var toast = this.InitToast(); 62 | 63 | this.AddProgressBarToToast(toast); 64 | this.AddAttachmentsToToast(toast); 65 | this.AddActionsToToast(toast); 66 | 67 | return this.ConvertToastToNotification(toast); 68 | } 69 | 70 | /// 71 | /// Gets the initialize skeleton for a toast notification. 72 | /// 73 | /// Basic skeleton with sound, image and text. 74 | private ToastContent InitToast() 75 | { 76 | return new ToastContent() 77 | { 78 | Launch = this.Content.GetXml(), 79 | Audio = this.Content.Sound, 80 | 81 | Visual = new ToastVisual() 82 | { 83 | BindingGeneric = new ToastBindingGeneric() 84 | { 85 | Children = 86 | { 87 | new AdaptiveText() 88 | { 89 | Text = this.Options.Title 90 | }, 91 | 92 | new AdaptiveText() 93 | { 94 | Text = this.Options.Text 95 | } 96 | }, 97 | 98 | AppLogoOverride = this.Content.Icon 99 | } 100 | }, 101 | 102 | Actions = new ToastActionsCustom() 103 | { 104 | Buttons = { }, 105 | Inputs = { } 106 | } 107 | }; 108 | } 109 | 110 | /// 111 | /// Adds optional progress bar to the toast. 112 | /// 113 | /// Tho toast to extend for. 114 | private void AddProgressBarToToast(ToastContent toast) 115 | { 116 | var progressBar = this.Content.ProgressBar; 117 | 118 | if (progressBar != null) 119 | { 120 | toast.Visual.BindingGeneric.Children.Add(progressBar); 121 | } 122 | } 123 | 124 | /// 125 | /// Adds attachments to the toast. 126 | /// 127 | /// Tho toast to extend for. 128 | private void AddAttachmentsToToast(ToastContent toast) 129 | { 130 | foreach (var image in this.Content.Attachments) 131 | { 132 | toast.Visual.BindingGeneric.Children.Add(image); 133 | } 134 | } 135 | 136 | /// 137 | /// Adds buttons and input fields to the toast. 138 | /// 139 | /// Tho toast to extend for. 140 | private void AddActionsToToast(ToastContent toast) 141 | { 142 | foreach (var btn in this.Content.Inputs) 143 | { 144 | (toast.Actions as ToastActionsCustom).Inputs.Add(btn); 145 | } 146 | 147 | foreach (var btn in this.Content.Buttons) 148 | { 149 | (toast.Actions as ToastActionsCustom).Buttons.Add(btn); 150 | } 151 | } 152 | 153 | /// 154 | /// Converts the toast into a notification. 155 | /// 156 | /// The toast to convert. 157 | /// A notification ready to schedule. 158 | private ScheduledToastNotification ConvertToastToNotification(ToastContent toast) 159 | { 160 | var xml = toast.GetXml(); 161 | var at = this.request.TriggerDate; 162 | ScheduledToastNotification notification; 163 | 164 | Debug.WriteLine("[local-notification] Next trigger at: " + at); 165 | 166 | if (!at.HasValue) 167 | { 168 | return null; 169 | } 170 | 171 | try 172 | { 173 | notification = new ScheduledToastNotification(xml, at.Value); 174 | } 175 | catch 176 | { 177 | return null; 178 | } 179 | 180 | notification.Id = this.Content.Id; 181 | notification.Tag = this.Options.Id.ToString(); 182 | notification.SuppressPopup = this.Options.Silent; 183 | 184 | if (this.request.Occurrence > 2) 185 | { 186 | notification.Group = notification.Tag; 187 | } 188 | 189 | return notification; 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/Notification.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification 23 | { 24 | using System; 25 | using System.Collections.Generic; 26 | using global::LocalNotificationProxy.LocalNotification.Toast; 27 | using Microsoft.Toolkit.Uwp.Notifications; 28 | using Windows.UI.Notifications; 29 | 30 | internal class Notification 31 | { 32 | /// 33 | /// Initializes a new instance of the class. 34 | /// 35 | /// The options hash map from JS side. 36 | public Notification(Options options) 37 | { 38 | this.Options = options; 39 | } 40 | 41 | /// 42 | /// Initializes a new instance of the class. 43 | /// 44 | /// The options as a xml string. 45 | public Notification(string xml) 46 | { 47 | this.Options = Options.Parse(xml); 48 | } 49 | 50 | /// 51 | /// Initializes a new instance of the class. 52 | /// 53 | /// The options as a toast object. 54 | public Notification(ScheduledToastNotification toast) 55 | { 56 | this.Options = Options.Parse(toast.Content.GetXml()); 57 | } 58 | 59 | /// 60 | /// Initializes a new instance of the class. 61 | /// 62 | /// The options as a toast object. 63 | public Notification(ToastNotification toast) 64 | { 65 | var xml = toast.Content.DocumentElement.GetAttribute("launch"); 66 | this.Options = Options.Parse(xml); 67 | } 68 | 69 | public enum Type 70 | { 71 | All, Scheduled, Triggered, Unknown 72 | } 73 | 74 | /// 75 | /// Gets the wrapped notification options. 76 | /// 77 | public Options Options { get; private set; } 78 | 79 | /// 80 | /// Gets the unique identifier for the toast. 81 | /// 82 | public string Id => $"{this.Options.Id}#{this.Options.Trigger.Occurrence}"; 83 | 84 | /// 85 | /// Gets a ToastAudio object based on the specified sound uri. 86 | /// 87 | public ToastAudio Sound 88 | { 89 | get 90 | { 91 | var sound = new ToastAudio(); 92 | var path = this.Options.Sound; 93 | 94 | if (path == null || path.Length == 0 || path.Equals("false")) 95 | { 96 | sound.Silent = true; 97 | } 98 | else 99 | if (path.StartsWith("file:///") || path.StartsWith("http")) 100 | { 101 | sound.Src = new Uri(path, UriKind.Absolute); 102 | } 103 | else 104 | if (path.StartsWith("file://")) 105 | { 106 | sound.Src = new Uri(path.Replace("file:/", "ms-appx:///www")); 107 | } 108 | else 109 | if (path.StartsWith("res://")) 110 | { 111 | sound.Src = new Uri(path.Replace("res://", "ms-winsoundevent:notification.")); 112 | } 113 | else 114 | if (path.StartsWith("app://")) 115 | { 116 | sound.Src = new Uri(path.Replace("app:/", "ms-appdata://")); 117 | } 118 | 119 | return sound; 120 | } 121 | } 122 | 123 | /// 124 | /// Gets a GenericAppLogo object based on the specified icon uri. 125 | /// 126 | public ToastGenericAppLogo Icon 127 | { 128 | get 129 | { 130 | var image = new ToastGenericAppLogo(); 131 | var path = this.Options.Icon; 132 | 133 | if (path == null || path.StartsWith("res://logo")) 134 | { 135 | image.Source = string.Empty; 136 | } 137 | else 138 | if (path.StartsWith("file:///") || path.StartsWith("http")) 139 | { 140 | image.Source = path; 141 | } 142 | else 143 | if (path.StartsWith("file://")) 144 | { 145 | image.Source = path.Replace("file:/", "ms-appx:///www"); 146 | } 147 | else 148 | if (path.StartsWith("res://")) 149 | { 150 | image.Source = path.Replace("res://", "ms-appx:///images"); 151 | } 152 | else 153 | if (path.StartsWith("app://")) 154 | { 155 | image.Source = path.Replace("app:/", "ms-appdata://local"); 156 | } 157 | else 158 | { 159 | image.Source = string.Empty; 160 | } 161 | 162 | if (image.Source.EndsWith("?crop=none")) 163 | { 164 | image.HintCrop = ToastGenericAppLogoCrop.None; 165 | } 166 | else 167 | if (image.Source.EndsWith("?crop=cirlce")) 168 | { 169 | image.HintCrop = ToastGenericAppLogoCrop.Circle; 170 | } 171 | 172 | return image; 173 | } 174 | } 175 | 176 | /// 177 | /// Gets the parsed image attachments. 178 | /// 179 | public List Attachments 180 | { 181 | get 182 | { 183 | var images = new List(); 184 | 185 | if (this.Options.Attachments == null) 186 | { 187 | return images; 188 | } 189 | 190 | foreach (string path in this.Options.Attachments) 191 | { 192 | var image = new AdaptiveImage(); 193 | 194 | if (path.StartsWith("file:///") || path.StartsWith("http")) 195 | { 196 | image.Source = path; 197 | } 198 | else 199 | if (path.StartsWith("file://")) 200 | { 201 | image.Source = path.Replace("file:/", "ms-appx:///www"); 202 | } 203 | else 204 | if (path.StartsWith("res://")) 205 | { 206 | image.Source = path.Replace("res://", "ms-appx:///images"); 207 | } 208 | else 209 | if (path.StartsWith("app://")) 210 | { 211 | image.Source = path.Replace("app:/", "ms-appdata://local"); 212 | } 213 | 214 | if (image.Source != null) 215 | { 216 | images.Add(image); 217 | } 218 | } 219 | 220 | return images; 221 | } 222 | } 223 | 224 | /// 225 | /// Gets all toast buttons. 226 | /// 227 | public List Buttons 228 | { 229 | get 230 | { 231 | var buttons = new List(); 232 | 233 | foreach (var action in this.Options.Actions) 234 | { 235 | if (action is Button) 236 | { 237 | buttons.Add(new ToastButton(action.Title, this.Options.GetXml(action.ID)) 238 | { 239 | ActivationType = action.Launch ? ToastActivationType.Foreground : ToastActivationType.Background 240 | }); 241 | } 242 | else if (action is Input && (action as Input).SubmitTitle != null) 243 | { 244 | var input = action as Input; 245 | 246 | buttons.Add(new ToastButton(input.SubmitTitle, this.Options.GetXml(input.ID)) 247 | { 248 | ActivationType = input.Launch ? ToastActivationType.Foreground : ToastActivationType.Background, 249 | TextBoxId = input.ID 250 | }); 251 | } 252 | } 253 | 254 | return buttons; 255 | } 256 | } 257 | 258 | /// 259 | /// Gets all toast inputs. 260 | /// 261 | public List Inputs 262 | { 263 | get 264 | { 265 | var inputs = new List(); 266 | 267 | foreach (var action in this.Options.Actions) 268 | { 269 | if (!(action is Input)) 270 | { 271 | continue; 272 | } 273 | 274 | inputs.Add(new ToastTextBox(action.ID) 275 | { 276 | Title = action.Title, 277 | PlaceholderContent = (action as Input).EmptyText, 278 | DefaultInput = (action as Input).DefaultValue 279 | }); 280 | } 281 | 282 | return inputs; 283 | } 284 | } 285 | 286 | /// 287 | /// Gets the progress bar widget. 288 | /// 289 | public AdaptiveProgressBar ProgressBar 290 | { 291 | get 292 | { 293 | var bar = this.Options.ProgressBar; 294 | 295 | if (!bar.Enabled) 296 | { 297 | return null; 298 | } 299 | 300 | return new AdaptiveProgressBar() 301 | { 302 | Title = bar.Title, 303 | Value = new BindableProgressBarValue("progress.value"), 304 | ValueStringOverride = new BindableString("progress.description"), 305 | Status = new BindableString("progress.status") 306 | }; 307 | } 308 | } 309 | 310 | /// 311 | /// Gets the instance as an serialized xml element. 312 | /// 313 | /// Element with all property values set as attributes. 314 | public string GetXml() 315 | { 316 | return this.Options.GetXml(); 317 | } 318 | } 319 | } 320 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/Options.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification 23 | { 24 | using global::LocalNotificationProxy.LocalNotification.Toast; 25 | using Windows.Data.Xml.Dom; 26 | 27 | public sealed class Options 28 | { 29 | /// 30 | /// Gets notification event. 31 | /// 32 | public string Action { get; private set; } = "click"; 33 | 34 | /// 35 | /// Gets or sets notification ID. 36 | /// 37 | public int Id { get; set; } = 0; 38 | 39 | /// 40 | /// Gets or sets notification title. 41 | /// 42 | public string Title { get; set; } 43 | 44 | /// 45 | /// Gets or sets notification text. 46 | /// 47 | public string Text { get; set; } 48 | 49 | /// 50 | /// Gets or sets app badge number. 51 | /// 52 | public int Badge { get; set; } 53 | 54 | /// 55 | /// Gets or sets the notification sound. 56 | /// 57 | public string Sound { get; set; } 58 | 59 | /// 60 | /// Gets or sets the notification image. 61 | /// 62 | public string Icon { get; set; } 63 | 64 | /// 65 | /// Gets or sets a value indicating whether the popup shall be visible. 66 | /// 67 | public bool Silent { get; set; } = false; 68 | 69 | /// 70 | /// Gets or sets the notification trigger. 71 | /// 72 | public Toast.Trigger Trigger { get; set; } 73 | 74 | /// 75 | /// Gets or sets the notification user data. 76 | /// 77 | public string Data { get; set; } 78 | 79 | /// 80 | /// Gets or sets the notification attachments. 81 | /// 82 | public string[] Attachments { get; set; } 83 | 84 | /// 85 | /// Gets or sets the notification actions. 86 | /// 87 | public IAction[] Actions { get; set; } 88 | 89 | /// 90 | /// Gets or sets the notification progress bar. 91 | /// 92 | public ProgressBar ProgressBar { get; set; } 93 | 94 | /// 95 | /// Deserializes the XML string into an instance of Options. 96 | /// 97 | /// The serialized instance of Options as an xml string. 98 | /// An instance where all properties have been assigned. 99 | public static Options Parse(string identifier) 100 | { 101 | var doc = new XmlDocument(); 102 | doc.LoadXml(identifier); 103 | 104 | var options = new Options(); 105 | var node = doc.DocumentElement; 106 | 107 | options.Id = int.Parse(node.GetAttribute("id")); 108 | options.Badge = int.Parse(node.GetAttribute("badge")); 109 | options.Trigger = Toast.Trigger.Parse(node.GetAttribute("trigger")); 110 | 111 | if (node.GetAttributeNode("text") != null) 112 | { 113 | options.Text = node.GetAttribute("text"); 114 | } 115 | 116 | if (node.GetAttributeNode("title") != null) 117 | { 118 | options.Title = node.GetAttribute("title"); 119 | } 120 | 121 | if (node.GetAttributeNode("sound") != null) 122 | { 123 | options.Sound = node.GetAttribute("sound"); 124 | } 125 | 126 | if (node.GetAttributeNode("image") != null) 127 | { 128 | options.Icon = node.GetAttribute("image"); 129 | } 130 | 131 | if (node.GetAttributeNode("data") != null) 132 | { 133 | options.Data = node.GetAttribute("data"); 134 | } 135 | 136 | if (node.GetAttributeNode("attachments") != null) 137 | { 138 | options.Attachments = node.GetAttribute("attachments").Split(','); 139 | } 140 | 141 | if (node.GetAttributeNode("silent") != null) 142 | { 143 | options.Silent = true; 144 | } 145 | 146 | if (node.GetAttributeNode("action") != null) 147 | { 148 | options.Action = node.GetAttribute("action"); 149 | } 150 | 151 | return options; 152 | } 153 | 154 | /// 155 | /// Gets the instance as an serialized xml element. 156 | /// 157 | /// Element with all property values set as attributes. 158 | public string GetXml() 159 | { 160 | return this.GetXml(null); 161 | } 162 | 163 | /// 164 | /// Gets the instance as an serialized xml element. 165 | /// 166 | /// Optional (internal) event name. 167 | /// Element with all property values set as attributes. 168 | internal string GetXml(string action) 169 | { 170 | var node = new XmlDocument().CreateElement("options"); 171 | 172 | node.SetAttribute("id", this.Id.ToString()); 173 | node.SetAttribute("badge", this.Badge.ToString()); 174 | node.SetAttribute("trigger", this.Trigger.GetXml()); 175 | 176 | if (this.Title != null) 177 | { 178 | node.SetAttribute("title", this.Title); 179 | } 180 | 181 | if (this.Text != null) 182 | { 183 | node.SetAttribute("text", this.Text); 184 | } 185 | 186 | if (this.Sound != null) 187 | { 188 | node.SetAttribute("sound", this.Sound); 189 | } 190 | 191 | if (this.Icon != null) 192 | { 193 | node.SetAttribute("image", this.Icon); 194 | } 195 | 196 | if (this.Data != null) 197 | { 198 | node.SetAttribute("data", this.Data); 199 | } 200 | 201 | if (this.Attachments != null) 202 | { 203 | node.SetAttribute("attachments", string.Join(",", this.Attachments)); 204 | } 205 | 206 | if (this.Silent) 207 | { 208 | node.SetAttribute("silent", "1"); 209 | } 210 | 211 | if (action != null) 212 | { 213 | node.SetAttribute("action", action); 214 | } 215 | 216 | return node.GetXml(); 217 | } 218 | } 219 | } -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/Request.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification 23 | { 24 | using System; 25 | 26 | internal class Request 27 | { 28 | /// 29 | /// The right trigger for the options 30 | /// 31 | private readonly Trigger.DateTrigger trigger; 32 | 33 | /// 34 | /// How often the trigger shall occur. 35 | /// 36 | private readonly int count; 37 | 38 | /// 39 | /// The trigger spec. 40 | /// 41 | private readonly Toast.Trigger spec; 42 | 43 | /// 44 | /// The current trigger date. 45 | /// 46 | private DateTime? triggerDate; 47 | 48 | /// 49 | /// Initializes a new instance of the class. 50 | /// 51 | /// The options spec. 52 | public Request(Options options) 53 | { 54 | this.Options = options; 55 | this.spec = options.Trigger; 56 | this.count = Math.Max(this.spec.Count, 1); 57 | this.trigger = this.BuildTrigger(); 58 | this.triggerDate = this.trigger.GetNextTriggerDate(this.GetBaseDate()); 59 | } 60 | 61 | /// 62 | /// Gets the options spec. 63 | /// 64 | public Options Options { get; private set; } 65 | 66 | /// 67 | /// Gets the value of the internal occurrence counter. 68 | /// 69 | public int Occurrence { get => this.trigger.Occurrence; } 70 | 71 | /// 72 | /// Gets a value indicating whether there's one more trigger date to calculate. 73 | /// 74 | public bool HasNext { get => this.triggerDate.HasValue && this.Occurrence <= this.count; } 75 | 76 | /// 77 | /// Gets the current trigger date. 78 | /// 79 | public DateTime? TriggerDate 80 | { 81 | get 82 | { 83 | if (!this.triggerDate.HasValue) 84 | { 85 | return null; 86 | } 87 | 88 | if (this.spec.Before != 0) 89 | { 90 | var before = this.ToDateTime(this.spec.Before); 91 | 92 | if (this.triggerDate.Value >= before) 93 | { 94 | return null; 95 | } 96 | } 97 | 98 | var minDate = DateTime.Now.AddSeconds(0.2); 99 | 100 | if (this.triggerDate >= minDate) 101 | { 102 | return this.triggerDate; 103 | } 104 | 105 | if ((minDate - this.triggerDate).Value.TotalMinutes <= 1) 106 | { 107 | return minDate; 108 | } 109 | 110 | return null; 111 | } 112 | } 113 | 114 | /// 115 | /// Moves the internal occurrence counter by one. 116 | /// 117 | /// false if it wasnt possible anymore to move ahead. 118 | public bool MoveNext() 119 | { 120 | if (this.HasNext) 121 | { 122 | this.triggerDate = this.GetNextTriggerDate(); 123 | } 124 | else 125 | { 126 | this.triggerDate = null; 127 | } 128 | 129 | return this.triggerDate.HasValue; 130 | } 131 | 132 | /// 133 | /// Gets the next trigger date based on the current trigger date. 134 | /// 135 | /// null if there's no next one. 136 | private DateTime? GetNextTriggerDate() 137 | { 138 | if (this.triggerDate.HasValue) 139 | { 140 | return this.trigger.GetNextTriggerDate(this.triggerDate.Value); 141 | } 142 | else 143 | { 144 | return null; 145 | } 146 | } 147 | 148 | /// 149 | /// Build the trigger specified in options. 150 | /// 151 | /// Configured trigger instance 152 | private Trigger.DateTrigger BuildTrigger() 153 | { 154 | if (this.spec.Every is Toast.Every) 155 | { 156 | var matchers = this.GetMatchers(); 157 | var specials = this.GetSpecials(); 158 | 159 | return new Trigger.MatchTrigger(matchers, specials); 160 | } 161 | 162 | var unit = this.GetUnit(); 163 | var ticks = this.GetTicks(); 164 | 165 | return new Trigger.IntervalTrigger(ticks, unit); 166 | } 167 | 168 | /// 169 | /// Gets the unit value. 170 | /// 171 | /// SECOND by default. 172 | private Trigger.DateTrigger.Unit GetUnit() 173 | { 174 | var unit = "SECOND"; 175 | 176 | if (!string.IsNullOrEmpty(this.spec.Unit)) 177 | { 178 | unit = this.spec.Unit; 179 | } 180 | else if (this.spec.Every is string) 181 | { 182 | unit = this.spec.Every as string; 183 | } 184 | 185 | return (Trigger.DateTrigger.Unit)Enum.Parse( 186 | typeof(Trigger.DateTrigger.Unit), unit.ToUpper()); 187 | } 188 | 189 | /// 190 | /// Gets the tick value. 191 | /// 192 | /// Defaults to 0 193 | private int GetTicks() 194 | { 195 | if (this.spec.At != 0) 196 | { 197 | return 0; 198 | } 199 | else if (this.spec.In != 0) 200 | { 201 | return this.spec.In; 202 | } 203 | else if (this.spec.Every is string) 204 | { 205 | return 1; 206 | } 207 | else if (this.spec.Every is double) 208 | { 209 | return Convert.ToInt32(this.spec.Every); 210 | } 211 | 212 | return 0; 213 | } 214 | 215 | /// 216 | /// Gets an array of all date parts to construct a datetime instance. 217 | /// 218 | /// [min, hour, day, month, year] 219 | private int?[] GetMatchers() 220 | { 221 | var every = this.spec.Every as Toast.Every; 222 | 223 | return new int?[] 224 | { 225 | every.Minute, every.Hour, every.Day, every.Month, every.Year 226 | }; 227 | } 228 | 229 | /// 230 | /// Gets an array of all date parts to construct a datetime instance. 231 | /// 232 | /// [weekday, weekdayOrdinal, weekOfMonth, quarter] 233 | private int?[] GetSpecials() 234 | { 235 | var every = this.spec.Every as Toast.Every; 236 | 237 | return new int?[] 238 | { 239 | every.Weekday, every.WeekdayOrdinal, every.WeekOfMonth, every.Quarter 240 | }; 241 | } 242 | 243 | /// 244 | /// Gets the base date from where to calculate the next trigger date. 245 | /// 246 | /// Usually points to now 247 | private DateTime GetBaseDate() 248 | { 249 | if (this.spec.At != 0) 250 | { 251 | return this.ToDateTime(this.spec.At); 252 | } 253 | else if (this.spec.FirstAt != 0) 254 | { 255 | return this.ToDateTime(this.spec.FirstAt); 256 | } 257 | else if (this.spec.After != 0) 258 | { 259 | return this.ToDateTime(this.spec.After); 260 | } 261 | 262 | return DateTime.Now; 263 | } 264 | 265 | /// 266 | /// Unix time from milliseconds. 267 | /// 268 | /// Milliseconds 269 | /// DateTime object. 270 | private DateTime ToDateTime(long ms) 271 | { 272 | return DateTimeOffset.FromUnixTimeMilliseconds(ms).LocalDateTime; 273 | } 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/Toast/Button.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification.Toast 23 | { 24 | public sealed class Button : IAction 25 | { 26 | /// 27 | /// Gets or sets the ID. 28 | /// 29 | public string ID { get; set; } 30 | 31 | /// 32 | /// Gets or sets the title. 33 | /// 34 | public string Title { get; set; } 35 | 36 | /// 37 | /// Gets or sets a value indicating whether to launch the app. 38 | /// 39 | public bool Launch { get; set; } = true; 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/Toast/Every.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification.Toast 23 | { 24 | using System; 25 | using Windows.Data.Xml.Dom; 26 | 27 | public sealed class Every 28 | { 29 | /// 30 | /// Gets or sets the minute. 31 | /// 32 | public int? Minute { get; set; } 33 | 34 | /// 35 | /// Gets or sets the hour. 36 | /// 37 | public int? Hour { get; set; } 38 | 39 | /// 40 | /// Gets or sets the day. 41 | /// 42 | public int? Day { get; set; } 43 | 44 | /// 45 | /// Gets or sets the day of week. 46 | /// 47 | public int? Weekday { get; set; } 48 | 49 | /// 50 | /// Gets or sets the week of year. 51 | /// 52 | public int? Week { get; set; } 53 | 54 | /// 55 | /// Gets or sets the day of ordinal week. 56 | /// 57 | public int? WeekdayOrdinal { get; set; } 58 | 59 | /// 60 | /// Gets or sets the week of month. 61 | /// 62 | public int? WeekOfMonth { get; set; } 63 | 64 | /// 65 | /// Gets or sets the month. 66 | /// 67 | public int? Month { get; set; } 68 | 69 | /// 70 | /// Gets or sets the quarter. 71 | /// 72 | public int? Quarter { get; set; } 73 | 74 | /// 75 | /// Gets or sets the year. 76 | /// 77 | public int? Year { get; set; } 78 | 79 | /// 80 | /// Deserializes the XML string into an instance of Every. 81 | /// 82 | /// The serialized instance of Options as an xml string. 83 | /// An instance where all properties have been assigned. 84 | internal static Every Parse(string xml) 85 | { 86 | var doc = new XmlDocument(); 87 | doc.LoadXml(xml); 88 | 89 | var every = new Every(); 90 | var node = doc.DocumentElement; 91 | 92 | if (node.GetAttributeNode("minute") != null) 93 | { 94 | every.Minute = Convert.ToInt32(node.GetAttribute("minute")); 95 | } 96 | 97 | if (node.GetAttributeNode("hour") != null) 98 | { 99 | every.Hour = Convert.ToInt32(node.GetAttribute("hour")); 100 | } 101 | 102 | if (node.GetAttributeNode("day") != null) 103 | { 104 | every.Day = Convert.ToInt32(node.GetAttribute("day")); 105 | } 106 | 107 | if (node.GetAttributeNode("weekday") != null) 108 | { 109 | every.Weekday = Convert.ToInt32(node.GetAttribute("weekday")); 110 | } 111 | 112 | if (node.GetAttributeNode("week") != null) 113 | { 114 | every.Week = Convert.ToInt32(node.GetAttribute("week")); 115 | } 116 | 117 | if (node.GetAttributeNode("weekdayordinal") != null) 118 | { 119 | every.WeekdayOrdinal = Convert.ToInt32(node.GetAttribute("weekdayOrdinal")); 120 | } 121 | 122 | if (node.GetAttributeNode("weekOfMonth") != null) 123 | { 124 | every.WeekOfMonth = Convert.ToInt32(node.GetAttribute("weekOfMonth")); 125 | } 126 | 127 | if (node.GetAttributeNode("month") != null) 128 | { 129 | every.Month = Convert.ToInt32(node.GetAttribute("month")); 130 | } 131 | 132 | if (node.GetAttributeNode("year") != null) 133 | { 134 | every.Year = Convert.ToInt32(node.GetAttribute("year")); 135 | } 136 | 137 | return every; 138 | } 139 | 140 | /// 141 | /// Gets the instance as an serialized xml element. 142 | /// 143 | /// Element with all property values set as attributes. 144 | internal string GetXml() 145 | { 146 | var node = new XmlDocument().CreateElement("every"); 147 | 148 | if (this.Minute.HasValue) 149 | { 150 | node.SetAttribute("minute", this.Minute.ToString()); 151 | } 152 | 153 | if (this.Hour.HasValue) 154 | { 155 | node.SetAttribute("hour", this.Hour.ToString()); 156 | } 157 | 158 | if (this.Day.HasValue) 159 | { 160 | node.SetAttribute("day", this.Day.ToString()); 161 | } 162 | 163 | if (this.Weekday.HasValue) 164 | { 165 | node.SetAttribute("weekday", this.Weekday.ToString()); 166 | } 167 | 168 | if (this.Week.HasValue) 169 | { 170 | node.SetAttribute("week", this.Week.ToString()); 171 | } 172 | 173 | if (this.WeekdayOrdinal.HasValue) 174 | { 175 | node.SetAttribute("weekdayOrdinal", this.WeekdayOrdinal.ToString()); 176 | } 177 | 178 | if (this.WeekOfMonth.HasValue) 179 | { 180 | node.SetAttribute("weekOfMonth", this.WeekOfMonth.ToString()); 181 | } 182 | 183 | if (this.Month.HasValue) 184 | { 185 | node.SetAttribute("month", this.Month.ToString()); 186 | } 187 | 188 | if (this.Year.HasValue) 189 | { 190 | node.SetAttribute("year", this.Year.ToString()); 191 | } 192 | 193 | return node.GetXml(); 194 | } 195 | } 196 | } 197 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/Toast/IAction.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification.Toast 23 | { 24 | public interface IAction 25 | { 26 | /// 27 | /// Gets or sets the ID. 28 | /// 29 | string ID { get; set; } 30 | 31 | /// 32 | /// Gets or sets the title. 33 | /// 34 | string Title { get; set; } 35 | 36 | /// 37 | /// Gets or sets a value indicating whether to launch the app. 38 | /// 39 | bool Launch { get; set; } 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/Toast/Input.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification.Toast 23 | { 24 | public sealed class Input : IAction 25 | { 26 | /// 27 | /// Gets or sets the ID. 28 | /// 29 | public string ID { get; set; } 30 | 31 | /// 32 | /// Gets or sets the title. 33 | /// 34 | public string Title { get; set; } 35 | 36 | /// 37 | /// Gets or sets the title of the submit button. 38 | /// 39 | public string SubmitTitle { get; set; } 40 | 41 | /// 42 | /// Gets or sets placeholder text. 43 | /// 44 | public string EmptyText { get; set; } 45 | 46 | /// 47 | /// Gets or sets the default text. 48 | /// 49 | public string DefaultValue { get; set; } 50 | 51 | /// 52 | /// Gets or sets a value indicating whether to launch the app. 53 | /// 54 | public bool Launch { get; set; } = true; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/Toast/ProgressBar.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification.Toast 23 | { 24 | public sealed class ProgressBar 25 | { 26 | /// 27 | /// Gets or sets a value indicating whether the notification has a progress bar. 28 | /// 29 | public bool Enabled { get; set; } = false; 30 | 31 | /// 32 | /// Gets or sets the title. 33 | /// 34 | public string Title { get; set; } = string.Empty; 35 | 36 | /// 37 | /// Gets or sets the value. 38 | /// 39 | public double Value { get; set; } = 0; 40 | 41 | /// 42 | /// Gets or sets the status. 43 | /// 44 | public string Status { get; set; } = string.Empty; 45 | 46 | /// 47 | /// Gets or sets the description. 48 | /// 49 | public string Description { get; set; } = string.Empty; 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/Toast/Trigger.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification.Toast 23 | { 24 | using Windows.Data.Xml.Dom; 25 | 26 | public sealed class Trigger 27 | { 28 | // private DateTime? triggerDate; 29 | 30 | /// 31 | /// Gets the trigger type. 32 | /// 33 | public string Type { get; } = "calendar"; 34 | 35 | /// 36 | /// Gets or sets the fix trigger date. 37 | /// 38 | public long At { get; set; } = 0; 39 | 40 | /// 41 | /// Gets or sets the first trigger date. 42 | /// 43 | public long FirstAt { get; set; } = 0; 44 | 45 | /// 46 | /// Gets or sets the before trigger date. 47 | /// 48 | public long Before { get; set; } = 0; 49 | 50 | /// 51 | /// Gets or sets the after trigger date. 52 | /// 53 | public long After { get; set; } = 0; 54 | 55 | /// 56 | /// Gets or sets the relative trigger date from now. 57 | /// 58 | public int In { get; set; } = 0; 59 | 60 | /// 61 | /// Gets or sets the trigger count. 62 | /// 63 | public int Count { get; set; } = 1; 64 | 65 | /// 66 | /// Gets the trigger occurrence. 67 | /// 68 | public int Occurrence { get; internal set; } = 1; 69 | 70 | /// 71 | /// Gets or sets the trigger interval. 72 | /// 73 | public object Every { get; set; } 74 | 75 | /// 76 | /// Gets or sets the trigger unit. 77 | /// 78 | public string Unit { get; set; } 79 | 80 | /// 81 | /// Deserializes the XML string into an instance of Trigger. 82 | /// 83 | /// The serialized instance of Options as an xml string. 84 | /// An instance where all properties have been assigned. 85 | internal static Trigger Parse(string xml) 86 | { 87 | var doc = new XmlDocument(); 88 | doc.LoadXml(xml); 89 | 90 | var trigger = new Trigger(); 91 | var node = doc.DocumentElement; 92 | 93 | trigger.At = long.Parse(node.GetAttribute("at")); 94 | trigger.FirstAt = long.Parse(node.GetAttribute("firstAt")); 95 | trigger.Before = long.Parse(node.GetAttribute("before")); 96 | trigger.After = long.Parse(node.GetAttribute("after")); 97 | trigger.In = int.Parse(node.GetAttribute("in")); 98 | trigger.Count = int.Parse(node.GetAttribute("count")); 99 | trigger.Occurrence = int.Parse(node.GetAttribute("occurrence")); 100 | 101 | if (node.GetAttributeNode("unit") != null) 102 | { 103 | trigger.Unit = node.GetAttribute("unit"); 104 | } 105 | 106 | if (node.GetAttributeNode("strEvery") != null) 107 | { 108 | trigger.Every = node.GetAttribute("strEvery"); 109 | } 110 | else if (node.GetAttributeNode("hshEvery") != null) 111 | { 112 | trigger.Every = Toast.Every.Parse(node.GetAttribute("hshEvery")); 113 | } 114 | 115 | return trigger; 116 | } 117 | 118 | /// 119 | /// Gets the instance as an serialized xml element. 120 | /// 121 | /// Element with all property values set as attributes. 122 | internal string GetXml() 123 | { 124 | var node = new XmlDocument().CreateElement("trigger"); 125 | 126 | node.SetAttribute("at", this.At.ToString()); 127 | node.SetAttribute("firstAt", this.FirstAt.ToString()); 128 | node.SetAttribute("before", this.Before.ToString()); 129 | node.SetAttribute("after", this.After.ToString()); 130 | node.SetAttribute("in", this.In.ToString()); 131 | node.SetAttribute("count", this.Count.ToString()); 132 | node.SetAttribute("occurrence", this.Occurrence.ToString()); 133 | 134 | if (!string.IsNullOrEmpty(this.Unit)) 135 | { 136 | node.SetAttribute("unit", this.Unit); 137 | } 138 | 139 | if (this.Every != null) 140 | { 141 | if (this.Every is Every) 142 | { 143 | node.SetAttribute("hshEvery", (this.Every as Every).GetXml()); 144 | } 145 | else 146 | { 147 | node.SetAttribute("strEvery", this.Every.ToString()); 148 | } 149 | } 150 | 151 | return node.GetXml(); 152 | } 153 | } 154 | 155 | } 156 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/Trigger/DateTrigger.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification.Trigger 23 | { 24 | using System; 25 | 26 | internal abstract class DateTrigger 27 | { 28 | /// 29 | /// Default unit is SECOND 30 | /// 31 | public enum Unit : byte 32 | { 33 | NULL, SECOND, MINUTE, HOUR, DAY, WEEK, MONTH, QUARTER, YEAR 34 | } 35 | 36 | /// 37 | /// Gets or sets the occurrence counter. 38 | /// 39 | public int Occurrence { get; protected set; } = 1; 40 | 41 | /// 42 | /// Gets the next trigger date. 43 | /// 44 | /// The date from where to calculate the next one. 45 | /// Null if there is no next trigger date. 46 | public abstract DateTime? GetNextTriggerDate(DateTime date); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotification/Trigger/IntervalTrigger.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy.LocalNotification.Trigger 23 | { 24 | using System; 25 | 26 | internal class IntervalTrigger : DateTrigger 27 | { 28 | /// 29 | /// The number of ticks per interval. 30 | /// 31 | private readonly int ticks; 32 | 33 | /// 34 | /// Initializes a new instance of the class. 35 | /// 36 | /// The number of ticks per interval. 37 | /// The unit of the ticks. 38 | public IntervalTrigger(int ticks, Unit unit) 39 | { 40 | this.ticks = ticks; 41 | this.Unit = unit; 42 | } 43 | 44 | /// 45 | /// Gets the unit of the ticks 46 | /// 47 | internal new Unit Unit { get; private set; } 48 | 49 | /// 50 | /// Gets the next trigger date. 51 | /// 52 | /// The date from where to calculate the next one. 53 | /// Null if there is no next trigger date. 54 | public override DateTime? GetNextTriggerDate(DateTime date) 55 | { 56 | this.Occurrence += 1; 57 | return this.AddInterval(date); 58 | } 59 | 60 | /// 61 | /// Adds the interval to the specified date. 62 | /// 63 | /// The date where to add the interval of ticks 64 | /// A new datetime instance 65 | protected DateTime AddInterval(DateTime date) 66 | { 67 | switch (this.Unit) 68 | { 69 | case Unit.SECOND: 70 | return date.AddSeconds(this.ticks); 71 | case Unit.MINUTE: 72 | return date.AddMinutes(this.ticks); 73 | case Unit.HOUR: 74 | return date.AddHours(this.ticks); 75 | case Unit.DAY: 76 | return date.AddDays(this.ticks); 77 | case Unit.WEEK: 78 | return date.AddDays(this.ticks * 7); 79 | case Unit.MONTH: 80 | return date.AddMonths(this.ticks); 81 | case Unit.QUARTER: 82 | return date.AddMonths(this.ticks * 3); 83 | case Unit.YEAR: 84 | return date.AddYears(this.ticks); 85 | default: 86 | return date; 87 | } 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotificationProxy.cs: -------------------------------------------------------------------------------- 1 | /* 2 | * Apache 2.0 License 3 | * 4 | * Copyright (c) Sebastian Katzer 2017 5 | * 6 | * This file contains Original Code and/or Modifications of Original Code 7 | * as defined in and that are subject to the Apache License 8 | * Version 2.0 (the 'License'). You may not use this file except in 9 | * compliance with the License. Please obtain a copy of the License at 10 | * http://opensource.org/licenses/Apache-2.0/ and read it before using this 11 | * file. 12 | * 13 | * The Original Code and all software distributed under the License are 14 | * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 15 | * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 16 | * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 17 | * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 18 | * Please see the License for the specific language governing rights and 19 | * limitations under the License. 20 | */ 21 | 22 | namespace LocalNotificationProxy 23 | { 24 | using System.Runtime.InteropServices.WindowsRuntime; 25 | using LocalNotification; 26 | 27 | public sealed class LocalNotificationProxy 28 | { 29 | /// 30 | /// Manager wrapps the native SDK methods. 31 | /// 32 | private Manager manager = new Manager(); 33 | 34 | /// 35 | /// Check permission to schedule notifications. 36 | /// 37 | /// True if settings are enabled 38 | public bool HasPermission() 39 | { 40 | return this.manager.Enabled; 41 | } 42 | 43 | /// 44 | /// Schedule notifications. 45 | /// 46 | /// List of key-value properties 47 | public void Schedule([ReadOnlyArray] Options[] notifications) 48 | { 49 | this.manager.Schedule(notifications); 50 | } 51 | 52 | /// 53 | /// Update notifications. 54 | /// 55 | /// List of key-value properties 56 | public void Update([ReadOnlyArray] Options[] notifications) 57 | { 58 | this.manager.Update(notifications); 59 | } 60 | 61 | /// 62 | /// Clear the notifications specified by id. 63 | /// 64 | /// The IDs of the notification to clear. 65 | /// The cleared notifications. 66 | public Options[] Clear([ReadOnlyArray] int[] ids) 67 | { 68 | return this.manager.Clear(ids).ToArray(); 69 | } 70 | 71 | /// 72 | /// Clear all notifications. 73 | /// 74 | public void ClearAll() 75 | { 76 | this.manager.ClearAll(); 77 | } 78 | 79 | /// 80 | /// Cancel the notifications specified by id. 81 | /// 82 | /// The IDs of the notification to clear. 83 | /// The cleared notifications. 84 | public Options[] Cancel([ReadOnlyArray] int[] ids) 85 | { 86 | return this.manager.Cancel(ids).ToArray(); 87 | } 88 | 89 | /// 90 | /// Cancel all notifications. 91 | /// 92 | public void CancelAll() 93 | { 94 | this.manager.CancelAll(); 95 | } 96 | 97 | /// 98 | /// Gets the type of the notification specified by ID. 99 | /// 100 | /// The ID of the notification to find for. 101 | /// The type (scheduled, triggered or unknown). 102 | public string Type(int id) 103 | { 104 | return this.manager.GetType(id.ToString()).ToString().ToLower(); 105 | } 106 | 107 | /// 108 | /// List of all notifiation by id. 109 | /// 110 | /// The type of the notifications to return for. 111 | /// List of numbers 112 | public int[] Ids(int code) 113 | { 114 | var type = Notification.Type.Unknown; 115 | 116 | switch (code) 117 | { 118 | case 0: 119 | type = Notification.Type.All; 120 | break; 121 | case 1: 122 | type = Notification.Type.Scheduled; 123 | break; 124 | case 2: 125 | type = Notification.Type.Triggered; 126 | break; 127 | } 128 | 129 | return this.manager.GetIdsByType(type).ToArray(); 130 | } 131 | 132 | #pragma warning disable SA1300 // Element must begin with upper-case letter 133 | /// 134 | /// Gets a single notifiation specified by id. 135 | /// 136 | /// The ID of the notification to find. 137 | /// List of options instances 138 | public Options notification(int id) 139 | { 140 | var toast = this.manager.Get(id); 141 | 142 | return toast != null ? toast.Options : null; 143 | } 144 | #pragma warning restore SA1300 // Element must begin with upper-case letter 145 | 146 | /// 147 | /// List of (all) notifiation specified by id. 148 | /// 149 | /// The type of the notifications to return for. 150 | /// Optional list of IDs to find. 151 | /// List of options instances 152 | public Options[] Notifications(int code, [ReadOnlyArray] int[] ids) 153 | { 154 | var type = Notification.Type.Unknown; 155 | 156 | switch (code) 157 | { 158 | case 0: 159 | type = Notification.Type.All; 160 | break; 161 | case 1: 162 | type = Notification.Type.Scheduled; 163 | break; 164 | case 2: 165 | type = Notification.Type.Triggered; 166 | break; 167 | case 3: 168 | return this.manager.GetOptions(ids).ToArray(); 169 | } 170 | 171 | return this.manager.GetOptionsByType(type).ToArray(); 172 | } 173 | } 174 | } 175 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/LocalNotificationProxy.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {F5B32CBA-8DAB-43E5-AE4F-98B3B1281FF1} 8 | winmdobj 9 | Properties 10 | LocalNotificationProxy 11 | LocalNotificationProxy 12 | de-DE 13 | UAP 14 | 10.0.16299.0 15 | 10.0.15063.0 16 | 14 17 | 512 18 | {A5A43C5B-DE2A-4C0C-9213-0A381AF9435A};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} 19 | false 20 | 21 | 22 | AnyCPU 23 | true 24 | full 25 | false 26 | bin\Debug\ 27 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 28 | prompt 29 | 4 30 | 31 | 32 | AnyCPU 33 | pdbonly 34 | true 35 | bin\Release\ 36 | TRACE;NETFX_CORE;WINDOWS_UWP 37 | prompt 38 | 4 39 | 40 | 41 | x86 42 | true 43 | bin\x86\Debug\ 44 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 45 | ;2008 46 | full 47 | x86 48 | false 49 | prompt 50 | 51 | 52 | x86 53 | bin\x86\Release\ 54 | TRACE;NETFX_CORE;WINDOWS_UWP 55 | true 56 | ;2008 57 | pdbonly 58 | x86 59 | false 60 | prompt 61 | 62 | 63 | ARM 64 | true 65 | bin\ARM\Debug\ 66 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 67 | ;2008 68 | full 69 | ARM 70 | false 71 | prompt 72 | false 73 | false 74 | 75 | 76 | ARM 77 | bin\ARM\Release\ 78 | TRACE;NETFX_CORE;WINDOWS_UWP 79 | true 80 | ;2008 81 | pdbonly 82 | ARM 83 | false 84 | prompt 85 | false 86 | 87 | 88 | x64 89 | true 90 | bin\x64\Debug\ 91 | DEBUG;TRACE;NETFX_CORE;WINDOWS_UWP 92 | ;2008 93 | full 94 | x64 95 | false 96 | prompt 97 | 98 | 99 | x64 100 | bin\x64\Release\ 101 | TRACE;NETFX_CORE;WINDOWS_UWP 102 | true 103 | ;2008 104 | pdbonly 105 | x64 106 | false 107 | prompt 108 | 109 | 110 | PackageReference 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 5.0.2 134 | 135 | 136 | 1.0.2 137 | 138 | 139 | 140 | 141 | {fb381278-f4ad-4703-a12a-c43ee0b231bd} 142 | Microsoft.Toolkit.Uwp.Notifications.UWP 143 | 144 | 145 | 146 | 147 | 14.0 148 | 149 | 150 | 157 | -------------------------------------------------------------------------------- /src/windows/LocalNotificationProxy/LocalNotificationProxy/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("LocalNotificationProxy")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("")] 12 | [assembly: AssemblyProduct("LocalNotificationProxy")] 13 | [assembly: AssemblyCopyright("Copyright © 2017")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Version information for an assembly consists of the following four values: 18 | // 19 | // Major Version 20 | // Minor Version 21 | // Build Number 22 | // Revision 23 | // 24 | // You can specify all the values or you can default the Build and Revision Numbers 25 | // by using the '*' as shown below: 26 | // [assembly: AssemblyVersion("1.0.*")] 27 | [assembly: AssemblyVersion("1.0.0.0")] 28 | [assembly: AssemblyFileVersion("1.0.0.0")] 29 | [assembly: ComVisible(false)] -------------------------------------------------------------------------------- /src/windows/lib.UW/ARM/LocalNotificationProxy.winmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/src/windows/lib.UW/ARM/LocalNotificationProxy.winmd -------------------------------------------------------------------------------- /src/windows/lib.UW/ARM/Microsoft.Toolkit.Uwp.Notifications.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/src/windows/lib.UW/ARM/Microsoft.Toolkit.Uwp.Notifications.dll -------------------------------------------------------------------------------- /src/windows/lib.UW/x64/LocalNotificationProxy.winmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/src/windows/lib.UW/x64/LocalNotificationProxy.winmd -------------------------------------------------------------------------------- /src/windows/lib.UW/x64/Microsoft.Toolkit.Uwp.Notifications.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/src/windows/lib.UW/x64/Microsoft.Toolkit.Uwp.Notifications.dll -------------------------------------------------------------------------------- /src/windows/lib.UW/x86/LocalNotificationProxy.winmd: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/src/windows/lib.UW/x86/LocalNotificationProxy.winmd -------------------------------------------------------------------------------- /src/windows/lib.UW/x86/Microsoft.Toolkit.Uwp.Notifications.dll: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timkellypa/cordova-plugin-local-notifications/083ccca0f4eee8fbec0cde1edd32207c286d2a04/src/windows/lib.UW/x86/Microsoft.Toolkit.Uwp.Notifications.dll --------------------------------------------------------------------------------