summaryrefslogtreecommitdiff
path: root/plugins/de.appplant.cordova.plugin.local-notification
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/de.appplant.cordova.plugin.local-notification')
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/CHANGELOG.md61
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/LICENSE202
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/README.md136
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/plugin.xml228
-rwxr-xr-xplugins/de.appplant.cordova.plugin.local-notification/scripts/windows/broadcastActivateEvent.js80
-rwxr-xr-xplugins/de.appplant.cordova.plugin.local-notification/scripts/windows/setToastCapable.js63
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/ClearReceiver.java48
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/ClickActivity.java69
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/LocalNotification.java609
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/RestoreReceiver.java65
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/TriggerReceiver.java70
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractClearReceiver.java75
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractClickActivity.java103
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractRestoreReceiver.java83
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractTriggerReceiver.java122
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AssetUtil.java436
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Builder.java194
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/ClearReceiver.java44
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/ClickActivity.java55
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Manager.java455
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Notification.java350
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Options.java303
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/TriggerReceiver.java59
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotification.h78
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotification.m738
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotificationOptions.h39
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotificationOptions.m246
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/ios/UIApplication+APPLocalNotification.h63
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/ios/UIApplication+APPLocalNotification.m331
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/ios/UILocalNotification+APPLocalNotification.h57
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/ios/UILocalNotification+APPLocalNotification.m244
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/windows/LocalNotificationCore.js436
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/windows/LocalNotificationProxy.js311
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/src/windows/LocalNotificationUtil.js443
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/www/local-notification-core.js475
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/www/local-notification-util.js299
-rw-r--r--plugins/de.appplant.cordova.plugin.local-notification/www/local-notification.js370
37 files changed, 8040 insertions, 0 deletions
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/CHANGELOG.md b/plugins/de.appplant.cordova.plugin.local-notification/CHANGELOG.md
new file mode 100644
index 00000000..611e02f8
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/CHANGELOG.md
@@ -0,0 +1,61 @@
+ChangeLog
+---------
+
+Please also read the [Upgrade Guide](https://github.com/katzer/cordova-plugin-local-notifications/wiki/Upgrade-Guide) for more information.
+
+#### Version 0.8.1 (08.03.2015)
+
+- Fix incompatibility with cordova version 3.5-3.0
+- Fire `clear` instead of `cancel` event when clicked on repeating notifications
+- Do not fire `clear` or `cancel` event when clicked on persistent notifications
+
+### Version 0.8.0 (05.03.2015)
+
+- Support for iOS 8, Android 2 (SDK >= 7) and Android 5
+ - Windows Phone 8.1 will be added soon
+- New interfaces to ask for / register permissions required to schedule local notifications
+ - `hasPermission()` and `registerPermission()`
+ - _schedule()_ will register the permission automatically and schedule the notification if granted.
+- New interface to update already scheduled|triggered local notifications
+ - `update()`
+- New interfaces to clear the notification center
+ - `clear()` and `clearAll()`
+- New interfaces to query for local notifications, their properties, their IDs and their existence depend on their state
+ - `isPresent()`, `isScheduled()`, `isTriggered()`
+ - `getIds()`, `getAllIds()`, `getScheduledIds()`, `getTriggeredIds()`
+ - `get()`, `getAll()`, `getScheduled()`, `getTriggered()`
+- Schedule multiple local notifications at once
+ - `schedule( [{...},{...}] )`
+- Update multiple local notifications at once
+ - `update( [{...},{...}] )`
+- Clear multiple local notifications at once
+ - `clear( [1, 2] )`
+- Cancel multiple local notifications at once
+ - `cancel( [1, 2] )`
+- New URI format to specify sound and image resources
+ - `http(s):` for remote resources _(Android)_
+ - `file:` for local resources relative to the _www_ folder
+ - `res:` for native resources
+- New events
+ - `schedule`, `update`, `clear`, `clearall` and `cancelall`
+- Enhanced event informations
+ - Listener will get called with the local notification object instead of only the ID
+- Multiple listener for one event
+ - `on(event, callback, scope)`
+- Unregister event listener
+ - `un(event, callback)`
+- New Android specific properties
+ - `led` properties
+ - `sound` and `image` accepts remote resources
+- Callback function and scope for all interface methods
+ - `schedule( notification, callback, scope )`
+- Renamed `add()` to `schedule()`
+- `autoCancel` property has been removed
+ - Use `ongoing: true` for persistent local notifications on Android
+- Renamed repeat intervals
+ - `second`, `minute`, `hour`, `day`, `week`, `month` and `year`
+- Renamed some local notification properties
+ - `date`, `json`, `message` and `repeat`
+ - Scheduling local notifications with the deprecated properties is still possible
+- [Kitchen Sink sample app](https://github.com/katzer/cordova-plugin-local-notifications/tree/example)
+- [Wiki](https://github.com/katzer/cordova-plugin-local-notifications/wiki)
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/LICENSE b/plugins/de.appplant.cordova.plugin.local-notification/LICENSE
new file mode 100644
index 00000000..28974b74
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright 2013-2015 appPlant UG, Inc.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License. \ No newline at end of file
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/README.md b/plugins/de.appplant.cordova.plugin.local-notification/README.md
new file mode 100644
index 00000000..878632ba
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/README.md
@@ -0,0 +1,136 @@
+
+[![PayPayl donate button](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=L3HKQCD9UA35A "Donate once-off to this project using Paypal")
+
+#### :bangbang: Please vote for these cordova-windows issues :bangbang:
+1. https://issues.apache.org/jira/browse/CB-8674 _(Missing launch arguments)_
+2. https://issues.apache.org/jira/browse/CB-8946 _(Missing ToastCapable flag)_
+
+Thanks a lot!
+
+Cordova Local-Notification Plugin
+=================================
+
+The essential purpose of local notifications is to enable an application to inform its users that it has something for them — for example, a message or an upcoming appointment — when the application isn’t running in the foreground.<br>
+They are scheduled by an application and delivered on the same device.
+
+<img width="35%" align="right" hspace="19" vspace="12" src="https://github.com/katzer/cordova-plugin-local-notifications/blob/example/images/android.png"></img>
+
+### How they appear to the user
+Users see notifications in the following ways:
+- Displaying an alert or banner
+- Badging the app’s icon
+- Playing a sound
+
+
+### Examples of Notification Usage
+Local notifications are ideally suited for applications with time-based behaviors, such as calendar and to-do list applications. Applications that run in the background for the limited period allowed by iOS might also find local notifications useful.<br>
+For example, applications that depend on servers for messages or data can poll their servers for incoming items while running in the background; if a message is ready to view or an update is ready to download, they can then present a local notification immediately to inform their users.
+
+
+## Supported Platforms
+The current 0.8 branch supports the following platforms:
+- __iOS__ _(including iOS8)_<br>
+- __Android__ _(SDK >=7)_
+- __Windows 8.1__ _(added with v0.8.2)_
+- __Windows Phone 8.1__ _(added with v0.8.2)_
+
+Find out more informations [here][wiki_platforms] in our wiki.
+
+
+## Installation
+The plugin is installable from source and available on Cordova Plugin Registry and PhoneGap Build.
+
+Find out more informations [here][wiki_installation] in our wiki.
+
+
+## I want to get a quick overview
+All wiki pages contain samples, but for a quick overview the sample section may be the fastest way.
+
+Find out more informations [here][wiki_samples] in our wiki.
+
+
+## I want to get a deep overview
+The plugin supports scheduling local notifications in various ways with a single interface. It also allows you to update, clear or cancel them. There are different interfaces to query for local notifications and a complete set of events to hook into the life cycle of local notifications.
+
+Find out more about how to schedule single, multiple, delayed or repeating local notifications [here][wiki_schedule].<br>
+Informations about events like _click_ or _trigger_ can be found [here][wiki_events].
+
+To get a deep overview we recommend to read about all the topics in our [wiki][wiki] and try out the [Kitchen Sink App][wiki_kitchensink]
+
+
+## I want to see the plugin in action
+The plugin offers a kitchen sink sample app. Check out the cordova project and run the app directly from your command line or preferred IDE.
+
+Find out more informations [here][wiki_kitchensink] in our wiki.
+
+
+## What's new
+We are proud to announce our newest release version 0.8.x. Beside the hard work at the office and at the weekends it contains a lot of goodies, new features and easy to use APIs.
+
+Find out more informations [here][wiki_changelog] in our wiki.
+
+
+## Sample
+The sample demonstrates how to schedule a local notification which repeats every week. The listener will be called when the user has clicked on the local notification.
+
+```javascript
+cordova.plugins.notification.local.schedule({
+ id: 1,
+ title: "Production Jour fixe",
+ text: "Duration 1h",
+ firstAt: monday_9_am,
+ every: "week",
+ sound: "file://sounds/reminder.mp3",
+ icon: "http://icons.com/?cal_id=1",
+ data: { meetingId:"123#fg8" }
+});
+
+cordova.plugins.notification.local.on("click", function (notification) {
+ joinMeeting(notification.data.meetingId);
+});
+```
+
+Find out more informations [here][wiki_samples] in our wiki.
+
+
+## I would like to propose new features
+We appricate any feature proposal and support for their development. Please describe them [here][feature_proposal_issue].
+
+Find out more informations [here][wiki_next] in our wiki.
+
+## Supporting
+Your support is needed. If you use the plugin please send us a drop through the donation button.
+
+Thank you!
+
+[![PayPayl donate button](https://img.shields.io/badge/paypal-donate-yellow.svg)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=L3HKQCD9UA35A "Donate once-off to this project using Paypal")
+
+
+## Contributing
+
+1. Fork it
+2. Create your feature branch (`git checkout -b my-new-feature`)
+3. Commit your changes (`git commit -am 'Add some feature'`)
+4. Push to the branch (`git push origin my-new-feature`)
+5. Create new Pull Request
+
+
+## License
+
+This software is released under the [Apache 2.0 License][apache2_license].
+
+© 2013-2015 appPlant UG, Inc. All rights reserved
+
+
+[cordova]: https://cordova.apache.org
+[wiki]: https://github.com/katzer/cordova-plugin-local-notifications/wiki
+[wiki_platforms]: https://github.com/katzer/cordova-plugin-local-notifications/wiki/02.-Platforms
+[wiki_installation]: https://github.com/katzer/cordova-plugin-local-notifications/wiki/03.-Installation
+[wiki_kitchensink]: https://github.com/katzer/cordova-plugin-local-notifications/tree/example
+[wiki_schedule]: https://github.com/katzer/cordova-plugin-local-notifications/wiki/04.-Scheduling
+[wiki_events]: https://github.com/katzer/cordova-plugin-local-notifications/wiki/09.-Events
+[wiki_samples]: https://github.com/katzer/cordova-plugin-local-notifications/wiki/11.-Samples
+[wiki_changelog]: https://github.com/katzer/cordova-plugin-local-notifications/wiki/Upgrade-Guide
+[wiki_next]: https://github.com/katzer/cordova-plugin-local-notifications/wiki/Feature-Requests
+[feature_proposal_issue]: https://github.com/katzer/cordova-plugin-local-notifications/issues/451
+[apache2_license]: http://opensource.org/licenses/Apache-2.0
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/plugin.xml b/plugins/de.appplant.cordova.plugin.local-notification/plugin.xml
new file mode 100644
index 00000000..7efd3434
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/plugin.xml
@@ -0,0 +1,228 @@
+<?xml version="1.0" encoding="UTF-8"?>
+
+<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ id="de.appplant.cordova.plugin.local-notification"
+ version="0.8.2-dev">
+
+ <name>LocalNotification</name>
+
+ <description>The plugin supports scheduling local notifications in various ways with a single interface. It also allows you to update, clear or cancel them. There are different interfaces to query for local notifications and a complete set of events to hook into the life cycle of local notifications. To get a deep overview we recommend to read about all the topics in our wiki and try out the Kitchen Sink App</description>
+
+ <repo>https://github.com/katzer/cordova-plugin-local-notifications.git</repo>
+
+ <keywords>appplant, notification, local notification</keywords>
+
+ <license>Apache 2.0</license>
+
+ <author>Sebastián Katzer</author>
+
+ <!-- cordova -->
+ <engines>
+ <engine name="cordova" version=">=3.6.0" />
+ <engine name="cordova" version="<4.0.0" />
+ </engines>
+
+ <!-- dependencies -->
+ <dependency id="cordova-plugin-device" />
+
+ <!-- info -->
+ <info>
+ Your support is needed. If you use the local-notification plugin please support us in order to ensure further development.
+ https://github.com/katzer/cordova-plugin-local-notifications#supporting
+
+ Thank you!
+ </info>
+
+ <!-- js -->
+ <js-module src="www/local-notification.js" name="LocalNotification">
+ <clobbers target="cordova.plugins.notification.local" />
+ <clobbers target="plugin.notification.local" />
+ </js-module>
+
+ <js-module src="www/local-notification-core.js" name="LocalNotification.Core">
+ <clobbers target="cordova.plugins.notification.local.core" />
+ <clobbers target="plugin.notification.local.core" />
+ </js-module>
+
+ <js-module src="www/local-notification-util.js" name="LocalNotification.Util">
+ <merges target="cordova.plugins.notification.local.core" />
+ <merges target="plugin.notification.local.core" />
+ </js-module>
+
+ <!-- ios -->
+ <platform name="ios">
+
+ <dependency id="de.appplant.cordova.common.registerusernotificationsettings" />
+
+ <config-file target="config.xml" parent="/*">
+ <feature name="LocalNotification">
+ <param name="ios-package" value="APPLocalNotification" onload="true" />
+ <param name="onload" value="true" />
+ </feature>
+ </config-file>
+
+ <header-file src="src/ios/APPLocalNotification.h" />
+ <source-file src="src/ios/APPLocalNotification.m" />
+
+ <header-file src="src/ios/APPLocalNotificationOptions.h" />
+ <source-file src="src/ios/APPLocalNotificationOptions.m" />
+
+ <header-file src="src/ios/UIApplication+APPLocalNotification.h" />
+ <source-file src="src/ios/UIApplication+APPLocalNotification.m" />
+
+ <header-file src="src/ios/UILocalNotification+APPLocalNotification.h" />
+ <source-file src="src/ios/UILocalNotification+APPLocalNotification.m" />
+
+ </platform>
+
+ <!-- android -->
+ <platform name="android">
+
+ <framework src="com.android.support:support-v4:+" />
+
+ <config-file target="res/xml/config.xml" parent="/*">
+ <feature name="LocalNotification">
+ <param name="android-package" value="de.appplant.cordova.plugin.localnotification.LocalNotification"/>
+ </feature>
+ </config-file>
+
+ <config-file target="AndroidManifest.xml" parent="/manifest/application">
+
+ <receiver
+ android:name="de.appplant.cordova.plugin.localnotification.TriggerReceiver"
+ android:exported="false" />
+
+ <receiver
+ android:name="de.appplant.cordova.plugin.localnotification.ClearReceiver"
+ android:exported="false" />
+
+ <activity
+ android:name="de.appplant.cordova.plugin.localnotification.ClickActivity"
+ android:launchMode="singleInstance"
+ android:theme="@android:style/Theme.NoDisplay"
+ android:exported="false" />
+
+ <receiver
+ android:name="de.appplant.cordova.plugin.notification.TriggerReceiver"
+ android:exported="false" />
+
+ <receiver
+ android:name="de.appplant.cordova.plugin.notification.ClearReceiver"
+ android:exported="false" />
+
+ <receiver android:name="de.appplant.cordova.plugin.localnotification.RestoreReceiver" android:exported="false" >
+ <intent-filter>
+ <action android:name="android.intent.action.BOOT_COMPLETED" />
+ </intent-filter>
+ </receiver>
+
+ <activity
+ android:name="de.appplant.cordova.plugin.notification.ClickActivity"
+ android:launchMode="singleInstance"
+ android:theme="@android:style/Theme.NoDisplay"
+ android:exported="false" />
+
+ </config-file>
+
+ <config-file target="AndroidManifest.xml" parent="/manifest">
+ <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
+ <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
+ </config-file>
+
+ <source-file
+ src="src/android/LocalNotification.java"
+ target-dir="src/de/appplant/cordova/plugin/localnotification" />
+
+ <source-file
+ src="src/android/TriggerReceiver.java"
+ target-dir="src/de/appplant/cordova/plugin/localnotification" />
+
+ <source-file
+ src="src/android/ClickActivity.java"
+ target-dir="src/de/appplant/cordova/plugin/localnotification" />
+
+ <source-file
+ src="src/android/ClearReceiver.java"
+ target-dir="src/de/appplant/cordova/plugin/localnotification" />
+
+ <source-file
+ src="src/android/RestoreReceiver.java"
+ target-dir="src/de/appplant/cordova/plugin/localnotification" />
+
+ <source-file
+ src="src/android/notification/AbstractClearReceiver.java"
+ target-dir="src/de/appplant/cordova/plugin/notification" />
+
+ <source-file
+ src="src/android/notification/AbstractClickActivity.java"
+ target-dir="src/de/appplant/cordova/plugin/notification" />
+
+ <source-file
+ src="src/android/notification/AbstractRestoreReceiver.java"
+ target-dir="src/de/appplant/cordova/plugin/notification" />
+
+ <source-file
+ src="src/android/notification/AbstractTriggerReceiver.java"
+ target-dir="src/de/appplant/cordova/plugin/notification" />
+
+ <source-file
+ src="src/android/notification/AssetUtil.java"
+ target-dir="src/de/appplant/cordova/plugin/notification" />
+
+ <source-file
+ src="src/android/notification/Builder.java"
+ target-dir="src/de/appplant/cordova/plugin/notification" />
+
+ <source-file
+ src="src/android/notification/ClearReceiver.java"
+ target-dir="src/de/appplant/cordova/plugin/notification" />
+
+ <source-file
+ src="src/android/notification/ClickActivity.java"
+ target-dir="src/de/appplant/cordova/plugin/notification" />
+
+ <source-file
+ src="src/android/notification/Manager.java"
+ target-dir="src/de/appplant/cordova/plugin/notification" />
+
+ <source-file
+ src="src/android/notification/Notification.java"
+ target-dir="src/de/appplant/cordova/plugin/notification" />
+
+ <source-file
+ src="src/android/notification/Options.java"
+ target-dir="src/de/appplant/cordova/plugin/notification" />
+
+ <source-file
+ src="src/android/notification/TriggerReceiver.java"
+ target-dir="src/de/appplant/cordova/plugin/notification" />
+
+ </platform>
+
+ <!-- windows -->
+ <platform name="windows">
+
+ <js-module src="src/windows/LocalNotificationProxy.js" name="LocalNotification.Proxy" >
+ <merges target="" />
+ </js-module>
+
+ <js-module src="src/windows/LocalNotificationCore.js" name="LocalNotification.Proxy.Core" >
+ <merges target="" />
+ </js-module>
+
+ <js-module src="src/windows/LocalNotificationUtil.js" name="LocalNotification.Proxy.Util" >
+ <merges target="" />
+ </js-module>
+
+ <!-- Platform Hooks -->
+ <hook type="after_platform_add" src="scripts/windows/setToastCapable.js" />
+ <hook type="after_plugin_install" src="scripts/windows/setToastCapable.js" />
+
+ <hook type="after_platform_add" src="scripts/windows/broadcastActivateEvent.js" />
+ <hook type="after_plugin_install" src="scripts/windows/broadcastActivateEvent.js" />
+ <hook type="after_prepare" src="scripts/windows/broadcastActivateEvent.js" />
+
+ </platform>
+
+</plugin>
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/scripts/windows/broadcastActivateEvent.js b/plugins/de.appplant.cordova.plugin.local-notification/scripts/windows/broadcastActivateEvent.js
new file mode 100755
index 00000000..40a90ca0
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/scripts/windows/broadcastActivateEvent.js
@@ -0,0 +1,80 @@
+#!/usr/bin/env node
+
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+
+// Includes a snippet into the cordova-core js file
+// to fire the activated event after device is ready
+
+
+var fs = require('fs'),
+ rootdir = process.argv[2];
+
+if (!rootdir)
+ return;
+
+/**
+ * Replaces a string with another one in a file.
+ *
+ * @param {String} path
+ * Absolute or relative file path from cordova root project.
+ * @param {String} to_replace
+ * The string to replace.
+ * @param {String}
+ * The string to replace with.
+ */
+function replace (filename, to_replace, replace_with) {
+ var data = fs.readFileSync(filename, 'utf8'),
+ result;
+
+ if (data.indexOf(replace_with) > -1)
+ return;
+
+ result = data.replace(to_replace, replace_with);
+ fs.writeFileSync(filename, result, 'utf8');
+}
+
+// Fires the activated event again after device is ready
+var snippet =
+ "var activatedHandler = function (args) {" +
+ "channel.deviceready.subscribe(function () {" +
+ "app.queueEvent(args);" +
+ "});" +
+ "};" +
+ "app.addEventListener('activated', activatedHandler, false);" +
+ "document.addEventListener('deviceready', function () {" +
+ "app.removeEventListener('activated', activatedHandler);" +
+ "}, false);\n" +
+ " app.start();";
+
+// Path to cordova-core js files where the snippet needs to be included
+var files = [
+ 'platforms/windows/www/cordova.js',
+ 'platforms/windows/platform_www/cordova.js'
+];
+
+// Includes the snippet before app.start() is called
+for (var i = 0; i < files.length; i++) {
+ replace(files[i], 'app.start();', snippet);
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/scripts/windows/setToastCapable.js b/plugins/de.appplant.cordova.plugin.local-notification/scripts/windows/setToastCapable.js
new file mode 100755
index 00000000..46b56102
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/scripts/windows/setToastCapable.js
@@ -0,0 +1,63 @@
+#!/usr/bin/env node
+
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+
+// Hook sets ToastCapable on true to enable local-notifications
+
+
+var fs = require('fs'),
+ rootdir = process.argv[2];
+
+if (!rootdir)
+ return;
+
+/**
+ * Replaces a string with another one in a file.
+ *
+ * @param {String} path
+ * Absolute or relative file path from cordova root project.
+ * @param {String} to_replace
+ * The string to replace.
+ * @param {String}
+ * The string to replace with.
+ */
+function replace (filename, to_replace, replace_with) {
+ var data = fs.readFileSync(filename, 'utf8'),
+ result;
+
+ if (data.indexOf('ToastCapable') > -1)
+ return;
+
+ result = data.replace(new RegExp(to_replace, 'g'), replace_with);
+
+ fs.writeFileSync(filename, result, 'utf8');
+}
+
+// Set ToastCapable for Windows Phone
+replace('platforms/windows/package.phone.appxmanifest', '<m3:VisualElements', '<m3:VisualElements ToastCapable="true"');
+// Set ToastCapable for Windows 8.1
+replace('platforms/windows/package.windows.appxmanifest', '<m2:VisualElements', '<m2:VisualElements ToastCapable="true"');
+// Set ToastCapable for Windows 8.0
+replace('platforms/windows/package.windows80.appxmanifest', '<VisualElements', '<VisualElements ToastCapable="true"');
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/ClearReceiver.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/ClearReceiver.java
new file mode 100644
index 00000000..e0892e37
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/ClearReceiver.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.localnotification;
+
+import de.appplant.cordova.plugin.notification.Notification;
+
+
+/**
+ * The clear intent receiver is triggered when the user clears a
+ * notification manually. It un-persists the cleared notification from the
+ * shared preferences.
+ */
+public class ClearReceiver extends de.appplant.cordova.plugin.notification.ClearReceiver {
+
+ /**
+ * Called when a local notification was cleared from outside of the app.
+ *
+ * @param notification
+ * Wrapper around the local notification
+ */
+ @Override
+ public void onClear (Notification notification) {
+ super.onClear(notification);
+ LocalNotification.fireEvent("clear", notification);
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/ClickActivity.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/ClickActivity.java
new file mode 100644
index 00000000..d366d355
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/ClickActivity.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.localnotification;
+
+import de.appplant.cordova.plugin.notification.Builder;
+import de.appplant.cordova.plugin.notification.Notification;
+import de.appplant.cordova.plugin.notification.TriggerReceiver;
+
+/**
+ * The receiver activity is triggered when a notification is clicked by a user.
+ * The activity calls the background callback and brings the launch intent
+ * up to foreground.
+ */
+public class ClickActivity extends de.appplant.cordova.plugin.notification.ClickActivity {
+
+ /**
+ * Called when local notification was clicked by the user.
+ *
+ * @param notification
+ * Wrapper around the local notification
+ */
+ @Override
+ public void onClick(Notification notification) {
+ LocalNotification.fireEvent("click", notification);
+
+ if (!notification.getOptions().isOngoing()) {
+ String event = notification.isRepeating() ? "clear" : "cancel";
+
+ LocalNotification.fireEvent(event, notification);
+ }
+
+ super.onClick(notification);
+ }
+
+ /**
+ * Build notification specified by options.
+ *
+ * @param builder
+ * Notification builder
+ */
+ @Override
+ public Notification buildNotification (Builder builder) {
+ return builder
+ .setTriggerReceiver(TriggerReceiver.class)
+ .build();
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/LocalNotification.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/LocalNotification.java
new file mode 100644
index 00000000..906c8d69
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/LocalNotification.java
@@ -0,0 +1,609 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.localnotification;
+
+import android.app.Activity;
+import android.os.Build;
+
+import org.apache.cordova.CallbackContext;
+import org.apache.cordova.CordovaInterface;
+import org.apache.cordova.CordovaPlugin;
+import org.apache.cordova.CordovaWebView;
+import org.apache.cordova.PluginResult;
+import org.json.JSONArray;
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+
+import de.appplant.cordova.plugin.notification.Manager;
+import de.appplant.cordova.plugin.notification.Notification;
+
+/**
+ * This plugin utilizes the Android AlarmManager in combination with local
+ * notifications. When a local notification is scheduled the alarm manager takes
+ * care of firing the event. When the event is processed, a notification is put
+ * in the Android notification center and status bar.
+ */
+public class LocalNotification extends CordovaPlugin {
+
+ // Reference to the web view for static access
+ private static CordovaWebView webView = null;
+
+ // Indicates if the device is ready (to receive events)
+ private static Boolean deviceready = false;
+
+ // To inform the user about the state of the app in callbacks
+ protected static Boolean isInBackground = true;
+
+ // Queues all events before deviceready
+ private static ArrayList<String> eventQueue = new ArrayList<String>();
+
+ /**
+ * Called after plugin construction and fields have been initialized.
+ * Prefer to use pluginInitialize instead since there is no value in
+ * having parameters on the initialize() function.
+ *
+ * pluginInitialize is not available for cordova 3.0-3.5 !
+ */
+ @Override
+ public void initialize (CordovaInterface cordova, CordovaWebView webView) {
+ LocalNotification.webView = super.webView;
+ }
+
+ /**
+ * Called when the system is about to start resuming a previous activity.
+ *
+ * @param multitasking
+ * Flag indicating if multitasking is turned on for app
+ */
+ @Override
+ public void onPause(boolean multitasking) {
+ super.onPause(multitasking);
+ isInBackground = true;
+ }
+
+ /**
+ * Called when the activity will start interacting with the user.
+ *
+ * @param multitasking
+ * Flag indicating if multitasking is turned on for app
+ */
+ @Override
+ public void onResume(boolean multitasking) {
+ super.onResume(multitasking);
+ isInBackground = false;
+ deviceready();
+ }
+
+ /**
+ * The final call you receive before your activity is destroyed.
+ */
+ @Override
+ public void onDestroy() {
+ deviceready = false;
+ isInBackground = true;
+ }
+
+ /**
+ * Executes the request.
+ *
+ * This method is called from the WebView thread. To do a non-trivial
+ * amount of work, use:
+ * cordova.getThreadPool().execute(runnable);
+ *
+ * To run on the UI thread, use:
+ * cordova.getActivity().runOnUiThread(runnable);
+ *
+ * @param action
+ * The action to execute.
+ * @param args
+ * The exec() arguments in JSON form.
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ * @return
+ * Whether the action was valid.
+ */
+ @Override
+ public boolean execute (final String action, final JSONArray args,
+ final CallbackContext command) throws JSONException {
+
+ Notification.setDefaultTriggerReceiver(TriggerReceiver.class);
+
+ cordova.getThreadPool().execute(new Runnable() {
+ public void run() {
+ if (action.equals("schedule")) {
+ schedule(args);
+ command.success();
+ }
+ else if (action.equals("update")) {
+ update(args);
+ command.success();
+ }
+ else if (action.equals("cancel")) {
+ cancel(args);
+ command.success();
+ }
+ else if (action.equals("cancelAll")) {
+ cancelAll();
+ command.success();
+ }
+ else if (action.equals("clear")) {
+ clear(args);
+ command.success();
+ }
+ else if (action.equals("clearAll")) {
+ clearAll();
+ command.success();
+ }
+ else if (action.equals("isPresent")) {
+ isPresent(args.optInt(0), command);
+ }
+ else if (action.equals("isScheduled")) {
+ isScheduled(args.optInt(0), command);
+ }
+ else if (action.equals("isTriggered")) {
+ isTriggered(args.optInt(0), command);
+ }
+ else if (action.equals("getAllIds")) {
+ getAllIds(command);
+ }
+ else if (action.equals("getScheduledIds")) {
+ getScheduledIds(command);
+ }
+ else if (action.equals("getTriggeredIds")) {
+ getTriggeredIds(command);
+ }
+ else if (action.equals("getSingle")) {
+ getSingle(args, command);
+ }
+ else if (action.equals("getSingleScheduled")) {
+ getSingleScheduled(args, command);
+ }
+ else if (action.equals("getSingleTriggered")) {
+ getSingleTriggered(args, command);
+ }
+ else if (action.equals("getAll")) {
+ getAll(args, command);
+ }
+ else if (action.equals("getScheduled")) {
+ getScheduled(args, command);
+ }
+ else if (action.equals("getTriggered")) {
+ getTriggered(args, command);
+ }
+ else if (action.equals("deviceready")) {
+ deviceready();
+ }
+ }
+ });
+
+ return true;
+ }
+
+ /**
+ * Schedule multiple local notifications.
+ *
+ * @param notifications
+ * Properties for each local notification
+ */
+ private void schedule (JSONArray notifications) {
+ for (int i = 0; i < notifications.length(); i++) {
+ JSONObject options = notifications.optJSONObject(i);
+
+ Notification notification =
+ getNotificationMgr().schedule(options, TriggerReceiver.class);
+
+ fireEvent("schedule", notification);
+ }
+ }
+
+ /**
+ * Update multiple local notifications.
+ *
+ * @param updates
+ * Notification properties including their IDs
+ */
+ private void update (JSONArray updates) {
+ for (int i = 0; i < updates.length(); i++) {
+ JSONObject update = updates.optJSONObject(i);
+ int id = update.optInt("id", 0);
+
+ Notification notification =
+ getNotificationMgr().update(id, update, TriggerReceiver.class);
+
+ fireEvent("update", notification);
+ }
+ }
+
+ /**
+ * Cancel multiple local notifications.
+ *
+ * @param ids
+ * Set of local notification IDs
+ */
+ private void cancel (JSONArray ids) {
+ for (int i = 0; i < ids.length(); i++) {
+ int id = ids.optInt(i, 0);
+
+ Notification notification =
+ getNotificationMgr().cancel(id);
+
+ if (notification != null) {
+ fireEvent("cancel", notification);
+ }
+ }
+ }
+
+ /**
+ * Cancel all scheduled notifications.
+ */
+ private void cancelAll() {
+ getNotificationMgr().cancelAll();
+ fireEvent("cancelall");
+ }
+
+ /**
+ * Clear multiple local notifications without canceling them.
+ *
+ * @param ids
+ * Set of local notification IDs
+ */
+ private void clear(JSONArray ids){
+ for (int i = 0; i < ids.length(); i++) {
+ int id = ids.optInt(i, 0);
+
+ Notification notification =
+ getNotificationMgr().clear(id);
+
+ if (notification != null) {
+ fireEvent("clear", notification);
+ }
+ }
+ }
+
+ /**
+ * Clear all triggered notifications without canceling them.
+ */
+ private void clearAll() {
+ getNotificationMgr().clearAll();
+ fireEvent("clearall");
+ }
+
+ /**
+ * If a notification with an ID is present.
+ *
+ * @param id
+ * Notification ID
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void isPresent (int id, CallbackContext command) {
+ boolean exist = getNotificationMgr().exist(id);
+
+ PluginResult result = new PluginResult(
+ PluginResult.Status.OK, exist);
+
+ command.sendPluginResult(result);
+ }
+
+ /**
+ * If a notification with an ID is scheduled.
+ *
+ * @param id
+ * Notification ID
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void isScheduled (int id, CallbackContext command) {
+ boolean exist = getNotificationMgr().exist(
+ id, Notification.Type.SCHEDULED);
+
+ PluginResult result = new PluginResult(
+ PluginResult.Status.OK, exist);
+
+ command.sendPluginResult(result);
+ }
+
+ /**
+ * If a notification with an ID is triggered.
+ *
+ * @param id
+ * Notification ID
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void isTriggered (int id, CallbackContext command) {
+ boolean exist = getNotificationMgr().exist(
+ id, Notification.Type.TRIGGERED);
+
+ PluginResult result = new PluginResult(
+ PluginResult.Status.OK, exist);
+
+ command.sendPluginResult(result);
+ }
+
+ /**
+ * Set of IDs from all existent notifications.
+ *
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void getAllIds (CallbackContext command) {
+ List<Integer> ids = getNotificationMgr().getIds();
+
+ command.success(new JSONArray(ids));
+ }
+
+ /**
+ * Set of IDs from all scheduled notifications.
+ *
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void getScheduledIds (CallbackContext command) {
+ List<Integer> ids = getNotificationMgr().getIdsByType(
+ Notification.Type.SCHEDULED);
+
+ command.success(new JSONArray(ids));
+ }
+
+ /**
+ * Set of IDs from all triggered notifications.
+ *
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void getTriggeredIds (CallbackContext command) {
+ List<Integer> ids = getNotificationMgr().getIdsByType(
+ Notification.Type.TRIGGERED);
+
+ command.success(new JSONArray(ids));
+ }
+
+ /**
+ * Options from local notification.
+ *
+ * @param ids
+ * Set of local notification IDs
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void getSingle (JSONArray ids, CallbackContext command) {
+ getOptions(ids.optString(0), Notification.Type.ALL, command);
+ }
+
+ /**
+ * Options from scheduled notification.
+ *
+ * @param ids
+ * Set of local notification IDs
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void getSingleScheduled (JSONArray ids, CallbackContext command) {
+ getOptions(ids.optString(0), Notification.Type.SCHEDULED, command);
+ }
+
+ /**
+ * Options from triggered notification.
+ *
+ * @param ids
+ * Set of local notification IDs
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void getSingleTriggered (JSONArray ids, CallbackContext command) {
+ getOptions(ids.optString(0), Notification.Type.TRIGGERED, command);
+ }
+
+ /**
+ * Set of options from local notification.
+ *
+ * @param ids
+ * Set of local notification IDs
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void getAll (JSONArray ids, CallbackContext command) {
+ getOptions(ids, Notification.Type.ALL, command);
+ }
+
+ /**
+ * Set of options from scheduled notifications.
+ *
+ * @param ids
+ * Set of local notification IDs
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void getScheduled (JSONArray ids, CallbackContext command) {
+ getOptions(ids, Notification.Type.SCHEDULED, command);
+ }
+
+ /**
+ * Set of options from triggered notifications.
+ *
+ * @param ids
+ * Set of local notification IDs
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void getTriggered (JSONArray ids, CallbackContext command) {
+ getOptions(ids, Notification.Type.TRIGGERED, command);
+ }
+
+ /**
+ * Options from local notification.
+ *
+ * @param id
+ * Set of local notification IDs
+ * @param type
+ * The local notification life cycle type
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void getOptions (String id, Notification.Type type,
+ CallbackContext command) {
+
+ JSONArray ids = new JSONArray().put(id);
+
+ JSONObject options =
+ getNotificationMgr().getOptionsBy(type, toList(ids)).get(0);
+
+ command.success(options);
+ }
+
+ /**
+ * Set of options from local notifications.
+ *
+ * @param ids
+ * Set of local notification IDs
+ * @param type
+ * The local notification life cycle type
+ * @param command
+ * The callback context used when calling back into JavaScript.
+ */
+ private void getOptions (JSONArray ids, Notification.Type type,
+ CallbackContext command) {
+
+ List<JSONObject> options;
+
+ if (ids.length() == 0) {
+ options = getNotificationMgr().getOptionsByType(type);
+ } else {
+ options = getNotificationMgr().getOptionsBy(type, toList(ids));
+ }
+
+ command.success(new JSONArray(options));
+ }
+
+ /**
+ * Call all pending callbacks after the deviceready event has been fired.
+ */
+ private static synchronized void deviceready () {
+ isInBackground = false;
+ deviceready = true;
+
+ for (String js : eventQueue) {
+ sendJavascript(js);
+ }
+
+ eventQueue.clear();
+ }
+
+ /**
+ * Fire given event on JS side. Does inform all event listeners.
+ *
+ * @param event
+ * The event name
+ */
+ private void fireEvent (String event) {
+ fireEvent(event, null);
+ }
+
+ /**
+ * Fire given event on JS side. Does inform all event listeners.
+ *
+ * @param event
+ * The event name
+ * @param notification
+ * Optional local notification to pass the id and properties.
+ */
+ static void fireEvent (String event, Notification notification) {
+ String state = getApplicationState();
+ String params = "\"" + state + "\"";
+
+ if (notification != null) {
+ params = notification.toString() + "," + params;
+ }
+
+ String js = "cordova.plugins.notification.local.core.fireEvent(" +
+ "\"" + event + "\"," + params + ")";
+
+ sendJavascript(js);
+ }
+
+ /**
+ * Use this instead of deprecated sendJavascript
+ *
+ * @param js
+ * JS code snippet as string
+ */
+ private static synchronized void sendJavascript(final String js) {
+
+ if (!deviceready) {
+ eventQueue.add(js);
+ return;
+ }
+ Runnable jsLoader = new Runnable() {
+ public void run() {
+ webView.loadUrl("javascript:" + js);
+ }
+ };
+ try {
+ Method post = webView.getClass().getMethod("post",Runnable.class);
+ post.invoke(webView,jsLoader);
+ } catch(Exception e) {
+
+ ((Activity)(webView.getContext())).runOnUiThread(jsLoader);
+ }
+ }
+
+ /**
+ * Convert JSON array of integers to List.
+ *
+ * @param ary
+ * Array of integers
+ */
+ private List<Integer> toList (JSONArray ary) {
+ ArrayList<Integer> list = new ArrayList<Integer>();
+
+ for (int i = 0; i < ary.length(); i++) {
+ list.add(ary.optInt(i));
+ }
+
+ return list;
+ }
+
+ /**
+ * Current application state.
+ *
+ * @return
+ * "background" or "foreground"
+ */
+ static String getApplicationState () {
+ return isInBackground ? "background" : "foreground";
+ }
+
+ /**
+ * Notification manager instance.
+ */
+ private Manager getNotificationMgr() {
+ return Manager.getInstance(cordova.getActivity());
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/RestoreReceiver.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/RestoreReceiver.java
new file mode 100644
index 00000000..7de4e328
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/RestoreReceiver.java
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2014-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.localnotification;
+
+import de.appplant.cordova.plugin.notification.AbstractRestoreReceiver;
+import de.appplant.cordova.plugin.notification.Builder;
+import de.appplant.cordova.plugin.notification.Notification;
+
+/**
+ * This class is triggered upon reboot of the device. It needs to re-register
+ * the alarms with the AlarmManager since these alarms are lost in case of
+ * reboot.
+ */
+public class RestoreReceiver extends AbstractRestoreReceiver {
+
+ /**
+ * Called when a local notification need to be restored.
+ *
+ * @param notification
+ * Wrapper around the local notification
+ */
+ @Override
+ public void onRestore (Notification notification) {
+ if (notification.isScheduled()) {
+ notification.schedule();
+ }
+ }
+
+ /**
+ * Build notification specified by options.
+ *
+ * @param builder
+ * Notification builder
+ */
+ @Override
+ public Notification buildNotification (Builder builder) {
+ return builder
+ .setTriggerReceiver(TriggerReceiver.class)
+ .setClearReceiver(ClearReceiver.class)
+ .setClickActivity(ClickActivity.class)
+ .build();
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/TriggerReceiver.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/TriggerReceiver.java
new file mode 100644
index 00000000..3c423c01
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/TriggerReceiver.java
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.localnotification;
+
+import de.appplant.cordova.plugin.notification.Builder;
+import de.appplant.cordova.plugin.notification.Notification;
+
+/**
+ * The alarm receiver is triggered when a scheduled alarm is fired. This class
+ * reads the information in the intent and displays this information in the
+ * Android notification bar. The notification uses the default notification
+ * sound and it vibrates the phone.
+ */
+public class TriggerReceiver extends de.appplant.cordova.plugin.notification.TriggerReceiver {
+
+ /**
+ * Called when a local notification was triggered. Does present the local
+ * notification, re-schedule the alarm if necessary and fire trigger event.
+ *
+ * @param notification
+ * Wrapper around the local notification
+ * @param updated
+ * If an update has triggered or the original
+ */
+ @Override
+ public void onTrigger (Notification notification, boolean updated) {
+ super.onTrigger(notification, updated);
+
+ if (!updated) {
+ LocalNotification.fireEvent("trigger", notification);
+ }
+ }
+
+ /**
+ * Build notification specified by options.
+ *
+ * @param builder
+ * Notification builder
+ */
+ @Override
+ public Notification buildNotification (Builder builder) {
+ return builder
+ .setTriggerReceiver(TriggerReceiver.class)
+ .setClickActivity(ClickActivity.class)
+ .setClearReceiver(ClearReceiver.class)
+ .build();
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractClearReceiver.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractClearReceiver.java
new file mode 100644
index 00000000..94d2a19b
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractClearReceiver.java
@@ -0,0 +1,75 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.notification;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Abstract delete receiver for local notifications. Creates the local
+ * notification and calls the event functions for further proceeding.
+ */
+abstract public class AbstractClearReceiver extends BroadcastReceiver {
+
+ /**
+ * Called when the notification was cleared from the notification center.
+ *
+ * @param context
+ * Application context
+ * @param intent
+ * Received intent with content data
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Bundle bundle = intent.getExtras();
+ JSONObject options;
+
+ try {
+ String data = bundle.getString(Options.EXTRA);
+ options = new JSONObject(data);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ return;
+ }
+
+ Notification notification =
+ new Builder(context, options).build();
+
+ onClear(notification);
+ }
+
+ /**
+ * Called when a local notification was cleared from outside of the app.
+ *
+ * @param notification
+ * Wrapper around the local notification
+ */
+ abstract public void onClear (Notification notification);
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractClickActivity.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractClickActivity.java
new file mode 100644
index 00000000..a02a9981
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractClickActivity.java
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.notification;
+
+import android.app.Activity;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+/**
+ * Abstract content receiver activity for local notifications. Creates the
+ * local notification and calls the event functions for further proceeding.
+ */
+abstract public class AbstractClickActivity extends Activity {
+
+ /**
+ * Called when local notification was clicked to launch the main intent.
+ *
+ * @param state
+ * Saved instance state
+ */
+ @Override
+ public void onCreate (Bundle state) {
+ super.onCreate(state);
+
+ Intent intent = getIntent();
+ Bundle bundle = intent.getExtras();
+ Context context = getApplicationContext();
+
+ try {
+ String data = bundle.getString(Options.EXTRA);
+ JSONObject options = new JSONObject(data);
+
+ Builder builder =
+ new Builder(context, options);
+
+ Notification notification =
+ buildNotification(builder);
+
+ onClick(notification);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Called when local notification was clicked by the user.
+ *
+ * @param notification
+ * Wrapper around the local notification
+ */
+ abstract public void onClick (Notification notification);
+
+ /**
+ * Build notification specified by options.
+ *
+ * @param builder
+ * Notification builder
+ */
+ abstract public Notification buildNotification (Builder builder);
+
+ /**
+ * Launch main intent from package.
+ */
+ public void launchApp() {
+ Context context = getApplicationContext();
+ String pkgName = context.getPackageName();
+
+ Intent intent = context
+ .getPackageManager()
+ .getLaunchIntentForPackage(pkgName);
+
+ intent.addFlags(
+ Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
+
+ context.startActivity(intent);
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractRestoreReceiver.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractRestoreReceiver.java
new file mode 100644
index 00000000..8a1f3656
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractRestoreReceiver.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2014-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.notification;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+
+import org.json.JSONObject;
+
+import java.util.List;
+
+/**
+ * This class is triggered upon reboot of the device. It needs to re-register
+ * the alarms with the AlarmManager since these alarms are lost in case of
+ * reboot.
+ */
+abstract public class AbstractRestoreReceiver extends BroadcastReceiver {
+
+ /**
+ * Called on device reboot.
+ *
+ * @param context
+ * Application context
+ * @param intent
+ * Received intent with content data
+ */
+ @Override
+ public void onReceive (Context context, Intent intent) {
+ Manager notificationMgr =
+ Manager.getInstance(context);
+
+ List<JSONObject> options =
+ notificationMgr.getOptions();
+
+ for (JSONObject data : options) {
+ Builder builder = new Builder(context, data);
+
+ Notification notification =
+ buildNotification(builder);
+
+ onRestore(notification);
+ }
+ }
+
+ /**
+ * Called when a local notification need to be restored.
+ *
+ * @param notification
+ * Wrapper around the local notification
+ */
+ abstract public void onRestore (Notification notification);
+
+ /**
+ * Build notification specified by options.
+ *
+ * @param builder
+ * Notification builder
+ */
+ abstract public Notification buildNotification (Builder builder);
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractTriggerReceiver.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractTriggerReceiver.java
new file mode 100644
index 00000000..fc6759c5
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AbstractTriggerReceiver.java
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.notification;
+
+import android.content.BroadcastReceiver;
+import android.content.Context;
+import android.content.Intent;
+import android.os.Bundle;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Calendar;
+
+/**
+ * Abstract broadcast receiver for local notifications. Creates the
+ * notification options and calls the event functions for further proceeding.
+ */
+abstract public class AbstractTriggerReceiver extends BroadcastReceiver {
+
+ /**
+ * Called when an alarm was triggered.
+ *
+ * @param context
+ * Application context
+ * @param intent
+ * Received intent with content data
+ */
+ @Override
+ public void onReceive(Context context, Intent intent) {
+ Bundle bundle = intent.getExtras();
+ Options options;
+
+ try {
+ String data = bundle.getString(Options.EXTRA);
+ JSONObject dict = new JSONObject(data);
+
+ options = new Options(context).parse(dict);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ return;
+ }
+
+ if (options == null)
+ return;
+
+ if (isFirstAlarmInFuture(options))
+ return;
+
+ Builder builder = new Builder(options);
+ Notification notification = buildNotification(builder);
+ boolean updated = notification.isUpdate();
+
+ onTrigger(notification, updated);
+ }
+
+ /**
+ * Called when a local notification was triggered.
+ *
+ * @param notification
+ * Wrapper around the local notification
+ * @param updated
+ * If an update has triggered or the original
+ */
+ abstract public void onTrigger (Notification notification, boolean updated);
+
+ /**
+ * Build notification specified by options.
+ *
+ * @param builder
+ * Notification builder
+ */
+ abstract public Notification buildNotification (Builder builder);
+
+ /*
+ * If you set a repeating alarm at 11:00 in the morning and it
+ * should trigger every morning at 08:00 o'clock, it will
+ * immediately fire. E.g. Android tries to make up for the
+ * 'forgotten' reminder for that day. Therefore we ignore the event
+ * if Android tries to 'catch up'.
+ */
+ private Boolean isFirstAlarmInFuture (Options options) {
+ Notification notification = new Builder(options).build();
+
+ if (!notification.isRepeating())
+ return false;
+
+ Calendar now = Calendar.getInstance();
+ Calendar alarm = Calendar.getInstance();
+
+ alarm.setTime(notification.getOptions().getTriggerDate());
+
+ int alarmHour = alarm.get(Calendar.HOUR_OF_DAY);
+ int alarmMin = alarm.get(Calendar.MINUTE);
+ int currentHour = now.get(Calendar.HOUR_OF_DAY);
+ int currentMin = now.get(Calendar.MINUTE);
+
+ return (currentHour != alarmHour && currentMin != alarmMin);
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AssetUtil.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AssetUtil.java
new file mode 100644
index 00000000..2da8a2c3
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/AssetUtil.java
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.notification;
+
+import android.content.Context;
+import android.content.res.AssetManager;
+import android.content.res.Resources;
+import android.graphics.Bitmap;
+import android.graphics.BitmapFactory;
+import android.media.RingtoneManager;
+import android.net.Uri;
+import android.os.StrictMode;
+import android.util.Log;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.net.HttpURLConnection;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Util class to map unified asset URIs to native URIs. URIs like file:///
+ * map to absolute paths while file:// point relatively to the www folder
+ * within the asset resources. And res:// means a resource from the native
+ * res folder. Remote assets are accessible via http:// for example.
+ */
+class AssetUtil {
+
+ // Name of the storage folder
+ private static final String STORAGE_FOLDER = "/localnotification";
+
+ // Placeholder URI for default sound
+ private static final String DEFAULT_SOUND = "res://platform_default";
+
+ // Ref to the context passed through the constructor to access the
+ // resources and app directory.
+ private final Context context;
+
+ /**
+ * Constructor
+ *
+ * @param context
+ * Application context
+ */
+ private AssetUtil(Context context) {
+ this.context = context;
+ }
+
+ /**
+ * Static method to retrieve class instance.
+ *
+ * @param context
+ * Application context
+ */
+ static AssetUtil getInstance(Context context) {
+ return new AssetUtil(context);
+ }
+
+ /**
+ * Parse path path to native URI.
+ *
+ * @param path
+ * Path to path file
+ */
+ Uri parseSound (String path) {
+
+ if (path == null || path.isEmpty())
+ return Uri.EMPTY;
+
+ if (path.equalsIgnoreCase(DEFAULT_SOUND)) {
+ return RingtoneManager.getDefaultUri(RingtoneManager
+ .TYPE_NOTIFICATION);
+ }
+
+ return parse(path);
+ }
+
+ /**
+ * The URI for a path.
+ *
+ * @param path
+ * The given path
+ */
+ Uri parse (String path) {
+
+ if (path.startsWith("res:")) {
+ return getUriForResourcePath(path);
+ } else if (path.startsWith("file:///")) {
+ return getUriFromPath(path);
+ } else if (path.startsWith("file://")) {
+ return getUriFromAsset(path);
+ } else if (path.startsWith("http")){
+ return getUriFromRemote(path);
+ }
+
+ return Uri.EMPTY;
+ }
+
+ /**
+ * URI for a file.
+ *
+ * @param path
+ * Absolute path like file:///...
+ *
+ * @return
+ * URI pointing to the given path
+ */
+ private Uri getUriFromPath(String path) {
+ String absPath = path.replaceFirst("file://", "");
+ File file = new File(absPath);
+
+ if (!file.exists()) {
+ Log.e("Asset", "File not found: " + file.getAbsolutePath());
+ return Uri.EMPTY;
+ }
+
+ return Uri.fromFile(file);
+ }
+
+ /**
+ * URI for an asset.
+ *
+ * @param path
+ * Asset path like file://...
+ *
+ * @return
+ * URI pointing to the given path
+ */
+ private Uri getUriFromAsset(String path) {
+ File dir = context.getExternalCacheDir();
+
+ if (dir == null) {
+ Log.e("Asset", "Missing external cache dir");
+ return Uri.EMPTY;
+ }
+
+ String resPath = path.replaceFirst("file:/", "www");
+ String fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
+ String storage = dir.toString() + STORAGE_FOLDER;
+ File file = new File(storage, fileName);
+
+ //noinspection ResultOfMethodCallIgnored
+ new File(storage).mkdir();
+
+ try {
+ AssetManager assets = context.getAssets();
+ FileOutputStream outStream = new FileOutputStream(file);
+ InputStream inputStream = assets.open(resPath);
+
+ copyFile(inputStream, outStream);
+
+ outStream.flush();
+ outStream.close();
+
+ return Uri.fromFile(file);
+
+ } catch (Exception e) {
+ Log.e("Asset", "File not found: assets/" + resPath);
+ e.printStackTrace();
+ }
+
+ return Uri.EMPTY;
+ }
+
+ /**
+ * The URI for a resource.
+ *
+ * @param path
+ * The given relative path
+ *
+ * @return
+ * URI pointing to the given path
+ */
+ private Uri getUriForResourcePath(String path) {
+ File dir = context.getExternalCacheDir();
+
+ if (dir == null) {
+ Log.e("Asset", "Missing external cache dir");
+ return Uri.EMPTY;
+ }
+
+ String resPath = path.replaceFirst("res://", "");
+
+ int resId = getResIdForDrawable(resPath);
+
+ if (resId == 0) {
+ Log.e("Asset", "File not found: " + resPath);
+ return Uri.EMPTY;
+ }
+
+ String resName = extractResourceName(resPath);
+ String extName = extractResourceExtension(resPath);
+ String storage = dir.toString() + STORAGE_FOLDER;
+ File file = new File(storage, resName + extName);
+
+ //noinspection ResultOfMethodCallIgnored
+ new File(storage).mkdir();
+
+ try {
+ Resources res = context.getResources();
+ FileOutputStream outStream = new FileOutputStream(file);
+ InputStream inputStream = res.openRawResource(resId);
+ copyFile(inputStream, outStream);
+
+ outStream.flush();
+ outStream.close();
+
+ return Uri.fromFile(file);
+
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+
+ return Uri.EMPTY;
+ }
+
+ /**
+ * Uri from remote located content.
+ *
+ * @param path
+ * Remote address
+ *
+ * @return
+ * Uri of the downloaded file
+ */
+ private Uri getUriFromRemote(String path) {
+ File dir = context.getExternalCacheDir();
+
+ if (dir == null) {
+ Log.e("Asset", "Missing external cache dir");
+ return Uri.EMPTY;
+ }
+
+ String resName = extractResourceName(path);
+ String extName = extractResourceExtension(path);
+ String storage = dir.toString() + STORAGE_FOLDER;
+ File file = new File(storage, resName + extName);
+
+ //noinspection ResultOfMethodCallIgnored
+ new File(storage).mkdir();
+
+ try {
+ URL url = new URL(path);
+ HttpURLConnection connection = (HttpURLConnection) url.openConnection();
+
+ StrictMode.ThreadPolicy policy =
+ new StrictMode.ThreadPolicy.Builder().permitAll().build();
+
+ StrictMode.setThreadPolicy(policy);
+
+ connection.setRequestProperty("Connection", "close");
+ connection.setConnectTimeout(5000);
+ connection.connect();
+
+ InputStream input = connection.getInputStream();
+ FileOutputStream outStream = new FileOutputStream(file);
+
+ copyFile(input, outStream);
+
+ outStream.flush();
+ outStream.close();
+
+ return Uri.fromFile(file);
+
+ } catch (MalformedURLException e) {
+ Log.e("Asset", "Incorrect URL");
+ e.printStackTrace();
+ } catch (FileNotFoundException e) {
+ Log.e("Asset", "Failed to create new File from HTTP Content");
+ e.printStackTrace();
+ } catch (IOException e) {
+ Log.e("Asset", "No Input can be created from http Stream");
+ e.printStackTrace();
+ }
+
+ return Uri.EMPTY;
+ }
+
+ /**
+ * Copy content from input stream into output stream.
+ *
+ * @param in
+ * The input stream
+ * @param out
+ * The output stream
+ */
+ private void copyFile(InputStream in, OutputStream out) throws IOException {
+ byte[] buffer = new byte[1024];
+ int read;
+
+ while ((read = in.read(buffer)) != -1) {
+ out.write(buffer, 0, read);
+ }
+ }
+
+ /**
+ * Resource ID for drawable.
+ *
+ * @param resPath
+ * Resource path as string
+ */
+ int getResIdForDrawable(String resPath) {
+ int resId = getResIdForDrawable(getPkgName(), resPath);
+
+ if (resId == 0) {
+ resId = getResIdForDrawable("android", resPath);
+ }
+
+ return resId;
+ }
+
+ /**
+ * Resource ID for drawable.
+ *
+ * @param clsName
+ * Relative package or global android name space
+ * @param resPath
+ * Resource path as string
+ */
+ int getResIdForDrawable(String clsName, String resPath) {
+ String drawable = extractResourceName(resPath);
+ int resId = 0;
+
+ try {
+ Class<?> cls = Class.forName(clsName + ".R$drawable");
+
+ resId = (Integer) cls.getDeclaredField(drawable).get(Integer.class);
+ } catch (Exception ignore) {}
+
+ return resId;
+ }
+
+ /**
+ * Convert drawable resource to bitmap.
+ *
+ * @param drawable
+ * Drawable resource name
+ */
+ Bitmap getIconFromDrawable (String drawable) {
+ Resources res = context.getResources();
+ int iconId;
+
+ iconId = getResIdForDrawable(getPkgName(), drawable);
+
+ if (iconId == 0) {
+ iconId = getResIdForDrawable("android", drawable);
+ }
+
+ if (iconId == 0) {
+ iconId = android.R.drawable.ic_menu_info_details;
+ }
+
+ return BitmapFactory.decodeResource(res, iconId);
+ }
+
+ /**
+ * Convert URI to Bitmap.
+ *
+ * @param uri
+ * Internal image URI
+ */
+ Bitmap getIconFromUri (Uri uri) throws IOException {
+ InputStream input = context.getContentResolver().openInputStream(uri);
+
+ return BitmapFactory.decodeStream(input);
+ }
+
+ /**
+ * Extract name of drawable resource from path.
+ *
+ * @param resPath
+ * Resource path as string
+ */
+ private String extractResourceName (String resPath) {
+ String drawable = resPath;
+
+ if (drawable.contains("/")) {
+ drawable = drawable.substring(drawable.lastIndexOf('/') + 1);
+ }
+
+ if (resPath.contains(".")) {
+ drawable = drawable.substring(0, drawable.lastIndexOf('.'));
+ }
+
+ return drawable;
+ }
+
+ /**
+ * Extract extension of drawable resource from path.
+ *
+ * @param resPath
+ * Resource path as string
+ */
+ private String extractResourceExtension (String resPath) {
+ String extName = "png";
+
+ if (resPath.contains(".")) {
+ extName = resPath.substring(resPath.lastIndexOf('.'));
+ }
+
+ return extName;
+ }
+
+ /**
+ * Package name specified by context.
+ */
+ private String getPkgName () {
+ return context.getPackageName();
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Builder.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Builder.java
new file mode 100644
index 00000000..a0be8b93
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Builder.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.notification;
+
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.net.Uri;
+import android.support.v4.app.NotificationCompat;
+
+import org.json.JSONObject;
+
+import java.util.Random;
+
+/**
+ * Builder class for local notifications. Build fully configured local
+ * notification specified by JSON object passed from JS side.
+ */
+public class Builder {
+
+ // Application context passed by constructor
+ private final Context context;
+
+ // Notification options passed by JS
+ private final Options options;
+
+ // Receiver to handle the trigger event
+ private Class<?> triggerReceiver;
+
+ // Receiver to handle the clear event
+ private Class<?> clearReceiver = ClearReceiver.class;
+
+ // Activity to handle the click event
+ private Class<?> clickActivity = ClickActivity.class;
+
+ /**
+ * Constructor
+ *
+ * @param context
+ * Application context
+ * @param options
+ * Notification options
+ */
+ public Builder(Context context, JSONObject options) {
+ this.context = context;
+ this.options = new Options(context).parse(options);
+ }
+
+ /**
+ * Constructor
+ *
+ * @param options
+ * Notification options
+ */
+ public Builder(Options options) {
+ this.context = options.getContext();
+ this.options = options;
+ }
+
+ /**
+ * Set trigger receiver.
+ *
+ * @param receiver
+ * Broadcast receiver
+ */
+ public Builder setTriggerReceiver(Class<?> receiver) {
+ this.triggerReceiver = receiver;
+ return this;
+ }
+
+ /**
+ * Set clear receiver.
+ *
+ * @param receiver
+ * Broadcast receiver
+ */
+ public Builder setClearReceiver(Class<?> receiver) {
+ this.clearReceiver = receiver;
+ return this;
+ }
+
+ /**
+ * Set click activity.
+ *
+ * @param activity
+ * Activity
+ */
+ public Builder setClickActivity(Class<?> activity) {
+ this.clickActivity = activity;
+ return this;
+ }
+
+ /**
+ * Creates the notification with all its options passed through JS.
+ */
+ public Notification build() {
+ Uri sound = options.getSoundUri();
+ NotificationCompat.BigTextStyle style;
+ NotificationCompat.Builder builder;
+
+ style = new NotificationCompat.BigTextStyle()
+ .bigText(options.getText());
+
+ builder = new NotificationCompat.Builder(context)
+ .setDefaults(0)
+ .setContentTitle(options.getTitle())
+ .setContentText(options.getText())
+ .setNumber(options.getBadgeNumber())
+ .setTicker(options.getText())
+ .setSmallIcon(options.getSmallIcon())
+ .setLargeIcon(options.getIconBitmap())
+ .setAutoCancel(options.isAutoClear())
+ .setOngoing(options.isOngoing())
+ .setStyle(style)
+ .setLights(options.getLedColor(), 500, 500);
+
+ if (sound != null) {
+ builder.setSound(sound);
+ }
+
+ applyDeleteReceiver(builder);
+ applyContentReceiver(builder);
+
+ return new Notification(context, options, builder, triggerReceiver);
+ }
+
+ /**
+ * Set intent to handle the delete event. Will clean up some persisted
+ * preferences.
+ *
+ * @param builder
+ * Local notification builder instance
+ */
+ private void applyDeleteReceiver(NotificationCompat.Builder builder) {
+
+ if (clearReceiver == null)
+ return;
+
+ Intent deleteIntent = new Intent(context, clearReceiver)
+ .setAction(options.getIdStr())
+ .putExtra(Options.EXTRA, options.toString());
+
+ PendingIntent dpi = PendingIntent.getBroadcast(
+ context, 0, deleteIntent, PendingIntent.FLAG_CANCEL_CURRENT);
+
+ builder.setDeleteIntent(dpi);
+ }
+
+ /**
+ * Set intent to handle the click event. Will bring the app to
+ * foreground.
+ *
+ * @param builder
+ * Local notification builder instance
+ */
+ private void applyContentReceiver(NotificationCompat.Builder builder) {
+
+ if (clickActivity == null)
+ return;
+
+ Intent intent = new Intent(context, clickActivity)
+ .putExtra(Options.EXTRA, options.toString())
+ .setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
+
+ int requestCode = new Random().nextInt();
+
+ PendingIntent contentIntent = PendingIntent.getActivity(
+ context, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+
+ builder.setContentIntent(contentIntent);
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/ClearReceiver.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/ClearReceiver.java
new file mode 100644
index 00000000..761b6c5c
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/ClearReceiver.java
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.notification;
+
+/**
+ * The clear intent receiver is triggered when the user clears a
+ * notification manually. It un-persists the cleared notification from the
+ * shared preferences.
+ */
+public class ClearReceiver extends AbstractClearReceiver {
+
+ /**
+ * Called when a local notification was cleared from outside of the app.
+ *
+ * @param notification
+ * Wrapper around the local notification
+ */
+ @Override
+ public void onClear (Notification notification) {
+ notification.clear();
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/ClickActivity.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/ClickActivity.java
new file mode 100644
index 00000000..01af5c45
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/ClickActivity.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.notification;
+
+/**
+ * The receiver activity is triggered when a notification is clicked by a user.
+ * The activity calls the background callback and brings the launch intent
+ * up to foreground.
+ */
+public class ClickActivity extends AbstractClickActivity {
+
+ /**
+ * Called when local notification was clicked by the user. Will
+ * move the app to foreground.
+ *
+ * @param notification
+ * Wrapper around the local notification
+ */
+ @Override
+ public void onClick(Notification notification) {
+ launchApp();
+ }
+
+ /**
+ * Build notification specified by options.
+ *
+ * @param builder
+ * Notification builder
+ */
+ public Notification buildNotification (Builder builder) {
+ return builder.build();
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Manager.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Manager.java
new file mode 100644
index 00000000..03ea384f
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Manager.java
@@ -0,0 +1,455 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.notification;
+
+import android.app.NotificationManager;
+import android.content.Context;
+import android.content.SharedPreferences;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+import static de.appplant.cordova.plugin.notification.Notification.PREF_KEY;
+
+/**
+ * Central way to access all or single local notifications set by specific
+ * state like triggered or scheduled. Offers shortcut ways to schedule,
+ * cancel or clear local notifications.
+ */
+public class Manager {
+
+ // Context passed through constructor and used for notification builder.
+ private Context context;
+
+ /**
+ * Constructor
+ *
+ * @param context
+ * Application context
+ */
+ private Manager(Context context){
+ this.context = context;
+ }
+
+ /**
+ * Static method to retrieve class instance.
+ *
+ * @param context
+ * Application context
+ */
+ public static Manager getInstance(Context context) {
+ return new Manager(context);
+ }
+
+ /**
+ * Schedule local notification specified by JSON object.
+ *
+ * @param options
+ * JSON object with set of options
+ * @param receiver
+ * Receiver to handle the trigger event
+ */
+ public Notification schedule (JSONObject options, Class<?> receiver) {
+ return schedule(new Options(context).parse(options), receiver);
+ }
+
+ /**
+ * Schedule local notification specified by options object.
+ *
+ * @param options
+ * Set of notification options
+ * @param receiver
+ * Receiver to handle the trigger event
+ */
+ public Notification schedule (Options options, Class<?> receiver) {
+ Notification notification = new Builder(options)
+ .setTriggerReceiver(receiver)
+ .build();
+
+ notification.schedule();
+
+ return notification;
+ }
+
+ /**
+ * Clear local notification specified by ID.
+ *
+ * @param id
+ * The notification ID
+ * @param updates
+ * JSON object with notification options
+ * @param receiver
+ * Receiver to handle the trigger event
+ */
+ public Notification update (int id, JSONObject updates, Class<?> receiver) {
+ Notification notification = get(id);
+
+ if (notification == null)
+ return null;
+
+ notification.cancel();
+
+ JSONObject options = mergeJSONObjects(
+ notification.getOptions().getDict(), updates);
+
+ try {
+ options.putOpt("updatedAt", new Date().getTime());
+ } catch (JSONException ignore) {}
+
+ return schedule(options, receiver);
+ }
+
+ /**
+ * Clear local notification specified by ID.
+ *
+ * @param id
+ * The notification ID
+ */
+ public Notification clear (int id) {
+ Notification notification = get(id);
+
+ if (notification != null) {
+ notification.clear();
+ }
+
+ return notification;
+ }
+
+ /**
+ * Clear local notification specified by ID.
+ *
+ * @param id
+ * The notification ID
+ */
+ public Notification cancel (int id) {
+ Notification notification = get(id);
+
+ if (notification != null) {
+ notification.cancel();
+ }
+
+ return notification;
+ }
+
+ /**
+ * Clear all local notifications.
+ */
+ public void clearAll () {
+ List<Notification> notifications = getAll();
+
+ for (Notification notification : notifications) {
+ notification.clear();
+ }
+
+ getNotMgr().cancelAll();
+ }
+
+ /**
+ * Cancel all local notifications.
+ */
+ public void cancelAll () {
+ List<Notification> notifications = getAll();
+
+ for (Notification notification : notifications) {
+ notification.cancel();
+ }
+
+ getNotMgr().cancelAll();
+ }
+
+ /**
+ * All local notifications IDs.
+ */
+ public List<Integer> getIds() {
+ Set<String> keys = getPrefs().getAll().keySet();
+ ArrayList<Integer> ids = new ArrayList<Integer>();
+
+ for (String key : keys) {
+ ids.add(Integer.parseInt(key));
+ }
+
+ return ids;
+ }
+
+ /**
+ * All local notification IDs for given type.
+ *
+ * @param type
+ * The notification life cycle type
+ */
+ public List<Integer> getIdsByType(Notification.Type type) {
+ List<Notification> notifications = getAll();
+ ArrayList<Integer> ids = new ArrayList<Integer>();
+
+ for (Notification notification : notifications) {
+ if (notification.getType() == type) {
+ ids.add(notification.getId());
+ }
+ }
+
+ return ids;
+ }
+
+ /**
+ * List of local notifications with matching ID.
+ *
+ * @param ids
+ * Set of notification IDs
+ */
+ public List<Notification> getByIds(List<Integer> ids) {
+ ArrayList<Notification> notifications = new ArrayList<Notification>();
+
+ for (int id : ids) {
+ Notification notification = get(id);
+
+ if (notification != null) {
+ notifications.add(notification);
+ }
+ }
+
+ return notifications;
+ }
+
+ /**
+ * List of all local notification.
+ */
+ public List<Notification> getAll() {
+ return getByIds(getIds());
+ }
+
+ /**
+ * List of local notifications from given type.
+ *
+ * @param type
+ * The notification life cycle type
+ */
+ public List<Notification> getByType(Notification.Type type) {
+ List<Notification> notifications = getAll();
+ ArrayList<Notification> list = new ArrayList<Notification>();
+
+ if (type == Notification.Type.ALL)
+ return notifications;
+
+ for (Notification notification : notifications) {
+ if (notification.getType() == type) {
+ list.add(notification);
+ }
+ }
+
+ return list;
+ }
+
+ /**
+ * List of local notifications with matching ID from given type.
+ *
+ * @param type
+ * The notification life cycle type
+ * @param ids
+ * Set of notification IDs
+ */
+ @SuppressWarnings("UnusedDeclaration")
+ public List<Notification> getBy(Notification.Type type, List<Integer> ids) {
+ ArrayList<Notification> notifications = new ArrayList<Notification>();
+
+ for (int id : ids) {
+ Notification notification = get(id);
+
+ if (notification != null && notification.isScheduled()) {
+ notifications.add(notification);
+ }
+ }
+
+ return notifications;
+ }
+
+ /**
+ * If a notification with an ID exists.
+ *
+ * @param id
+ * Notification ID
+ */
+ public boolean exist (int id) {
+ return get(id) != null;
+ }
+
+ /**
+ * If a notification with an ID and type exists.
+ *
+ * @param id
+ * Notification ID
+ * @param type
+ * Notification type
+ */
+ public boolean exist (int id, Notification.Type type) {
+ Notification notification = get(id);
+
+ return notification != null && notification.getType() == type;
+ }
+
+ /**
+ * List of properties from all local notifications.
+ */
+ public List<JSONObject> getOptions() {
+ return getOptionsById(getIds());
+ }
+
+ /**
+ * List of properties from local notifications with matching ID.
+ *
+ * @param ids
+ * Set of notification IDs
+ */
+ public List<JSONObject> getOptionsById(List<Integer> ids) {
+ ArrayList<JSONObject> options = new ArrayList<JSONObject>();
+
+ for (int id : ids) {
+ Notification notification = get(id);
+
+ if (notification != null) {
+ options.add(notification.getOptions().getDict());
+ }
+ }
+
+ return options;
+ }
+
+ /**
+ * List of properties from all local notifications from given type.
+ *
+ * @param type
+ * The notification life cycle type
+ */
+ public List<JSONObject> getOptionsByType(Notification.Type type) {
+ ArrayList<JSONObject> options = new ArrayList<JSONObject>();
+ List<Notification> notifications = getByType(type);
+
+ for (Notification notification : notifications) {
+ options.add(notification.getOptions().getDict());
+ }
+
+ return options;
+ }
+
+ /**
+ * List of properties from local notifications with matching ID from
+ * given type.
+ *
+ * @param type
+ * The notification life cycle type
+ * @param ids
+ * Set of notification IDs
+ */
+ public List<JSONObject> getOptionsBy(Notification.Type type,
+ List<Integer> ids) {
+
+ if (type == Notification.Type.ALL)
+ return getOptionsById(ids);
+
+ ArrayList<JSONObject> options = new ArrayList<JSONObject>();
+ List<Notification> notifications = getByIds(ids);
+
+ for (Notification notification : notifications) {
+ if (notification.getType() == type) {
+ options.add(notification.getOptions().getDict());
+ }
+ }
+
+ return options;
+ }
+
+ /**
+ * Get existent local notification.
+ *
+ * @param id
+ * Notification ID
+ */
+ public Notification get(int id) {
+ Map<String, ?> alarms = getPrefs().getAll();
+ String notId = Integer.toString(id);
+ JSONObject options;
+
+ if (!alarms.containsKey(notId))
+ return null;
+
+
+ try {
+ String json = alarms.get(notId).toString();
+ options = new JSONObject(json);
+ } catch (JSONException e) {
+ e.printStackTrace();
+ return null;
+ }
+
+ Builder builder = new Builder(context, options);
+
+ return builder.build();
+ }
+
+ /**
+ * Merge two JSON objects.
+ *
+ * @param obj1
+ * JSON object
+ * @param obj2
+ * JSON object with new options
+ */
+ private JSONObject mergeJSONObjects (JSONObject obj1, JSONObject obj2) {
+ Iterator it = obj2.keys();
+
+ while (it.hasNext()) {
+ try {
+ String key = (String)it.next();
+
+ obj1.put(key, obj2.opt(key));
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ return obj1;
+ }
+
+ /**
+ * Shared private preferences for the application.
+ */
+ private SharedPreferences getPrefs () {
+ return context.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE);
+ }
+
+ /**
+ * Notification manager for the application.
+ */
+ private NotificationManager getNotMgr () {
+ return (NotificationManager) context
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Notification.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Notification.java
new file mode 100644
index 00000000..5dba9d54
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Notification.java
@@ -0,0 +1,350 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.notification;
+
+
+import android.app.AlarmManager;
+import android.app.NotificationManager;
+import android.app.PendingIntent;
+import android.content.Context;
+import android.content.Intent;
+import android.content.SharedPreferences;
+import android.os.Build;
+import android.support.v4.app.NotificationCompat;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Date;
+
+/**
+ * Wrapper class around OS notification class. Handles basic operations
+ * like show, delete, cancel for a single local notification instance.
+ */
+public class Notification {
+
+ // Used to differ notifications by their life cycle state
+ public enum Type {
+ ALL, SCHEDULED, TRIGGERED
+ }
+
+ // Default receiver to handle the trigger event
+ private static Class<?> defaultReceiver = TriggerReceiver.class;
+
+ // Key for private preferences
+ static final String PREF_KEY = "LocalNotification";
+
+ // Application context passed by constructor
+ private final Context context;
+
+ // Notification options passed by JS
+ private final Options options;
+
+ // Builder with full configuration
+ private final NotificationCompat.Builder builder;
+
+ // Receiver to handle the trigger event
+ private Class<?> receiver = defaultReceiver;
+
+ /**
+ * Constructor
+ *
+ * @param context
+ * Application context
+ * @param options
+ * Parsed notification options
+ * @param builder
+ * Pre-configured notification builder
+ */
+ protected Notification (Context context, Options options,
+ NotificationCompat.Builder builder, Class<?> receiver) {
+
+ this.context = context;
+ this.options = options;
+ this.builder = builder;
+
+ this.receiver = receiver != null ? receiver : defaultReceiver;
+ }
+
+ /**
+ * Get application context.
+ */
+ public Context getContext () {
+ return context;
+ }
+
+ /**
+ * Get notification options.
+ */
+ public Options getOptions () {
+ return options;
+ }
+
+ /**
+ * Get notification ID.
+ */
+ public int getId () {
+ return options.getId();
+ }
+
+ /**
+ * If it's a repeating notification.
+ */
+ public boolean isRepeating () {
+ return getOptions().getRepeatInterval() > 0;
+ }
+
+ /**
+ * If the notification was in the past.
+ */
+ public boolean wasInThePast () {
+ return new Date().after(options.getTriggerDate());
+ }
+
+ /**
+ * If the notification is scheduled.
+ */
+ public boolean isScheduled () {
+ return isRepeating() || !wasInThePast();
+ }
+
+ /**
+ * If the notification is triggered.
+ */
+ public boolean isTriggered () {
+ return wasInThePast();
+ }
+
+ /**
+ * If the notification is an update.
+ */
+ protected boolean isUpdate () {
+
+ if (!options.getDict().has("updatedAt"))
+ return false;
+
+ long now = new Date().getTime();
+
+ long updatedAt = options.getDict().optLong("updatedAt", now);
+
+ return (now - updatedAt) < 1000;
+ }
+
+ /**
+ * Notification type can be one of pending or scheduled.
+ */
+ public Type getType () {
+ return isTriggered() ? Type.TRIGGERED : Type.SCHEDULED;
+ }
+
+ /**
+ * Schedule the local notification.
+ */
+ public void schedule() {
+ long triggerTime = options.getTriggerTime();
+
+ persist();
+
+ // Intent gets called when the Notification gets fired
+ Intent intent = new Intent(context, receiver)
+ .setAction(options.getIdStr())
+ .putExtra(Options.EXTRA, options.toString());
+
+ PendingIntent pi = PendingIntent.getBroadcast(
+ context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
+
+ if (isRepeating()) {
+ getAlarmMgr().setRepeating(AlarmManager.RTC_WAKEUP,
+ triggerTime, options.getRepeatInterval(), pi);
+ } else {
+ getAlarmMgr().set(AlarmManager.RTC_WAKEUP, triggerTime, pi);
+ }
+ }
+
+ /**
+ * Clear the local notification without canceling repeating alarms.
+ *
+ */
+ public void clear () {
+ if (!isRepeating() && wasInThePast()) {
+ unpersist();
+ } else {
+ getNotMgr().cancel(getId());
+ }
+ }
+
+ /**
+ * Cancel the local notification.
+ *
+ * Create an intent that looks similar, to the one that was registered
+ * using schedule. Making sure the notification id in the action is the
+ * same. Now we can search for such an intent using the 'getService'
+ * method and cancel it.
+ */
+ public void cancel() {
+ Intent intent = new Intent(context, receiver)
+ .setAction(options.getIdStr());
+
+ PendingIntent pi = PendingIntent.
+ getBroadcast(context, 0, intent, 0);
+
+ getAlarmMgr().cancel(pi);
+ getNotMgr().cancel(options.getId());
+
+ unpersist();
+ }
+
+ /**
+ * Present the local notification to user.
+ */
+ public void show () {
+ // TODO Show dialog when in foreground
+ showNotification();
+ }
+
+ /**
+ * Show as local notification when in background.
+ */
+ @SuppressWarnings("deprecation")
+ private void showNotification () {
+ int id = getOptions().getId();
+
+ if (Build.VERSION.SDK_INT <= 15) {
+ // Notification for HoneyComb to ICS
+ getNotMgr().notify(id, builder.getNotification());
+ } else {
+ // Notification for Jellybean and above
+ getNotMgr().notify(id, builder.build());
+ }
+ }
+
+ /**
+ * Show as modal dialog when in foreground.
+ */
+ private void showDialog () {
+ // TODO
+ }
+
+ /**
+ * Count of triggers since schedule.
+ */
+ public int getTriggerCountSinceSchedule() {
+ long now = System.currentTimeMillis();
+ long triggerTime = options.getTriggerTime();
+
+ if (!wasInThePast())
+ return 0;
+
+ if (!isRepeating())
+ return 1;
+
+ return (int) ((now - triggerTime) / options.getRepeatInterval());
+ }
+
+ /**
+ * Encode options to JSON.
+ */
+ public String toString() {
+ JSONObject dict = options.getDict();
+ JSONObject json = new JSONObject();
+
+ try {
+ json = new JSONObject(dict.toString());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+
+ json.remove("firstAt");
+ json.remove("updatedAt");
+ json.remove("soundUri");
+ json.remove("iconUri");
+
+ return json.toString();
+ }
+
+ /**
+ * Persist the information of this notification to the Android Shared
+ * Preferences. This will allow the application to restore the notification
+ * upon device reboot, app restart, retrieve notifications, aso.
+ */
+ private void persist () {
+ SharedPreferences.Editor editor = getPrefs().edit();
+
+ editor.putString(options.getIdStr(), options.toString());
+
+ if (Build.VERSION.SDK_INT < 9) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ }
+
+ /**
+ * Remove the notification from the Android shared Preferences.
+ */
+ private void unpersist () {
+ SharedPreferences.Editor editor = getPrefs().edit();
+
+ editor.remove(options.getIdStr());
+
+ if (Build.VERSION.SDK_INT < 9) {
+ editor.commit();
+ } else {
+ editor.apply();
+ }
+ }
+
+ /**
+ * Shared private preferences for the application.
+ */
+ private SharedPreferences getPrefs () {
+ return context.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE);
+ }
+
+ /**
+ * Notification manager for the application.
+ */
+ private NotificationManager getNotMgr () {
+ return (NotificationManager) context
+ .getSystemService(Context.NOTIFICATION_SERVICE);
+ }
+
+ /**
+ * Alarm manager for the application.
+ */
+ private AlarmManager getAlarmMgr () {
+ return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
+ }
+
+ /**
+ * Set default receiver to handle the trigger event.
+ *
+ * @param receiver
+ * broadcast receiver
+ */
+ public static void setDefaultTriggerReceiver (Class<?> receiver) {
+ defaultReceiver = receiver;
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Options.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Options.java
new file mode 100644
index 00000000..198a52f4
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/Options.java
@@ -0,0 +1,303 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.notification;
+
+import android.app.AlarmManager;
+import android.content.Context;
+import android.graphics.Bitmap;
+import android.net.Uri;
+
+import org.json.JSONException;
+import org.json.JSONObject;
+
+import java.util.Date;
+
+/**
+ * Wrapper around the JSON object passed through JS which contains all
+ * possible option values. Class provides simple readers and more advanced
+ * methods to convert independent values into platform specific values.
+ */
+public class Options {
+
+ // Key name for bundled extras
+ static final String EXTRA = "NOTIFICATION_OPTIONS";
+
+ // The original JSON object
+ private JSONObject options = new JSONObject();
+
+ // Repeat interval
+ private long interval = 0;
+
+ // Application context
+ private final Context context;
+
+ // Asset util instance
+ private final AssetUtil assets;
+
+
+ /**
+ * Constructor
+ *
+ * @param context
+ * Application context
+ */
+ public Options(Context context){
+ this.context = context;
+ this.assets = AssetUtil.getInstance(context);
+ }
+
+ /**
+ * Parse given JSON properties.
+ *
+ * @param options
+ * JSON properties
+ */
+ public Options parse (JSONObject options) {
+ this.options = options;
+
+ parseInterval();
+ parseAssets();
+
+ return this;
+ }
+
+ /**
+ * Parse repeat interval.
+ */
+ private void parseInterval() {
+ String every = options.optString("every").toLowerCase();
+
+ if (every.isEmpty()) {
+ interval = 0;
+ } else
+ if (every.equals("second")) {
+ interval = 1000;
+ } else
+ if (every.equals("minute")) {
+ interval = AlarmManager.INTERVAL_FIFTEEN_MINUTES / 15;
+ } else
+ if (every.equals("hour")) {
+ interval = AlarmManager.INTERVAL_HOUR;
+ } else
+ if (every.equals("day")) {
+ interval = AlarmManager.INTERVAL_DAY;
+ } else
+ if (every.equals("week")) {
+ interval = AlarmManager.INTERVAL_DAY * 7;
+ } else
+ if (every.equals("month")) {
+ interval = AlarmManager.INTERVAL_DAY * 31;
+ } else
+ if (every.equals("year")) {
+ interval = AlarmManager.INTERVAL_DAY * 365;
+ } else {
+ try {
+ interval = Integer.parseInt(every) * 60000;
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+
+ /**
+ * Parse asset URIs.
+ */
+ private void parseAssets() {
+
+ if (options.has("iconUri"))
+ return;
+
+ Uri iconUri = assets.parse(options.optString("icon", "icon"));
+ Uri soundUri = assets.parseSound(options.optString("sound", null));
+
+ try {
+ options.put("iconUri", iconUri.toString());
+ options.put("soundUri", soundUri.toString());
+ } catch (JSONException e) {
+ e.printStackTrace();
+ }
+ }
+
+ /**
+ * Application context.
+ */
+ public Context getContext () {
+ return context;
+ }
+
+ /**
+ * Wrapped JSON object.
+ */
+ JSONObject getDict () {
+ return options;
+ }
+
+ /**
+ * Text for the local notification.
+ */
+ public String getText() {
+ return options.optString("text", "");
+ }
+
+ /**
+ * Repeat interval (day, week, month, year, aso.)
+ */
+ public long getRepeatInterval() {
+ return interval;
+ }
+
+ /**
+ * Badge number for the local notification.
+ */
+ public int getBadgeNumber() {
+ return options.optInt("badge", 0);
+ }
+
+ /**
+ * ongoing flag for local notifications.
+ */
+ public Boolean isOngoing() {
+ return options.optBoolean("ongoing", false);
+ }
+
+ /**
+ * autoClear flag for local notifications.
+ */
+ public Boolean isAutoClear() {
+ return options.optBoolean("autoClear", false);
+ }
+
+ /**
+ * ID for the local notification as a number.
+ */
+ public Integer getId() {
+ return options.optInt("id", 0);
+ }
+
+ /**
+ * ID for the local notification as a string.
+ */
+ public String getIdStr() {
+ return getId().toString();
+ }
+
+ /**
+ * Trigger date.
+ */
+ public Date getTriggerDate() {
+ return new Date(getTriggerTime());
+ }
+
+ /**
+ * Trigger date in milliseconds.
+ */
+ public long getTriggerTime() {
+ return Math.max(
+ System.currentTimeMillis(),
+ options.optLong("at", 0) * 1000
+ );
+ }
+
+ /**
+ * Title for the local notification.
+ */
+ public String getTitle() {
+ String title = options.optString("title", "");
+
+ if (title.isEmpty()) {
+ title = context.getApplicationInfo().loadLabel(
+ context.getPackageManager()).toString();
+ }
+
+ return title;
+ }
+
+ /**
+ * @return
+ * The notification color for LED
+ */
+ public int getLedColor() {
+ String hex = options.optString("led", "000000");
+ int aRGB = Integer.parseInt(hex,16);
+
+ aRGB += 0xFF000000;
+
+ return aRGB;
+ }
+
+ /**
+ * Sound file path for the local notification.
+ */
+ public Uri getSoundUri() {
+ Uri uri = null;
+
+ try{
+ uri = Uri.parse(options.optString("soundUri"));
+ } catch (Exception e){
+ e.printStackTrace();
+ }
+
+ return uri;
+ }
+
+ /**
+ * Icon bitmap for the local notification.
+ */
+ public Bitmap getIconBitmap() {
+ String icon = options.optString("icon", "icon");
+ Bitmap bmp;
+
+ try{
+ Uri uri = Uri.parse(options.optString("iconUri"));
+ bmp = assets.getIconFromUri(uri);
+ } catch (Exception e){
+ bmp = assets.getIconFromDrawable(icon);
+ }
+
+ return bmp;
+ }
+
+ /**
+ * Small icon resource ID for the local notification.
+ */
+ public int getSmallIcon () {
+ String icon = options.optString("smallIcon", "");
+
+ int resId = assets.getResIdForDrawable(icon);
+
+ if (resId == 0) {
+ resId = android.R.drawable.screen_background_dark;
+ }
+
+ return resId;
+ }
+
+ /**
+ * JSON object as string.
+ */
+ public String toString() {
+ return options.toString();
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/TriggerReceiver.java b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/TriggerReceiver.java
new file mode 100644
index 00000000..9427e31e
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/android/notification/TriggerReceiver.java
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+package de.appplant.cordova.plugin.notification;
+
+/**
+ * The alarm receiver is triggered when a scheduled alarm is fired. This class
+ * reads the information in the intent and displays this information in the
+ * Android notification bar. The notification uses the default notification
+ * sound and it vibrates the phone.
+ */
+public class TriggerReceiver extends AbstractTriggerReceiver {
+
+ /**
+ * Called when a local notification was triggered. Does present the local
+ * notification and re-schedule the alarm if necessary.
+ *
+ * @param notification
+ * Wrapper around the local notification
+ * @param updated
+ * If an update has triggered or the original
+ */
+ @Override
+ public void onTrigger (Notification notification, boolean updated) {
+ notification.show();
+ }
+
+ /**
+ * Build notification specified by options.
+ *
+ * @param builder
+ * Notification builder
+ */
+ @Override
+ public Notification buildNotification (Builder builder) {
+ return builder.build();
+ }
+
+}
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotification.h b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotification.h
new file mode 100644
index 00000000..f86bf498
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotification.h
@@ -0,0 +1,78 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+#import <Foundation/Foundation.h>
+#import <Cordova/CDVPlugin.h>
+
+@interface APPLocalNotification : CDVPlugin
+
+// Execute all queued events
+- (void) deviceready:(CDVInvokedUrlCommand*)command;
+
+// Inform if the app has the permission to show notifications
+- (void) hasPermission:(CDVInvokedUrlCommand*)command;
+// Register permission to show notifications
+- (void) registerPermission:(CDVInvokedUrlCommand*)command;
+
+// Schedule set of notifications
+- (void) schedule:(CDVInvokedUrlCommand*)command;
+// Update set of notifications
+- (void) update:(CDVInvokedUrlCommand*)command;
+// Cancel set of notifications
+- (void) cancel:(CDVInvokedUrlCommand*)command;
+// Cancel all notifications
+- (void) cancelAll:(CDVInvokedUrlCommand*)command;
+// Clear set of notifications
+- (void) clear:(CDVInvokedUrlCommand*)command;
+// Clear all notifications
+- (void) clearAll:(CDVInvokedUrlCommand*)command;
+
+// If a notification with an ID is present
+- (void) isPresent:(CDVInvokedUrlCommand*)command;
+// If a notification with an ID is scheduled
+- (void) isScheduled:(CDVInvokedUrlCommand*)command;
+// If a notification with an ID is triggered
+- (void) isTriggered:(CDVInvokedUrlCommand*)command;
+
+// List all ids from all local notifications
+- (void) getAllIds:(CDVInvokedUrlCommand*)command;
+// List all ids from all pending notifications
+- (void) getScheduledIds:(CDVInvokedUrlCommand*)command;
+// List all ids from all triggered notifications
+- (void) getTriggeredIds:(CDVInvokedUrlCommand*)command;
+
+// Propertys for given local notification
+- (void) getSingle:(CDVInvokedUrlCommand*)command;
+// Propertya for given scheduled notification
+- (void) getSingleScheduled:(CDVInvokedUrlCommand*)command;
+// Propertys for given triggered notification
+- (void) getSingleTriggered:(CDVInvokedUrlCommand*)command;
+
+// Property list for given local notifications
+- (void) getAll:(CDVInvokedUrlCommand*)command;
+// Property list for given scheduled notifications
+- (void) getScheduled:(CDVInvokedUrlCommand*)command;
+// Property list for given triggered notifications
+- (void) getTriggered:(CDVInvokedUrlCommand*)command;
+
+@end
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotification.m b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotification.m
new file mode 100644
index 00000000..43cf9f8c
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotification.m
@@ -0,0 +1,738 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+#import "APPLocalNotification.h"
+#import "APPLocalNotificationOptions.h"
+#import "UIApplication+APPLocalNotification.h"
+#import "UILocalNotification+APPLocalNotification.h"
+#import "AppDelegate+APPRegisterUserNotificationSettings.h"
+
+@interface APPLocalNotification ()
+
+// Retrieves the application state
+@property (readonly, getter=applicationState) NSString* applicationState;
+// All events will be queued until deviceready has been fired
+@property (readwrite, assign) BOOL deviceready;
+// Event queue
+@property (readonly, nonatomic, retain) NSMutableArray* eventQueue;
+// Needed when calling `registerPermission`
+@property (nonatomic, retain) CDVInvokedUrlCommand* command;
+
+@end
+
+@implementation APPLocalNotification
+
+@synthesize deviceready, eventQueue;
+
+#pragma mark -
+#pragma mark Interface
+
+/**
+ * Execute all queued events.
+ */
+- (void) deviceready:(CDVInvokedUrlCommand*)command
+{
+ deviceready = YES;
+
+ for (NSString* js in eventQueue) {
+ [self.commandDelegate evalJs:js];
+ }
+
+ [eventQueue removeAllObjects];
+}
+
+/**
+ * Schedule a set of notifications.
+ *
+ * @param properties
+ * A dict of properties for each notification
+ */
+- (void) schedule:(CDVInvokedUrlCommand*)command
+{
+ NSArray* notifications = command.arguments;
+
+ [self.commandDelegate runInBackground:^{
+ for (NSDictionary* options in notifications) {
+ UILocalNotification* notification;
+
+ notification = [[UILocalNotification alloc]
+ initWithOptions:options];
+
+ [self scheduleLocalNotification:[notification copy]];
+ [self fireEvent:@"schedule" notification:notification];
+
+ if (notifications.count > 1) {
+ [NSThread sleepForTimeInterval:0.01];
+ }
+ }
+
+ [self execCallback:command];
+ }];
+}
+
+/**
+ * Update a set of notifications.
+ *
+ * @param properties
+ * A dict of properties for each notification
+ */
+- (void) update:(CDVInvokedUrlCommand*)command
+{
+ NSArray* notifications = command.arguments;
+
+ [self.commandDelegate runInBackground:^{
+ for (NSDictionary* options in notifications) {
+ NSNumber* id = [options objectForKey:@"id"];
+ UILocalNotification* notification;
+
+ notification = [self.app localNotificationWithId:id];
+
+ if (!notification)
+ continue;
+
+ [self updateLocalNotification:[notification copy]
+ withOptions:options];
+
+ [self fireEvent:@"update" notification:notification];
+
+ if (notifications.count > 1) {
+ [NSThread sleepForTimeInterval:0.01];
+ }
+ }
+
+ [self execCallback:command];
+ }];
+}
+
+/**
+ * Cancel a set of notifications.
+ *
+ * @param ids
+ * The IDs of the notifications
+ */
+- (void) cancel:(CDVInvokedUrlCommand*)command
+{
+ [self.commandDelegate runInBackground:^{
+ for (NSNumber* id in command.arguments) {
+ UILocalNotification* notification;
+
+ notification = [self.app localNotificationWithId:id];
+
+ if (!notification)
+ continue;
+
+ [self.app cancelLocalNotification:notification];
+ [self fireEvent:@"cancel" notification:notification];
+ }
+
+ [self execCallback:command];
+ }];
+}
+
+/**
+ * Cancel all local notifications.
+ */
+- (void) cancelAll:(CDVInvokedUrlCommand*)command
+{
+ [self.commandDelegate runInBackground:^{
+ [self cancelAllLocalNotifications];
+ [self fireEvent:@"cancelall"];
+ [self execCallback:command];
+ }];
+}
+
+/**
+ * Clear a set of notifications.
+ *
+ * @param ids
+ * The IDs of the notifications
+ */
+- (void) clear:(CDVInvokedUrlCommand*)command
+{
+ [self.commandDelegate runInBackground:^{
+ for (NSNumber* id in command.arguments) {
+ UILocalNotification* notification;
+
+ notification = [self.app localNotificationWithId:id];
+
+ if (!notification)
+ continue;
+
+ [self.app clearLocalNotification:notification];
+ [self fireEvent:@"clear" notification:notification];
+ }
+
+ [self execCallback:command];
+ }];
+}
+
+/**
+ * Clear all local notifications.
+ */
+- (void) clearAll:(CDVInvokedUrlCommand*)command
+{
+ [self.commandDelegate runInBackground:^{
+ [self clearAllLocalNotifications];
+ [self fireEvent:@"clearall"];
+ [self execCallback:command];
+ }];
+}
+
+/**
+ * If a notification by ID is present.
+ *
+ * @param id
+ * The ID of the notification
+ */
+- (void) isPresent:(CDVInvokedUrlCommand *)command
+{
+ [self isPresent:command type:NotifcationTypeAll];
+}
+
+/**
+ * If a notification by ID is scheduled.
+ *
+ * @param id
+ * The ID of the notification
+ */
+- (void) isScheduled:(CDVInvokedUrlCommand*)command
+{
+ [self isPresent:command type:NotifcationTypeScheduled];
+}
+
+/**
+ * Check if a notification with an ID is triggered.
+ *
+ * @param id
+ * The ID of the notification
+ */
+- (void) isTriggered:(CDVInvokedUrlCommand*)command
+{
+ [self isPresent:command type:NotifcationTypeTriggered];
+}
+
+/**
+ * Check if a notification with an ID exists.
+ *
+ * @param type
+ * The notification life cycle type
+ */
+- (void) isPresent:(CDVInvokedUrlCommand*)command
+ type:(APPLocalNotificationType)type;
+{
+ [self.commandDelegate runInBackground:^{
+ NSNumber* id = [command argumentAtIndex:0];
+ BOOL exist;
+
+ CDVPluginResult* result;
+
+ if (type == NotifcationTypeAll) {
+ exist = [self.app localNotificationExist:id];
+ } else {
+ exist = [self.app localNotificationExist:id type:type];
+ }
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
+ messageAsBool:exist];
+
+ [self.commandDelegate sendPluginResult:result
+ callbackId:command.callbackId];
+ }];
+}
+
+/**
+ * List all ids from all local notifications.
+ */
+- (void) getAllIds:(CDVInvokedUrlCommand*)command
+{
+ [self getIds:command byType:NotifcationTypeAll];
+}
+
+/**
+ * List all ids from all pending notifications.
+ */
+- (void) getScheduledIds:(CDVInvokedUrlCommand*)command
+{
+ [self getIds:command byType:NotifcationTypeScheduled];
+}
+
+/**
+ * List all ids from all triggered notifications.
+ */
+- (void) getTriggeredIds:(CDVInvokedUrlCommand*)command
+{
+ [self getIds:command byType:NotifcationTypeTriggered];
+}
+
+/**
+ * List of ids for given local notifications.
+ *
+ * @param type
+ * Notification life cycle type
+ * @param ids
+ * The IDs of the notifications
+ */
+- (void) getIds:(CDVInvokedUrlCommand*)command
+ byType:(APPLocalNotificationType)type;
+{
+ [self.commandDelegate runInBackground:^{
+ CDVPluginResult* result;
+ NSArray* ids;
+
+ if (type == NotifcationTypeAll) {
+ ids = [self.app localNotificationIds];
+ } else {
+ ids = [self.app localNotificationIdsByType:type];
+ }
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
+ messageAsArray:ids];
+
+ [self.commandDelegate sendPluginResult:result
+ callbackId:command.callbackId];
+ }];
+}
+
+/**
+ * Propertys for given local notification.
+ */
+- (void) getSingle:(CDVInvokedUrlCommand*)command
+{
+ [self getOption:command byType:NotifcationTypeAll];
+}
+
+/**
+ * Propertya for given scheduled notification.
+ */
+- (void) getSingleScheduled:(CDVInvokedUrlCommand*)command
+{
+ [self getOption:command byType:NotifcationTypeScheduled];
+}
+
+// Propertys for given triggered notification
+- (void) getSingleTriggered:(CDVInvokedUrlCommand*)command
+{
+ [self getOption:command byType:NotifcationTypeTriggered];
+}
+
+/**
+ * Property list for given local notifications.
+ *
+ * @param ids
+ * The IDs of the notifications
+ */
+- (void) getAll:(CDVInvokedUrlCommand*)command
+{
+ [self getOptions:command byType:NotifcationTypeAll];
+}
+
+/**
+ * Property list for given scheduled notifications.
+ *
+ * @param ids
+ * The IDs of the notifications
+ */
+- (void) getScheduled:(CDVInvokedUrlCommand*)command
+{
+ [self getOptions:command byType:NotifcationTypeScheduled];
+}
+
+/**
+ * Property list for given triggered notifications.
+ *
+ * @param ids
+ * The IDs of the notifications
+ */
+- (void) getTriggered:(CDVInvokedUrlCommand *)command
+{
+ [self getOptions:command byType:NotifcationTypeTriggered];
+}
+
+/**
+ * Propertys for given triggered notification.
+ *
+ * @param type
+ * Notification life cycle type
+ * @param ids
+ * The ID of the notification
+ */
+- (void) getOption:(CDVInvokedUrlCommand*)command
+ byType:(APPLocalNotificationType)type;
+{
+ [self.commandDelegate runInBackground:^{
+ NSArray* ids = command.arguments;
+ NSArray* notifications;
+ CDVPluginResult* result;
+
+ if (type == NotifcationTypeAll) {
+ notifications = [self.app localNotificationOptionsById:ids];
+ }
+ else {
+ notifications = [self.app localNotificationOptionsByType:type
+ andId:ids];
+ }
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
+ messageAsDictionary:notifications[0]];
+
+ [self.commandDelegate sendPluginResult:result
+ callbackId:command.callbackId];
+ }];
+}
+
+/**
+ * Property list for given triggered notifications.
+ *
+ * @param type
+ * Notification life cycle type
+ * @param ids
+ * The IDs of the notifications
+ */
+- (void) getOptions:(CDVInvokedUrlCommand*)command
+ byType:(APPLocalNotificationType)type;
+{
+ [self.commandDelegate runInBackground:^{
+ NSArray* ids = command.arguments;
+ NSArray* notifications;
+ CDVPluginResult* result;
+
+ if (type == NotifcationTypeAll && ids.count == 0) {
+ notifications = [self.app localNotificationOptions];
+ }
+ else if (type == NotifcationTypeAll) {
+ notifications = [self.app localNotificationOptionsById:ids];
+ }
+ else if (ids.count == 0) {
+ notifications = [self.app localNotificationOptionsByType:type];
+ }
+ else {
+ notifications = [self.app localNotificationOptionsByType:type
+ andId:ids];
+ }
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
+ messageAsArray:notifications];
+
+ [self.commandDelegate sendPluginResult:result
+ callbackId:command.callbackId];
+ }];
+}
+
+/**
+ * Inform if the app has the permission to show
+ * badges and local notifications.
+ */
+- (void) hasPermission:(CDVInvokedUrlCommand*)command
+{
+ [self.commandDelegate runInBackground:^{
+ CDVPluginResult* result;
+ BOOL hasPermission;
+
+ hasPermission = [self.app hasPermissionToScheduleLocalNotifications];
+
+ result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
+ messageAsBool:hasPermission];
+
+ [self.commandDelegate sendPluginResult:result
+ callbackId:command.callbackId];
+ }];
+}
+
+/**
+ * Ask for permission to show badges.
+ */
+- (void) registerPermission:(CDVInvokedUrlCommand*)command
+{
+ if ([[UIApplication sharedApplication]
+ respondsToSelector:@selector(registerUserNotificationSettings:)])
+ {
+ _command = command;
+
+ [self.commandDelegate runInBackground:^{
+ [self.app registerPermissionToScheduleLocalNotifications];
+ }];
+ } else {
+ [self hasPermission:command];
+ }
+}
+
+#pragma mark -
+#pragma mark Core Logic
+
+/**
+ * Schedule the local notification.
+ */
+- (void) scheduleLocalNotification:(UILocalNotification*)notification
+{
+ [self cancelForerunnerLocalNotification:notification];
+ [self.app scheduleLocalNotification:notification];
+}
+
+/**
+ * Update the local notification.
+ */
+- (void) updateLocalNotification:(UILocalNotification*)notification
+ withOptions:(NSDictionary*)newOptions
+{
+ NSMutableDictionary* options = [notification.userInfo mutableCopy];
+
+ [options addEntriesFromDictionary:newOptions];
+ [options setObject:[NSDate date] forKey:@"updatedAt"];
+
+ notification = [[UILocalNotification alloc]
+ initWithOptions:options];
+
+ [self scheduleLocalNotification:notification];
+}
+
+/**
+ * Cancel all local notifications.
+ */
+- (void) cancelAllLocalNotifications
+{
+ [self.app cancelAllLocalNotifications];
+ [self.app setApplicationIconBadgeNumber:0];
+}
+
+/**
+ * Clear all local notifications.
+ */
+- (void) clearAllLocalNotifications
+{
+ [self.app clearAllLocalNotifications];
+ [self.app setApplicationIconBadgeNumber:0];
+}
+
+/**
+ * Cancel a maybe given forerunner with the same ID.
+ */
+- (void) cancelForerunnerLocalNotification:(UILocalNotification*)notification
+{
+ NSNumber* id = notification.options.id;
+ UILocalNotification* forerunner;
+
+ forerunner = [self.app localNotificationWithId:id];
+
+ if (!forerunner)
+ return;
+
+ [self.app cancelLocalNotification:forerunner];
+}
+
+/**
+ * Cancels all non-repeating local notification older then
+ * a specific amount of seconds
+ */
+- (void) cancelAllNotificationsWhichAreOlderThen:(float)seconds
+{
+ NSArray* notifications;
+
+ notifications = [self.app localNotifications];
+
+ for (UILocalNotification* notification in notifications)
+ {
+ if (![notification isRepeating]
+ && notification.timeIntervalSinceFireDate > seconds)
+ {
+ [self.app cancelLocalNotification:notification];
+ [self fireEvent:@"cancel" notification:notification];
+ }
+ }
+}
+
+#pragma mark -
+#pragma mark Delegates
+
+/**
+ * Calls the cancel or trigger event after a local notification was received.
+ * Cancels the local notification if autoCancel was set to true.
+ */
+- (void) didReceiveLocalNotification:(NSNotification*)localNotification
+{
+ UILocalNotification* notification = [localNotification object];
+
+ if ([notification wasUpdated])
+ return;
+
+ NSTimeInterval timeInterval = [notification timeIntervalSinceLastTrigger];
+
+ NSString* event = (timeInterval <= 1 && deviceready) ? @"trigger" : @"click";
+
+ [self fireEvent:event notification:notification];
+
+ if (![event isEqualToString:@"click"])
+ return;
+
+ if ([notification isRepeating]) {
+ [self fireEvent:@"clear" notification:notification];
+ } else {
+ [self.app cancelLocalNotification:notification];
+ [self fireEvent:@"cancel" notification:notification];
+ }
+}
+
+/**
+ * Called when app has started
+ * (by clicking on a local notification).
+ */
+- (void) didFinishLaunchingWithOptions:(NSNotification*)notification
+{
+ NSDictionary* launchOptions = [notification userInfo];
+
+ UILocalNotification* localNotification;
+
+ localNotification = [launchOptions objectForKey:
+ UIApplicationLaunchOptionsLocalNotificationKey];
+
+ if (localNotification) {
+ [self didReceiveLocalNotification:
+ [NSNotification notificationWithName:CDVLocalNotification
+ object:localNotification]];
+ }
+}
+
+/**
+ * Called on otification settings registration is completed.
+ */
+- (void) didRegisterUserNotificationSettings:(UIUserNotificationSettings*)settings
+{
+ if (_command)
+ {
+ [self hasPermission:_command];
+ _command = NULL;
+ }
+}
+
+#pragma mark -
+#pragma mark Life Cycle
+
+/**
+ * Registers obervers after plugin was initialized.
+ */
+- (void) pluginInitialize
+{
+ NSNotificationCenter* center = [NSNotificationCenter
+ defaultCenter];
+
+ eventQueue = [[NSMutableArray alloc] init];
+
+ [center addObserver:self
+ selector:@selector(didReceiveLocalNotification:)
+ name:CDVLocalNotification
+ object:nil];
+
+ [center addObserver:self
+ selector:@selector(didFinishLaunchingWithOptions:)
+ name:UIApplicationDidFinishLaunchingNotification
+ object:nil];
+
+ [center addObserver:self
+ selector:@selector(didRegisterUserNotificationSettings:)
+ name:UIApplicationRegisterUserNotificationSettings
+ object:nil];
+}
+
+/**
+ * Clears all single repeating notifications which are older then 5 days
+ * before the app terminates.
+ */
+- (void) onAppTerminate
+{
+ [self cancelAllNotificationsWhichAreOlderThen:432000];
+}
+
+#pragma mark -
+#pragma mark Helper
+
+/**
+ * Retrieves the application state
+ *
+ * @return
+ * Either "background" or "foreground"
+ */
+- (NSString*) applicationState
+{
+ UIApplicationState state = [self.app applicationState];
+
+ bool isActive = state == UIApplicationStateActive;
+
+ return isActive ? @"foreground" : @"background";
+}
+
+/**
+ * Simply invokes the callback without any parameter.
+ */
+- (void) execCallback:(CDVInvokedUrlCommand*)command
+{
+ CDVPluginResult *result = [CDVPluginResult
+ resultWithStatus:CDVCommandStatus_OK];
+
+ [self.commandDelegate sendPluginResult:result
+ callbackId:command.callbackId];
+}
+
+/**
+ * Short hand for shared application instance.
+ */
+- (UIApplication*) app
+{
+ return [UIApplication sharedApplication];
+}
+
+/**
+ * Fire general event.
+ */
+- (void) fireEvent:(NSString*)event
+{
+ [self fireEvent:event notification:NULL];
+}
+
+/**
+ * Fire event for local notification.
+ */
+- (void) fireEvent:(NSString*)event notification:(UILocalNotification*)notification
+{
+ NSString* js;
+ NSString* params = [NSString stringWithFormat:
+ @"\"%@\"", self.applicationState];
+
+ if (notification) {
+ NSString* args = [notification encodeToJSON];
+
+ params = [NSString stringWithFormat:
+ @"%@,'%@'",
+ args, self.applicationState];
+ }
+
+ js = [NSString stringWithFormat:
+ @"cordova.plugins.notification.local.core.fireEvent('%@', %@)",
+ event, params];
+
+ if (deviceready) {
+ [self.commandDelegate evalJs:js];
+ } else {
+ [self.eventQueue addObject:js];
+ }
+}
+
+@end
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotificationOptions.h b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotificationOptions.h
new file mode 100644
index 00000000..73c3ef75
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotificationOptions.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+@interface APPLocalNotificationOptions : NSObject
+
+- (id) initWithDict:(NSDictionary*)dict;
+
+@property (readonly, getter=id) NSNumber* id;
+@property (readonly, getter=badgeNumber) NSInteger badgeNumber;
+@property (readonly, getter=alertBody) NSString* alertBody;
+@property (readonly, getter=soundName) NSString* soundName;
+@property (readonly, getter=fireDate) NSDate* fireDate;
+@property (readonly, getter=repeatInterval) NSCalendarUnit repeatInterval;
+@property (readonly, getter=userInfo) NSDictionary* userInfo;
+
+// If it's a repeating notification
+- (BOOL) isRepeating;
+
+@end
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotificationOptions.m b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotificationOptions.m
new file mode 100644
index 00000000..ac90f993
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/APPLocalNotificationOptions.m
@@ -0,0 +1,246 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+#import "APPLocalNotificationOptions.h"
+
+// Default sound ressource path
+NSString* const DEFAULT_SOUND = @"res://platform_default";
+
+@interface APPLocalNotificationOptions ()
+
+// The dictionary which contains all notification properties
+@property(nonatomic, retain) NSDictionary* dict;
+
+@end
+
+@implementation APPLocalNotificationOptions
+
+@synthesize dict;
+
+#pragma mark -
+#pragma mark Initialization
+
+/**
+ * Initialize the object with the given options when calling on JS side:
+ * notification.local.add(options)
+ */
+- (id) initWithDict:(NSDictionary*)dictionary
+{
+ self = [self init];
+
+ self.dict = dictionary;
+
+ return self;
+}
+
+#pragma mark -
+#pragma mark Attributes
+
+/**
+ * The notification's ID.
+ */
+- (NSNumber*) id
+{
+ NSInteger id = [[dict objectForKey:@"id"] integerValue];
+
+ return [NSNumber numberWithInteger:id];
+}
+
+/**
+ * The notification's title.
+ */
+- (NSString*) title
+{
+ return [dict objectForKey:@"title"];
+}
+
+/**
+ * The notification's message.
+ */
+- (NSString*) text
+{
+ return [dict objectForKey:@"text"];
+}
+
+/**
+ * The notification's badge number.
+ */
+- (NSInteger) badgeNumber
+{
+ return [[dict objectForKey:@"badge"] intValue];
+}
+
+#pragma mark -
+#pragma mark Complex Attributes
+
+/**
+ * The notification's alert body.
+ */
+- (NSString*) alertBody
+{
+ NSString* title = [self title];
+ NSString* msg = [self text];
+
+ NSString* alertBody = msg;
+
+ if (![self stringIsNullOrEmpty:title])
+ {
+ alertBody = [NSString stringWithFormat:@"%@\n%@",
+ title, msg];
+ }
+
+ return alertBody;
+}
+
+/**
+ * The notification's sound path.
+ */
+- (NSString*) soundName
+{
+ NSString* path = [dict objectForKey:@"sound"];
+
+ if ([self stringIsNullOrEmpty:path])
+ return NULL;
+
+ if ([path isEqualToString:DEFAULT_SOUND])
+ return UILocalNotificationDefaultSoundName;
+
+ if ([path hasPrefix:@"file:/"])
+ return [self soundNameForAsset:path];
+
+ if ([path hasPrefix:@"res:"])
+ return [self soundNameForResource:path];
+
+ return NULL;
+}
+
+/**
+ * The notification's fire date.
+ */
+- (NSDate*) fireDate
+{
+ double timestamp = [[dict objectForKey:@"at"]
+ doubleValue];
+
+ return [NSDate dateWithTimeIntervalSince1970:timestamp];
+}
+
+/**
+ * The notification's repeat interval.
+ */
+- (NSCalendarUnit) repeatInterval
+{
+ NSString* interval = [dict objectForKey:@"every"];
+
+ if ([self stringIsNullOrEmpty:interval]) {
+ return NSCalendarUnitEra;
+ }
+ else if ([interval isEqualToString:@"second"]) {
+ return NSCalendarUnitSecond;
+ }
+ else if ([interval isEqualToString:@"minute"]) {
+ return NSCalendarUnitMinute;
+ }
+ else if ([interval isEqualToString:@"hour"]) {
+ return NSCalendarUnitHour;
+ }
+ else if ([interval isEqualToString:@"day"]) {
+ return NSCalendarUnitDay;
+ }
+ else if ([interval isEqualToString:@"week"]) {
+ return NSCalendarUnitWeekOfYear;
+ }
+ else if ([interval isEqualToString:@"month"]) {
+ return NSCalendarUnitMonth;
+ }
+ else if ([interval isEqualToString:@"year"]) {
+ return NSCalendarUnitYear;
+ }
+
+ return NSCalendarUnitEra;
+}
+
+#pragma mark -
+#pragma mark Methods
+
+/**
+ * The notification's user info dict.
+ */
+- (NSDictionary*) userInfo
+{
+ if ([dict objectForKey:@"updatedAt"]) {
+ NSMutableDictionary* data = [dict mutableCopy];
+
+ [data removeObjectForKey:@"updatedAt"];
+
+ return data;
+ }
+
+ return dict;
+}
+
+/**
+ * If it's a repeating notification.
+ */
+- (BOOL) isRepeating
+{
+ NSCalendarUnit interval = self.repeatInterval;
+
+ return !(interval == NSCalendarUnitEra || interval == 0);
+}
+
+#pragma mark -
+#pragma mark Helpers
+
+/**
+ * Convert relative path to valid sound name attribute.
+ */
+- (NSString*) soundNameForAsset:(NSString*)path
+{
+ return [path stringByReplacingOccurrencesOfString:@"file:/"
+ withString:@"www"];
+}
+
+/**
+ * Convert resource path to valid sound name attribute.
+ */
+- (NSString*) soundNameForResource:(NSString*)path
+{
+ return [path pathComponents].lastObject;
+}
+
+/**
+ * If the string is empty.
+ */
+- (BOOL) stringIsNullOrEmpty:(NSString*)str
+{
+ if (str == (NSString*)[NSNull null])
+ return YES;
+
+ if ([str isEqualToString:@""])
+ return YES;
+
+ return NO;
+}
+
+@end
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/ios/UIApplication+APPLocalNotification.h b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/UIApplication+APPLocalNotification.h
new file mode 100644
index 00000000..a18568e5
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/UIApplication+APPLocalNotification.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+#import "UILocalNotification+APPLocalNotification.h"
+
+@interface UIApplication (APPLocalNotification)
+
+@property (readonly, getter=localNotifications) NSArray* localNotifications;
+@property (readonly, getter=localNotificationIds) NSArray* localNotificationIds;
+
+// If the app has the permission to schedule local notifications
+- (BOOL) hasPermissionToScheduleLocalNotifications;
+// Ask for permission to schedule local notifications
+- (void) registerPermissionToScheduleLocalNotifications;
+
+// List of all local notification IDs from given type
+- (NSArray*) localNotificationIdsByType:(APPLocalNotificationType)type;
+
+// If local notification with ID exists
+- (BOOL) localNotificationExist:(NSNumber*)id;
+// If local notification with ID and type exists
+- (BOOL) localNotificationExist:(NSNumber*)id type:(APPLocalNotificationType)type;
+
+// Local notification by ID
+- (UILocalNotification*) localNotificationWithId:(NSNumber*)id;
+// Local notification by ID and type
+- (UILocalNotification*) localNotificationWithId:(NSNumber*)id andType:(APPLocalNotificationType)type;
+
+// Property list from all local notifications
+- (NSArray*) localNotificationOptions;
+// Property list from given local notifications
+- (NSArray*) localNotificationOptionsById:(NSArray*)ids;
+// Property list from all local notifications with type constraint
+- (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type;
+// Property list from given local notifications with type constraint
+- (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type andId:(NSArray*)ids;
+
+// Clear single local notfications
+- (void) clearLocalNotification:(UILocalNotification*)notification;
+// Clear all local notfications
+- (void) clearAllLocalNotifications;
+
+@end
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/ios/UIApplication+APPLocalNotification.m b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/UIApplication+APPLocalNotification.m
new file mode 100644
index 00000000..60b6daac
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/UIApplication+APPLocalNotification.m
@@ -0,0 +1,331 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+#import "UIApplication+APPLocalNotification.h"
+#import "UILocalNotification+APPLocalNotification.h"
+
+@implementation UIApplication (APPLocalNotification)
+
+#pragma mark -
+#pragma mark Permissions
+
+/**
+ * If the app has the permission to schedule local notifications.
+ */
+- (BOOL) hasPermissionToScheduleLocalNotifications
+{
+ if ([[UIApplication sharedApplication]
+ respondsToSelector:@selector(registerUserNotificationSettings:)])
+ {
+ UIUserNotificationType types;
+ UIUserNotificationSettings *settings;
+
+ settings = [[UIApplication sharedApplication]
+ currentUserNotificationSettings];
+
+ types = UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound;
+
+ return (settings.types & types);
+ } else {
+ return YES;
+ }
+}
+
+/**
+ * Ask for permission to schedule local notifications.
+ */
+- (void) registerPermissionToScheduleLocalNotifications
+{
+ if ([[UIApplication sharedApplication]
+ respondsToSelector:@selector(registerUserNotificationSettings:)])
+ {
+ UIUserNotificationType types;
+ UIUserNotificationSettings *settings;
+
+ settings = [[UIApplication sharedApplication]
+ currentUserNotificationSettings];
+
+ types = settings.types|UIUserNotificationTypeAlert|UIUserNotificationTypeBadge|UIUserNotificationTypeSound;
+
+ settings = [UIUserNotificationSettings settingsForTypes:types
+ categories:nil];
+
+ [[UIApplication sharedApplication]
+ registerUserNotificationSettings:settings];
+ }
+}
+
+#pragma mark -
+#pragma mark LocalNotifications
+
+/**
+ * List of all local notifications which have been added
+ * but not yet removed from the notification center.
+ */
+- (NSArray*) localNotifications
+{
+ NSArray* scheduledNotifications = self.scheduledLocalNotifications;
+ NSMutableArray* notifications = [[NSMutableArray alloc] init];
+
+ for (UILocalNotification* notification in scheduledNotifications)
+ {
+ if (notification) {
+ [notifications addObject:notification];
+ }
+ }
+
+ return notifications;
+}
+
+/**
+ * List of all triggered local notifications which have been scheduled
+ * and not yet removed the notification center.
+ */
+- (NSArray*) triggeredLocalNotifications
+{
+ NSArray* notifications = self.localNotifications;
+ NSMutableArray* triggeredNotifications = [[NSMutableArray alloc] init];
+
+ for (UILocalNotification* notification in notifications)
+ {
+ if ([notification isTriggered]) {
+ [triggeredNotifications addObject:notification];
+ }
+ }
+
+ return triggeredNotifications;
+}
+
+/**
+ * List of all local notifications IDs.
+ */
+- (NSArray*) localNotificationIds
+{
+ NSArray* notifications = self.localNotifications;
+ NSMutableArray* ids = [[NSMutableArray alloc] init];
+
+ for (UILocalNotification* notification in notifications)
+ {
+ [ids addObject:notification.options.id];
+ }
+
+ return ids;
+}
+
+/**
+ * List of all local notifications IDs from given type.
+ *
+ * @param type
+ * Notification life cycle type
+ */
+- (NSArray*) localNotificationIdsByType:(APPLocalNotificationType)type
+{
+ NSArray* notifications = self.localNotifications;
+ NSMutableArray* ids = [[NSMutableArray alloc] init];
+
+ for (UILocalNotification* notification in notifications)
+ {
+ if (notification.type == type) {
+ [ids addObject:notification.options.id];
+ }
+ }
+
+ return ids;
+}
+
+/*
+ * If local notification with ID exists.
+ *
+ * @param id
+ * Notification ID
+ */
+- (BOOL) localNotificationExist:(NSNumber*)id
+{
+ return [self localNotificationWithId:id] != NULL;
+}
+
+/* If local notification with ID and type exists
+ *
+ * @param id
+ * Notification ID
+ * @param type
+ * Notification life cycle type
+ */
+- (BOOL) localNotificationExist:(NSNumber*)id type:(APPLocalNotificationType)type
+{
+ return [self localNotificationWithId:id andType:type] != NULL;
+}
+
+/**
+ * Get local notification with ID.
+ *
+ * @param id
+ * Notification ID
+ */
+- (UILocalNotification*) localNotificationWithId:(NSNumber*)id
+{
+ NSArray* notifications = self.localNotifications;
+
+ for (UILocalNotification* notification in notifications)
+ {
+ if ([notification.options.id isEqualToNumber:id]) {
+ return notification;
+ }
+ }
+
+ return NULL;
+}
+
+/*
+ * Get local notification with ID and type.
+ *
+ * @param id
+ * Notification ID
+ * @param type
+ * Notification life cycle type
+ */
+- (UILocalNotification*) localNotificationWithId:(NSNumber*)id andType:(APPLocalNotificationType)type
+{
+ UILocalNotification* notification = [self localNotificationWithId:id];
+
+ if (notification && notification.type == type)
+ return notification;
+
+ return NULL;
+}
+
+/**
+ * List of properties from all notifications.
+ */
+- (NSArray*) localNotificationOptions
+{
+ NSArray* notifications = self.localNotifications;
+ NSMutableArray* options = [[NSMutableArray alloc] init];
+
+ for (UILocalNotification* notification in notifications)
+ {
+ [options addObject:notification.options.userInfo];
+ }
+
+ return options;
+}
+
+/**
+ * List of properties from all local notifications from given type.
+ *
+ * @param type
+ * Notification life cycle type
+ */
+- (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type
+{
+ NSArray* notifications = self.localNotifications;
+ NSMutableArray* options = [[NSMutableArray alloc] init];
+
+ for (UILocalNotification* notification in notifications)
+ {
+ if (notification.type == type) {
+ [options addObject:notification.options.userInfo];
+ }
+ }
+
+ return options;
+}
+
+/**
+ * List of properties from given local notifications.
+ *
+ * @param ids
+ * Notification IDs
+ */
+- (NSArray*) localNotificationOptionsById:(NSArray*)ids
+{
+ UILocalNotification* notification;
+ NSMutableArray* options = [[NSMutableArray alloc] init];
+
+ for (NSNumber* id in ids)
+ {
+ notification = [self localNotificationWithId:id];
+
+ if (notification) {
+ [options addObject:notification.options.userInfo];
+ }
+ }
+
+ return options;
+}
+
+/**
+ * List of properties from given local notifications.
+ *
+ * @param type
+ * Notification life cycle type
+ * @param ids
+ * Notification IDs
+ */
+- (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type andId:(NSArray*)ids
+{
+ UILocalNotification* notification;
+ NSMutableArray* options = [[NSMutableArray alloc] init];
+
+ for (NSNumber* id in ids)
+ {
+ notification = [self localNotificationWithId:id];
+
+ if (notification && notification.type == type) {
+ [options addObject:notification.options.userInfo];
+ }
+ }
+
+ return options;
+}
+
+/*
+ * Clear all local notfications.
+ */
+- (void) clearAllLocalNotifications
+{
+ NSArray* notifications = self.triggeredLocalNotifications;
+
+ for (UILocalNotification* notification in notifications) {
+ [self clearLocalNotification:notification];
+ }
+}
+
+/*
+ * Clear single local notfication.
+ *
+ * @param notification
+ * The local notification object
+ */
+- (void) clearLocalNotification:(UILocalNotification*)notification
+{
+ [self cancelLocalNotification:notification];
+
+ if ([notification isRepeating]) {
+ notification.fireDate = notification.options.fireDate;
+
+ [self scheduleLocalNotification:notification];
+ };
+}
+
+@end
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/ios/UILocalNotification+APPLocalNotification.h b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/UILocalNotification+APPLocalNotification.h
new file mode 100644
index 00000000..ac0fdc20
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/UILocalNotification+APPLocalNotification.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+#import "APPLocalNotificationOptions.h"
+
+typedef NS_ENUM(NSUInteger, APPLocalNotificationType) {
+ NotifcationTypeAll = 0,
+ NotifcationTypeScheduled = 1,
+ NotifcationTypeTriggered = 2
+};
+
+@interface UILocalNotification (APPLocalNotification)
+
+// Initialize a new local notification
+- (id) initWithOptions:(NSDictionary*)dict;
+// The options provided by the plug-in
+- (APPLocalNotificationOptions*) options;
+// Timeinterval since last trigger date
+- (double) timeIntervalSinceLastTrigger;
+// Timeinterval since fire date
+- (double) timeIntervalSinceFireDate;
+// If the fire date was in the past
+- (BOOL) wasInThePast;
+// If the notification was already scheduled
+- (BOOL) isScheduled;
+// If the notification was already triggered
+- (BOOL) isTriggered;
+// If the notification was updated
+- (BOOL) wasUpdated;
+// If it's a repeating notification
+- (BOOL) isRepeating;
+// Notifciation type
+- (APPLocalNotificationType) type;
+// Encode the user info dict to JSON
+- (NSString*) encodeToJSON;
+
+@end
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/ios/UILocalNotification+APPLocalNotification.m b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/UILocalNotification+APPLocalNotification.m
new file mode 100644
index 00000000..d225cf52
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/ios/UILocalNotification+APPLocalNotification.m
@@ -0,0 +1,244 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+#import "UILocalNotification+APPLocalNotification.h"
+#import "APPLocalNotificationOptions.h"
+#import <objc/runtime.h>
+
+static char optionsKey;
+
+NSInteger const APPLocalNotificationTypeScheduled = 1;
+NSInteger const APPLocalNotificationTypeTriggered = 2;
+
+@implementation UILocalNotification (APPLocalNotification)
+
+#pragma mark -
+#pragma mark Init
+
+/**
+ * Initialize a local notification with the given options when calling on JS side:
+ * notification.local.add(options)
+ */
+- (id) initWithOptions:(NSDictionary*)dict
+{
+ self = [self init];
+
+ [self setUserInfo:dict];
+ [self __init];
+
+ return self;
+}
+
+/**
+ * Applies the given options when calling on JS side:
+ * notification.local.add(options)
+
+ */
+- (void) __init
+{
+ APPLocalNotificationOptions* options = self.options;
+
+ self.fireDate = options.fireDate;
+ self.timeZone = [NSTimeZone defaultTimeZone];
+ self.applicationIconBadgeNumber = options.badgeNumber;
+ self.repeatInterval = options.repeatInterval;
+ self.alertBody = options.alertBody;
+ self.soundName = options.soundName;
+
+ if ([self wasInThePast]) {
+ self.fireDate = [NSDate date];
+ }
+}
+
+#pragma mark -
+#pragma mark Methods
+
+/**
+ * The options provided by the plug-in.
+ */
+- (APPLocalNotificationOptions*) options
+{
+ APPLocalNotificationOptions* options = [self getOptions];
+
+ if (!options) {
+ options = [[APPLocalNotificationOptions alloc]
+ initWithDict:[self userInfo]];
+
+ [self setOptions:options];
+ }
+
+ return options;
+}
+
+/**
+ * Get associated option object
+ */
+- (APPLocalNotificationOptions*) getOptions
+{
+ return objc_getAssociatedObject(self, &optionsKey);
+}
+
+/**
+ * Set associated option object
+ */
+- (void) setOptions:(APPLocalNotificationOptions*)options
+{
+ objc_setAssociatedObject(self, &optionsKey,
+ options, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
+}
+
+/**
+ * The repeating interval in seconds.
+ */
+- (int) repeatIntervalInSeconds
+{
+ switch (self.repeatInterval) {
+ case NSCalendarUnitMinute:
+ return 60;
+
+ case NSCalendarUnitHour:
+ return 60000;
+
+ case NSCalendarUnitDay:
+ case NSCalendarUnitWeekOfYear:
+ case NSCalendarUnitMonth:
+ case NSCalendarUnitYear:
+ return 86400;
+
+ default:
+ return 1;
+ }
+}
+
+/**
+ * Timeinterval since fire date.
+ */
+- (double) timeIntervalSinceFireDate
+{
+ NSDate* now = [NSDate date];
+ NSDate* fireDate = self.fireDate;
+
+ int timespan = [now timeIntervalSinceDate:fireDate];
+
+ return timespan;
+}
+
+/**
+ * Timeinterval since last trigger date.
+ */
+- (double) timeIntervalSinceLastTrigger
+{
+ int timespan = [self timeIntervalSinceFireDate];
+
+ if ([self isRepeating]) {
+ timespan = timespan % [self repeatIntervalInSeconds];
+ }
+
+ return timespan;
+}
+
+/**
+ * Encode the user info dict to JSON.
+ */
+- (NSString*) encodeToJSON
+{
+ NSString* json;
+ NSData* data;
+ NSMutableDictionary* obj = [self.userInfo mutableCopy];
+
+ [obj removeObjectForKey:@"updatedAt"];
+
+ data = [NSJSONSerialization dataWithJSONObject:obj
+ options:NSJSONWritingPrettyPrinted
+ error:Nil];
+
+ json = [[NSString alloc] initWithData:data
+ encoding:NSUTF8StringEncoding];
+
+ return [json stringByReplacingOccurrencesOfString:@"\n"
+ withString:@""];
+}
+
+#pragma mark -
+#pragma mark State
+
+/**
+ * If the fire date was in the past.
+ */
+- (BOOL) wasInThePast
+{
+ return [self timeIntervalSinceLastTrigger] > 0;
+}
+
+// If the notification was already scheduled
+- (BOOL) isScheduled
+{
+ return [self isRepeating] || ![self wasInThePast];
+}
+
+/**
+ * If the notification was already triggered.
+ */
+- (BOOL) isTriggered
+{
+ NSDate* now = [NSDate date];
+ NSDate* fireDate = self.fireDate;
+
+ bool isLaterThanFireDate = !([now compare:fireDate] == NSOrderedAscending);
+
+ return isLaterThanFireDate;
+}
+
+/**
+ * If the notification was updated.
+ */
+- (BOOL) wasUpdated
+{
+ NSDate* now = [NSDate date];
+ NSDate* updatedAt = [self.userInfo objectForKey:@"updatedAt"];
+
+ if (updatedAt == NULL)
+ return NO;
+
+ int timespan = [now timeIntervalSinceDate:updatedAt];
+
+ return timespan < 1;
+}
+
+/**
+ * If it's a repeating notification.
+ */
+- (BOOL) isRepeating
+{
+ return [self.options isRepeating];
+}
+
+/**
+ * Process state type of the local notification.
+ */
+- (APPLocalNotificationType) type
+{
+ return [self isTriggered] ? NotifcationTypeTriggered : NotifcationTypeScheduled;
+}
+
+@end
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/windows/LocalNotificationCore.js b/plugins/de.appplant.cordova.plugin.local-notification/src/windows/LocalNotificationCore.js
new file mode 100644
index 00000000..f27193e1
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/windows/LocalNotificationCore.js
@@ -0,0 +1,436 @@
+/*
+ Copyright 2013-2015 appPlant UG
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+
+var proxy = require('de.appplant.cordova.plugin.local-notification.LocalNotification.Proxy');
+
+var Notifications = Windows.UI.Notifications;
+
+
+proxy.core = {
+
+ /**
+ * Executes all queued events.
+ */
+ deviceready: function () {
+ var plugin = cordova.plugins.notification.local,
+ events = this.eventQueue;
+
+ this.isReady = true;
+
+ for (var i = 0; i < events.length; i++) {
+ plugin.fireEvent.apply(plugin, events[i]);
+ }
+
+ this.eventQueue = [];
+ },
+
+ /**
+ * Schedules new local notifications.
+ *
+ * @param {Object[]} notifications
+ * Array of local notifications
+ * @param {String} event
+ * 'schedule' or 'update'
+ */
+ schedule: function (notifications) {
+ var triggerFn = function (notification) {
+ this.updateBadge(notification.badge);
+ this.fireEvent('trigger', notification);
+ };
+
+ for (var i = 0; i < notifications.length; i++) {
+ var options = notifications[i],
+ notification = this.build(options);
+
+ this.cancelLocalNotification(options.id);
+ this.scheduleLocalNotification(notification, options);
+ this.scheduleBackupNotification(notification, options);
+ this.fireEvent('schedule', options);
+ this.callOnTrigger(options, triggerFn);
+ }
+ },
+
+ /**
+ * Schedules a single local notification.
+ *
+ * @param {Windows.Data.Xml.Dom.XmlDocument} notification
+ * The local notification
+ * @param {Object} options
+ * Local notification properties
+ */
+ scheduleLocalNotification: function (notification, options) {
+ var interval = this.getRepeatInterval(options.every),
+ triggerTime = new Date((options.at * 1000)),
+ now = new Date().getTime(),
+ toast;
+
+ if (triggerTime <= now) {
+ triggerTime = new Date(now + 10);
+ }
+
+ try {
+ if (interval !== 0 && interval < 360001 && interval > 59999) {
+ toast = new Notifications.ScheduledToastNotification(
+ notification, triggerTime, interval, 5);
+ } else {
+ toast = new Notifications.ScheduledToastNotification(
+ notification, triggerTime);
+ }
+ } catch (e) {
+ console.error(e);
+ return;
+ }
+
+ toast.id = options.id;
+ toast.tag = 'Toast' + toast.id;
+
+ Notifications.ToastNotificationManager
+ .createToastNotifier()
+ .addToSchedule(toast);
+ },
+
+ /**
+ * Schedules a backup local notification 10 years later.
+ *
+ * @param {Object} notification
+ * The local notification
+ */
+ scheduleBackupNotification: function (notification, options) {
+ var properties = Object.create(options);
+
+ properties.id = options.id + '-2';
+ properties.at = options.at + 315360000; // 10 years later
+
+ this.scheduleLocalNotification(notification, properties);
+ },
+
+ /**
+ * Updates the badge number of the active tile.
+ *
+ * @param {Number} badge
+ * The badge number. Zero will clean the badge.
+ */
+ updateBadge: function (badge) {
+ var notifications = Windows.UI.Notifications,
+ type = notifications.BadgeTemplateType.badgeNumber,
+ xml = notifications.BadgeUpdateManager.getTemplateContent(type),
+ attrs = xml.getElementsByTagName('badge'),
+ notification = new notifications.BadgeNotification(xml);
+
+ attrs[0].setAttribute('value', badge);
+
+ notifications.BadgeUpdateManager.createBadgeUpdaterForApplication()
+ .update(notification);
+ },
+
+ /**
+ * Updates existing notifications specified by IDs in options.
+ *
+ * @param {Object[]} notifications
+ * Array of local notifications
+ */
+ update: function (notifications) {
+ for (var i = 0; i < notifications.length; i++) {
+ var updates = notifications[i],
+ options = getAll(updates.id || '0')[0];
+
+ this.updateLocalNotification(options, updates);
+ this.fireEvent('update', options);
+ }
+ },
+
+ /**
+ * Updates a single local notification.
+ *
+ * @param {Object} notification
+ * The local notification
+ * @param {Object} updates
+ * Updated properties
+ */
+ updateLocalNotification: function (notification, updates) {
+ for (var key in updates) {
+ notification[key] = updates[key];
+ }
+
+ this.cancelLocalNotification(notification.id);
+ this.scheduleLocalNotification(notification);
+ },
+
+ /**
+ * Clears the specified notifications.
+ *
+ * @param {int[]} ids
+ * List of local notification IDs
+ */
+ clear: function (ids) {
+ for (var i = 0; i < ids.length; i++) {
+ var id = ids[i],
+ notification = this.getAll([id])[0];
+
+ this.clearLocalNotification(id);
+ this.fireEvent('clear', notification);
+ }
+ },
+
+ /**
+ * Clears the local notification with the given ID.
+ *
+ * @param {String} id
+ * Local notification ID
+ */
+ clearLocalNotification: function (id) {
+ var notification = this.getAll([id])[0];
+
+ try {
+ this.getToastHistory().remove('Toast' + id);
+ } catch (e) {/*Only Phones support the NotificationHistory*/ }
+
+ if (this.isRepeating(notification))
+ return;
+
+ if (this.isTriggered(id) && !this.isScheduled(id)) {
+ this.cancelLocalNotification(id);
+ }
+ },
+
+ /**
+ * Clears all notifications.
+ */
+ clearAll: function () {
+ var ids = this.getTriggeredIds();
+
+ for (var i = 0; i < ids.length; i++) {
+ this.clearLocalNotification(ids[i]);
+ }
+
+ try {
+ this.getToastHistory().clear();
+ } catch (e) {/*Only Phones support the NotificationHistory*/ }
+ this.fireEvent('clearall');
+ },
+
+ /**
+ * Cancels all specified notifications.
+ *
+ * @param {int[]} ids
+ * List of local notification IDs
+ */
+ cancel: function (ids) {
+ for (var i = 0; i < ids.length; i++) {
+ var id = ids[i],
+ notification = this.getAll([id])[0];
+
+ this.cancelLocalNotification(ids[i]);
+ this.fireEvent('cancel', notification);
+ }
+ },
+
+ /**
+ * Cancels the local notification with the given ID.
+ *
+ * @param {String} id
+ * Local notification ID
+ */
+ cancelLocalNotification: function (id) {
+ var notifier = this.getToastNotifier(),
+ history = this.getToastHistory(),
+ toasts = this.getScheduledToasts();
+
+ try {
+ history.remove('Toast' + id);
+ } catch (e) {/*Only Phones support the NotificationHistory*/ }
+
+ for (var i = 0; i < toasts.length; i++) {
+ var toast = toasts[i];
+
+ if (toast.id == id || toast.id == id + '-2') {
+ notifier.removeFromSchedule(toast);
+ }
+ }
+ },
+
+ /**
+ * Cancels all notifications.
+ */
+ cancelAll: function () {
+ var ids = this.getAllIds();
+
+ for (var i = 0; i < ids.length; i++) {
+ this.cancelLocalNotification(ids[i]);
+ }
+
+ try {
+ this.getToastHistory().clear();
+ } catch (e) {/*Only Phones support the NotificationHistory*/ }
+ this.fireEvent('cancelall');
+ },
+
+ /**
+ * Checks if a notification with an ID is present.
+ *
+ * @param {int} id
+ * Local notification ID
+ */
+ isPresent: function (id) {
+ return !!this.findToastById(id);
+ },
+
+ /**
+ * Checks if a notification with an ID was scheduled.
+ *
+ * @param {int} id
+ * Local notification ID
+ */
+ isScheduled: function (id) {
+ var toast = this.findToastById(id);
+
+ return toast && this.isToastScheduled(toast);
+ },
+
+ /**
+ * Checks if a notification with an ID was triggered.
+ *
+ * @param {int} id
+ * Local notification ID
+ */
+ isTriggered: function (id) {
+ var toast = this.findToastById(id);
+
+ return toast && this.isToastTriggered(toast);
+ },
+
+ /**
+ * Lists all local notification IDs.
+ */
+ getAllIds: function () {
+ var toasts = this.getScheduledToasts(),
+ ids = [];
+
+ for (var i = 0; i < toasts.length; i++) {
+ var toast = toasts[i];
+
+ ids.push(this.getToastId(toast));
+ }
+
+ return ids;
+ },
+
+ /**
+ * Lists all scheduled notification IDs.
+ */
+ getScheduledIds: function () {
+ var toasts = this.getScheduledToasts(),
+ ids = [];
+
+ for (var i = 0; i < toasts.length; i++) {
+ var toast = toasts[i];
+
+ if (!this.isToastScheduled(toast))
+ continue;
+
+ ids.push(this.getToastId(toast));
+ }
+
+ return ids;
+ },
+
+ /**
+ * Lists all scheduled notification IDs.
+ */
+ getTriggeredIds: function () {
+ var toasts = this.getScheduledToasts(),
+ ids = [];
+
+ for (var i = 0; i < toasts.length; i++) {
+ var toast = toasts[i];
+
+ if (!this.isToastTriggered(toast))
+ continue;
+
+ ids.push(this.getToastId(toast));
+ }
+
+ return ids;
+ },
+
+ /**
+ * Property list for given notifications.
+ * If called without IDs, all notification will be returned.
+ *
+ * @param {int[]} ids
+ * List of local notification IDs.
+ * @param {String?} type
+ * Local notification life cycle type
+ */
+ getAll: function (ids, type) {
+ var toasts = this.getScheduledToasts(),
+ notifications = [];
+
+ if (!ids || ids.length === 0) {
+ ids = this.getAllIds();
+ }
+
+ for (var index = 0; index < ids.length; index++) {
+ var id = ids[index],
+ toast = this.findToastById(id);
+
+ if (!toast || type && this.getToastType(toast) != type)
+ continue;
+
+ var json = toast.content.lastChild.lastChild.innerText;
+
+ notifications.push(JSON.parse(json));
+ }
+
+ return notifications;
+ },
+
+ /**
+ * Property list for given notifications.
+ * If called without IDs, all notification will be returned.
+ *
+ * @param {int[]} ids
+ * List of local notification IDs
+ */
+ getScheduled: function (ids) {
+ if (!ids || ids.length === 0) {
+ ids = this.getAllIds();
+ }
+
+ return this.getAll(ids, 'scheduled');
+ },
+
+ /**
+ * Property list for given notifications.
+ * If called without IDs, all notification will be returned.
+ *
+ * @param {int[]} ids
+ * List of local notification IDs
+ */
+ getTriggered: function (ids) {
+ if (!ids || ids.length === 0) {
+ ids = this.getAllIds();
+ }
+
+ return this.getAll(ids, 'triggered');
+ },
+};
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/windows/LocalNotificationProxy.js b/plugins/de.appplant.cordova.plugin.local-notification/src/windows/LocalNotificationProxy.js
new file mode 100644
index 00000000..2f7ed3d7
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/windows/LocalNotificationProxy.js
@@ -0,0 +1,311 @@
+/*
+ Copyright 2013-2015 appPlant UG
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+/**
+ * Executes all queued events.
+ */
+exports.deviceready = function () {
+ exports.core.deviceready();
+};
+
+/**
+ * Schedule a new local notification.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {Object[]} notifications
+ * Array of local notifications
+ */
+exports.schedule = function (success, error, notifications) {
+ exports.core.schedule(notifications, 'schedule');
+
+ success();
+};
+
+/**
+ * Update existing notifications specified by IDs in options.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {Object[]} notifications
+ * Array of local notifications
+ */
+exports.update = function (success, error, notifications) {
+ exports.core.update(notifications);
+
+ success();
+};
+
+/**
+ * Clear the specified notification.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {int[]} ids
+ * List of local notification IDs
+ */
+exports.clear = function (success, error, ids) {
+ exports.core.clear(ids, true);
+
+ success();
+};
+
+/**
+ * Clear all previously sheduled notifications.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ */
+exports.clearAll = function (success, error) {
+ exports.core.clearAll();
+
+ success();
+};
+
+/**
+ * Cancel the specified notifications.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {int[]} ids
+ * List of local notification IDs
+ */
+exports.cancel = function (success, error, ids) {
+ exports.core.cancel(ids, true);
+
+ success();
+};
+
+/**
+ * Remove all previously registered notifications.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ */
+exports.cancelAll = function (success, error) {
+ exports.core.cancelAll();
+
+ success();
+};
+
+/**
+ * Check if a notification with an ID is present.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {int} id
+ * Local notification ID
+ */
+exports.isPresent = function (success, error, args) {
+ var found = exports.core.isPresent(args[0]);
+
+ success(found);
+};
+
+/**
+ * Check if a notification with an ID is scheduled.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {int} id
+ * Local notification ID
+ */
+exports.isScheduled = function (success, error, args) {
+ var found = exports.core.isScheduled(args[0]);
+
+ success(found);
+};
+
+/**
+ * Check if a notification with an ID was triggered.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {int} id
+ * Local notification ID
+ */
+exports.isTriggered = function (success, error, args) {
+ var found = exports.core.isTriggered(args[0]);
+
+ success(found);
+};
+
+/**
+ * List all local notification IDs.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ */
+exports.getAllIds = function (success, error) {
+ var ids = exports.core.getAllIds();
+
+ success(ids);
+};
+
+/**
+ * List all scheduled notification IDs.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ */
+exports.getScheduledIds = function (success, error) {
+ var ids = exports.core.getScheduledIds();
+
+ success(ids);
+};
+
+/**
+ * List all triggered notification IDs.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ */
+exports.getTriggeredIds = function (success, error) {
+ var ids = exports.core.getTriggeredIds();
+
+ success(ids);
+};
+
+/**
+ * Propertys for given notification.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {int[]} ids
+ * List of local notification IDs
+ */
+exports.getSingle = function (success, error, ids) {
+ var notification = exports.core.getAll(ids)[0];
+
+ success(notification);
+};
+
+/**
+ * Propertys for given scheduled notification.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {int[]} ids
+ * List of local notification IDs
+ */
+exports.getSingleScheduled = function (success, error, ids) {
+ var notification = exports.core.getScheduled(ids)[0];
+
+ success(notification);
+};
+
+/**
+ * Propertys for given triggered notification.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {int[]} ids
+ * List of local notification IDs
+ */
+exports.getSingleTriggered = function (success, error, ids) {
+ var notification = exports.core.getTriggered(ids)[0];
+
+ success(notification);
+};
+
+/**
+ * Property list for given notifications.
+ * If called without IDs, all notification will be returned.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {int[]} ids
+ * List of local notification IDs
+ */
+exports.getAll = function (success, error, ids) {
+ var notifications = exports.core.getAll(ids);
+
+ success(notifications);
+};
+
+/**
+ * Property list for given triggered notifications.
+ * If called without IDs, all notification will be returned.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {int[]} ids
+ * List of local notification IDs
+ */
+exports.getScheduled = function (success, error, ids) {
+ var notifications = exports.core.getScheduled(ids);
+
+ success(notifications);
+};
+
+/**
+ * Property list for given triggered notifications.
+ * If called without IDs, all notification will be returned.
+ *
+ * @param {Function} success
+ * Success callback
+ * @param {Function} error
+ * Error callback
+ * @param {int[]} ids
+ * List of local notification IDs
+ */
+exports.getTriggered = function (success, error, ids) {
+ var notifications = exports.core.getTriggered(ids);
+
+ success(notifications);
+};
+
+
+cordova.commandProxy.add('LocalNotification', exports);
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/src/windows/LocalNotificationUtil.js b/plugins/de.appplant.cordova.plugin.local-notification/src/windows/LocalNotificationUtil.js
new file mode 100644
index 00000000..4081a0b8
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/src/windows/LocalNotificationUtil.js
@@ -0,0 +1,443 @@
+/*
+ Copyright 2013-2015 appPlant UG
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+*/
+
+
+exports = require('de.appplant.cordova.plugin.local-notification.LocalNotification.Proxy').core;
+
+var channel = require('cordova/channel');
+
+
+/***********
+ * MEMBERS *
+ ***********/
+
+// True if App is running, false if suspended
+exports.isInBackground = true;
+
+// Indicates if the device is ready (to receive events)
+exports.isReady = false;
+
+// Queues all events before deviceready
+exports.eventQueue = [];
+
+/********
+ * UTIL *
+ ********/
+
+/**
+ * The repeating interval in milliseconds.
+ *
+ * @param {String} interval
+ * A number or a placeholder like `minute`.
+ *
+ * @return {Number}
+ * Interval in milliseconds
+ */
+exports.getRepeatInterval = function (every) {
+
+ if (!every)
+ return 0;
+
+ if (every == 'minute')
+ return 60000;
+
+ if (every == 'hour')
+ return 360000;
+
+ if (!NaN(every))
+ return parseInt(every) * 60000;
+
+ return 0;
+};
+
+/**
+ * If the notification is repeating.
+ *
+ * @param {Object} notification
+ * Local notification object
+ *
+ * @return Boolean
+ */
+exports.isRepeating = function (notification) {
+ return this.getRepeatInterval(notification.every) !== 0;
+};
+
+/**
+ * Parses sound file path.
+ *
+ * @param {String} path
+ * Relative path to sound resource
+ *
+ * @return {String} XML Tag for Sound-File
+ */
+exports.parseSound = function (path) {
+ if (!path.match(/^file/))
+ return '';
+
+ var uri = this.parseUri(path),
+ audio = "<audio src=" + uri + " loop='false'/>";
+
+ return audio;
+};
+
+/**
+ * Parses image file path.
+ *
+ * @param {String} path
+ * Relative path to image resource
+ *
+ * @return {String} XML-Tag for Image-File
+ */
+exports.parseImage = function (path) {
+ if (!path.match(/^file/))
+ return '';
+
+ var uri = this.parseUri(path),
+ image = "<image id='1' src=" + uri + " />";
+
+ return image;
+};
+
+/**
+ * Parses file path to URI.
+ *
+ * @param {String} path
+ * Relative path to a resource
+ *
+ * @return {String} URI to File
+ */
+exports.parseUri = function (path) {
+ var pkg = Windows.ApplicationModel.Package.current,
+ pkgId = pkg.id,
+ pkgName = pkgId.name;
+
+ var uri = "'ms-appx://" + pkgName + "/www" + path.slice(6, path.length) + "'";
+
+ return uri;
+};
+
+/**
+ * Builds the xml payload for a local notification based on its options.
+ *
+ * @param {Object} options
+ * Local notification properties
+ *
+ * @return Windows.Data.Xml.Dom.XmlDocument
+ */
+exports.build = function (options) {
+ var template = this.buildToastTemplate(options),
+ notification = new Windows.Data.Xml.Dom.XmlDocument();
+
+ try {
+ notification.loadXml(template);
+ } catch (e) {
+ console.error(
+ 'LocalNotification#schedule',
+ 'Error loading the xml, check for invalid characters.');
+ }
+
+ // Launch Attribute to enable onClick event
+ var launchAttr = notification.createAttribute('launch'),
+ toastNode = notification.selectSingleNode('/toast');
+
+ launchAttr.value = options.id.toString();
+ toastNode.attributes.setNamedItem(launchAttr);
+
+ return notification;
+};
+
+/**
+ * Builds the toast template with the right style depend on the options.
+ *
+ * @param {Object} options
+ * Local notification properties
+ *
+ * @return String
+ */
+exports.buildToastTemplate = function (options) {
+ var title = options.title,
+ message = options.text || '',
+ json = JSON.stringify(options),
+ sound = '';
+
+ if (options.sound && options.sound !== '') {
+ sound = this.parseSound(options.sound);
+ }
+
+ var templateName = "ToastText",
+ imageNode;
+ if (options.icon && options.icon !== '') {
+ imageNode = this.parseImage(options.icon);
+ // template with Image
+ if (imageNode !== '') {
+ templateName = "ToastImageAndText";
+ }
+ } else {
+ imageNode = "";
+ }
+
+ var bindingNode;
+ if (title && title !== '') {
+ bindingNode = "<binding template='" + templateName + "02'>" +
+ imageNode +
+ "<text id='1'>" + title + "</text>" +
+ "<text id='2'>" + message + "</text>" +
+ "</binding>";
+ } else {
+ bindingNode = "<binding template='" + templateName + "01'>" +
+ imageNode +
+ "<text id='1'>" + message + "</text>" +
+ "</binding>";
+ }
+ return "<toast>" +
+ "<visual>" +
+ bindingNode +
+ "</visual>" +
+ sound +
+ "<json>" + json + "</json>" +
+ "</toast>";
+};
+
+/**
+ * Short-hand method for the toast notification history.
+ */
+exports.getToastHistory = function () {
+ return Windows.UI.Notifications.ToastNotificationManager.history;
+};
+
+/**
+ * Gets a toast notifier instance.
+ *
+ * @return Object
+ */
+exports.getToastNotifier = function () {
+ return Windows.UI.Notifications.ToastNotificationManager
+ .createToastNotifier();
+};
+
+/**
+ * List of all scheduled toast notifiers.
+ *
+ * @return Array
+ */
+exports.getScheduledToasts = function () {
+ return this.getToastNotifier().getScheduledToastNotifications();
+};
+
+/**
+ * Gets the Id from the toast notifier.
+ *
+ * @param {Object} toast
+ * A toast notifier object
+ *
+ * @return String
+ */
+exports.getToastId = function (toast) {
+ var id = toast.id;
+
+ if (id.match(/-2$/))
+ return id.match(/^[^-]+/)[0];
+
+ return id;
+};
+
+/**
+ * Gets the notification life cycle type
+ * (scheduled or triggered)
+ *
+ * @param {Object} toast
+ * A toast notifier object
+ *
+ * @return String
+ */
+exports.getToastType = function (toast) {
+ return this.isToastTriggered(toast) ? 'triggered' : 'scheduled';
+};
+
+/**
+ * If the toast is already scheduled.
+ *
+ * @param {Object} toast
+ * A toast notifier object
+ *
+ * @return Boolean
+ */
+exports.isToastScheduled = function (toast) {
+ return !this.isToastTriggered(toast);
+};
+
+/**
+ * If the toast is already triggered.
+ *
+ * @param {Object} toast
+ * A toast notifier object
+ *
+ * @return Boolean
+ */
+exports.isToastTriggered = function (toast) {
+ var id = this.getToastId(toast),
+ notification = this.getAll([id])[0],
+ fireDate = new Date((notification.at) * 1000);
+
+ if (this.isRepeating(notification))
+ return false;
+
+ return fireDate <= new Date();
+};
+
+/**
+ * Finds the toast by it's ID.
+ *
+ * @param {String} id
+ * Local notification ID
+ *
+ * @param Object
+ */
+exports.findToastById = function (id) {
+ var toasts = this.getScheduledToasts();
+
+ for (var i = 0; i < toasts.length; i++) {
+ var toast = toasts[i];
+
+ if (this.getToastId(toast) == id)
+ return toast;
+ }
+
+ return null;
+};
+
+/**
+ * Sets trigger event for local notification.
+ *
+ * @param {Object} notification
+ * Local notification object
+ * @param {Function} callback
+ * Callback function
+ */
+exports.callOnTrigger = function (notification, callback) {
+ var triggerTime = new Date((notification.at * 1000)),
+ interval = triggerTime - new Date();
+
+ if (interval <= 0) {
+ callback.call(this, notification);
+ return;
+ }
+
+ WinJS.Promise.timeout(interval).then(function () {
+ if (exports.isPresent(notification.id)) {
+ callback.call(exports, notification);
+ }
+ });
+};
+
+/**
+ * Sets trigger event for all scheduled local notification.
+ *
+ * @param {Function} callback
+ * Callback function
+ */
+exports.callOnTriggerForScheduled = function (callback) {
+ var notifications = this.getScheduled();
+
+ for (var i = 0; i < notifications.length; i++) {
+ this.callOnTrigger(notifications[i], callback);
+ }
+};
+
+/**
+ * The application state - background or foreground.
+ *
+ * @return String
+ */
+exports.getApplicationState = function () {
+ return this.isInBackground ? 'background' : 'foreground';
+};
+
+/**
+ * Fires the event about a local notification.
+ *
+ * @param {String} event
+ * The event
+ * @param {Object} notification
+ * The notification
+ */
+exports.fireEvent = function (event, notification) {
+ var plugin = cordova.plugins.notification.local.core,
+ state = this.getApplicationState(),
+ args;
+
+ if (notification) {
+ args = [event, notification, state];
+ } else {
+ args = [event, state];
+ }
+
+ if (this.isReady && plugin) {
+ plugin.fireEvent.apply(plugin, args);
+ } else {
+ this.eventQueue.push(args);
+ }
+};
+
+
+/**************
+ * LIFE CYCLE *
+ **************/
+
+// Called before 'deviceready' event
+channel.onCordovaReady.subscribe(function () {
+ // Register trigger handler for each scheduled notification
+ exports.callOnTriggerForScheduled(function (notification) {
+ this.updateBadge(notification.badge);
+ this.fireEvent('trigger', notification);
+ });
+});
+
+// Handle onclick event
+WinJS.Application.addEventListener('activated', function (args) {
+ var id = args.detail.arguments,
+ notification = exports.getAll([id])[0];
+
+ if (!notification)
+ return;
+
+ exports.clearLocalNotification(id);
+
+ var repeating = exports.isRepeating(notification);
+
+ exports.fireEvent('click', notification);
+ exports.fireEvent(repeating ? 'clear' : 'cancel', notification);
+}, false);
+
+// App is running in background
+document.addEventListener('pause', function () {
+ exports.isInBackground = true;
+}, false);
+
+// App is running in foreground
+document.addEventListener('resume', function () {
+ exports.isInBackground = false;
+}, false);
+
+// App is running in foreground
+document.addEventListener('deviceready', function () {
+ exports.isInBackground = false;
+}, false);
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/www/local-notification-core.js b/plugins/de.appplant.cordova.plugin.local-notification/www/local-notification-core.js
new file mode 100644
index 00000000..03faa834
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/www/local-notification-core.js
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+var exec = require('cordova/exec');
+
+
+/********
+ * CORE *
+ ********/
+
+/**
+ * Returns the default settings.
+ *
+ * @return {Object}
+ */
+exports.getDefaults = function () {
+ return this._defaults;
+};
+
+/**
+ * Overwrite default settings.
+ *
+ * @param {Object} defaults
+ */
+exports.setDefaults = function (newDefaults) {
+ var defaults = this.getDefaults();
+
+ for (var key in defaults) {
+ if (newDefaults.hasOwnProperty(key)) {
+ defaults[key] = newDefaults[key];
+ }
+ }
+};
+
+/**
+ * Schedule a new local notification.
+ *
+ * @param {Object} opts
+ * The notification properties
+ * @param {Function} callback
+ * A function to be called after the notification has been canceled
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.schedule = function (opts, callback, scope) {
+ this.registerPermission(function(granted) {
+
+ if (!granted)
+ return;
+
+ var notifications = Array.isArray(opts) ? opts : [opts];
+
+ for (var i = 0; i < notifications.length; i++) {
+ var properties = notifications[i];
+
+ this.mergeWithDefaults(properties);
+ this.convertProperties(properties);
+ }
+
+ this.exec('schedule', notifications, callback, scope);
+ }, this);
+};
+
+/**
+ * Update existing notifications specified by IDs in options.
+ *
+ * @param {Object} options
+ * The notification properties to update
+ * @param {Function} callback
+ * A function to be called after the notification has been updated
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.update = function (opts, callback, scope) {
+ var notifications = Array.isArray(opts) ? opts : [opts];
+
+ for (var i = 0; i < notifications.length; i++) {
+ var properties = notifications[i];
+
+ this.convertProperties(properties);
+ }
+
+ this.exec('update', notifications, callback, scope);
+};
+
+/**
+ * Clear the specified notification.
+ *
+ * @param {String} id
+ * The ID of the notification
+ * @param {Function} callback
+ * A function to be called after the notification has been cleared
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.clear = function (ids, callback, scope) {
+ ids = Array.isArray(ids) ? ids : [ids];
+ ids = this.convertIds(ids);
+
+ this.exec('clear', ids, callback, scope);
+};
+
+/**
+ * Clear all previously sheduled notifications.
+ *
+ * @param {Function} callback
+ * A function to be called after all notifications have been cleared
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.clearAll = function (callback, scope) {
+ this.exec('clearAll', null, callback, scope);
+};
+
+/**
+ * Cancel the specified notifications.
+ *
+ * @param {String[]} ids
+ * The IDs of the notifications
+ * @param {Function} callback
+ * A function to be called after the notifications has been canceled
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.cancel = function (ids, callback, scope) {
+ ids = Array.isArray(ids) ? ids : [ids];
+ ids = this.convertIds(ids);
+
+ this.exec('cancel', ids, callback, scope);
+};
+
+/**
+ * Remove all previously registered notifications.
+ *
+ * @param {Function} callback
+ * A function to be called after all notifications have been canceled
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.cancelAll = function (callback, scope) {
+ this.exec('cancelAll', null, callback, scope);
+};
+
+/**
+ * Check if a notification with an ID is present.
+ *
+ * @param {String} id
+ * The ID of the notification
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.isPresent = function (id, callback, scope) {
+ this.exec('isPresent', id || 0, callback, scope);
+};
+
+/**
+ * Check if a notification with an ID is scheduled.
+ *
+ * @param {String} id
+ * The ID of the notification
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.isScheduled = function (id, callback, scope) {
+ this.exec('isScheduled', id || 0, callback, scope);
+};
+
+/**
+ * Check if a notification with an ID was triggered.
+ *
+ * @param {String} id
+ * The ID of the notification
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.isTriggered = function (id, callback, scope) {
+ this.exec('isTriggered', id || 0, callback, scope);
+};
+
+/**
+ * List all local notification IDs.
+ *
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getAllIds = function (callback, scope) {
+ this.exec('getAllIds', null, callback, scope);
+};
+
+/**
+ * Alias for `getAllIds`.
+ */
+exports.getIds = function () {
+ this.getAllIds.apply(this, arguments);
+};
+
+/**
+ * List all scheduled notification IDs.
+ *
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getScheduledIds = function (callback, scope) {
+ this.exec('getScheduledIds', null, callback, scope);
+};
+
+/**
+ * List all triggered notification IDs.
+ *
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getTriggeredIds = function (callback, scope) {
+ this.exec('getTriggeredIds', null, callback, scope);
+};
+
+/**
+ * Property list for given local notifications.
+ * If called without IDs, all notification will be returned.
+ *
+ * @param {Number[]?} ids
+ * Set of notification IDs
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.get = function () {
+ var args = Array.apply(null, arguments);
+
+ if (typeof args[0] == 'function') {
+ args.unshift([]);
+ }
+
+ var ids = args[0],
+ callback = args[1],
+ scope = args[2];
+
+ if (!Array.isArray(ids)) {
+ this.exec('getSingle', Number(ids), callback, scope);
+ return;
+ }
+
+ ids = this.convertIds(ids);
+
+ this.exec('getAll', ids, callback, scope);
+};
+
+/**
+ * Property list for all local notifications.
+ *
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getAll = function (callback, scope) {
+ this.exec('getAll', null, callback, scope);
+};
+
+/**
+ * Property list for given scheduled notifications.
+ * If called without IDs, all notification will be returned.
+ *
+ * @param {Number[]?} ids
+ * Set of notification IDs
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getScheduled = function () {
+ var args = Array.apply(null, arguments);
+
+ if (typeof args[0] == 'function') {
+ args.unshift([]);
+ }
+
+ var ids = args[0],
+ callback = args[1],
+ scope = args[2];
+
+ if (!Array.isArray(ids)) {
+ ids = [ids];
+ }
+
+ if (!Array.isArray(ids)) {
+ this.exec('getSingleScheduled', Number(ids), callback, scope);
+ return;
+ }
+
+ ids = this.convertIds(ids);
+
+ this.exec('getScheduled', ids, callback, scope);
+};
+
+/**
+ * Property list for all scheduled notifications.
+ *
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getAllScheduled = function (callback, scope) {
+ this.exec('getScheduled', null, callback, scope);
+};
+
+/**
+ * Property list for given triggered notifications.
+ * If called without IDs, all notification will be returned.
+ *
+ * @param {Number[]?} ids
+ * Set of notification IDs
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getTriggered = function () {
+ var args = Array.apply(null, arguments);
+
+ if (typeof args[0] == 'function') {
+ args.unshift([]);
+ }
+
+ var ids = args[0],
+ callback = args[1],
+ scope = args[2];
+
+ if (!Array.isArray(ids)) {
+ ids = [ids];
+ }
+
+ if (!Array.isArray(ids)) {
+ this.exec('getSingleTriggered', Number(ids), callback, scope);
+ return;
+ }
+
+ ids = this.convertIds(ids);
+
+ this.exec('getTriggered', ids, callback, scope);
+};
+
+/**
+ * Property list for all triggered notifications.
+ *
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getAllTriggered = function (callback, scope) {
+ this.exec('getTriggered', null, callback, scope);
+};
+
+/**
+ * Informs if the app has the permission to show notifications.
+ *
+ * @param {Function} callback
+ * The function to be exec as the callback
+ * @param {Object?} scope
+ * The callback function's scope
+ */
+exports.hasPermission = function (callback, scope) {
+ var fn = this.createCallbackFn(callback, scope);
+
+ if (device.platform != 'iOS') {
+ fn(true);
+ return;
+ }
+
+ exec(fn, null, 'LocalNotification', 'hasPermission', []);
+};
+
+/**
+ * Register permission to show notifications if not already granted.
+ *
+ * @param {Function} callback
+ * The function to be exec as the callback
+ * @param {Object?} scope
+ * The callback function's scope
+ */
+exports.registerPermission = function (callback, scope) {
+ var fn = this.createCallbackFn(callback, scope);
+
+ if (device.platform != 'iOS') {
+ fn(true);
+ return;
+ }
+
+ exec(fn, null, 'LocalNotification', 'registerPermission', []);
+};
+
+
+/**********
+ * EVENTS *
+ **********/
+
+/**
+ * Register callback for given event.
+ *
+ * @param {String} event
+ * The event's name
+ * @param {Function} callback
+ * The function to be exec as callback
+ * @param {Object?} scope
+ * The callback function's scope
+ */
+exports.on = function (event, callback, scope) {
+
+ if (!this._listener[event]) {
+ this._listener[event] = [];
+ }
+
+ var item = [callback, scope || window];
+
+ this._listener[event].push(item);
+};
+
+/**
+ * Unregister callback for given event.
+ *
+ * @param {String} event
+ * The event's name
+ * @param {Function} callback
+ * The function to be exec as callback
+ */
+exports.un = function (event, callback) {
+ var listener = this._listener[event];
+
+ if (!listener)
+ return;
+
+ for (var i = 0; i < listener.length; i++) {
+ var fn = listener[i][0];
+
+ if (fn == callback) {
+ listener.splice(i, 1);
+ break;
+ }
+ }
+};
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/www/local-notification-util.js b/plugins/de.appplant.cordova.plugin.local-notification/www/local-notification-util.js
new file mode 100644
index 00000000..7e96b64c
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/www/local-notification-util.js
@@ -0,0 +1,299 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+var exec = require('cordova/exec'),
+ channel = require('cordova/channel');
+
+
+/***********
+ * MEMBERS *
+ ***********/
+
+// Default values
+exports._defaults = {
+ text: '',
+ title: '',
+ sound: 'res://platform_default',
+ badge: 0,
+ id: 0,
+ data: undefined,
+ every: undefined,
+ at: undefined
+};
+
+// listener
+exports._listener = {};
+
+
+/********
+ * UTIL *
+ ********/
+
+/**
+ * Merge platform specific properties into the default ones.
+ *
+ * @return {Object}
+ * The default properties for the platform
+ */
+exports.applyPlatformSpecificOptions = function () {
+ var defaults = this._defaults;
+
+ switch (device.platform) {
+ case 'Android':
+ defaults.icon = 'res://icon';
+ defaults.smallIcon = 'res://ic_popup_reminder';
+ defaults.ongoing = false;
+ defaults.autoClear = true;
+ defaults.led = 'FFFFFF';
+ break;
+ }
+
+ return defaults;
+};
+
+/**
+ * Merge custom properties with the default values.
+ *
+ * @param {Object} options
+ * Set of custom values
+ *
+ * @retrun {Object}
+ * The merged property list
+ */
+exports.mergeWithDefaults = function (options) {
+ var defaults = this.getDefaults();
+
+ options.at = this.getValueFor(options, 'at', 'firstAt', 'date');
+ options.text = this.getValueFor(options, 'text', 'message');
+ options.data = this.getValueFor(options, 'data', 'json');
+
+ if (defaults.hasOwnProperty('autoClear')) {
+ options.autoClear = this.getValueFor(options, 'autoClear', 'autoCancel');
+ }
+
+ if (options.autoClear !== true && options.ongoing) {
+ options.autoClear = false;
+ }
+
+ if (options.at === undefined || options.at === null) {
+ options.at = new Date();
+ }
+
+ for (var key in defaults) {
+ if (options[key] === null || options[key] === undefined) {
+ if (options.hasOwnProperty(key) && ['data','sound'].indexOf(key) > -1) {
+ options[key] = undefined;
+ } else {
+ options[key] = defaults[key];
+ }
+ }
+ }
+
+ for (key in options) {
+ if (!defaults.hasOwnProperty(key)) {
+ delete options[key];
+ console.warn('Unknown property: ' + key);
+ }
+ }
+
+ return options;
+};
+
+/**
+ * Convert the passed values to their required type.
+ *
+ * @param {Object} options
+ * Set of custom values
+ *
+ * @retrun {Object}
+ * The converted property list
+ */
+exports.convertProperties = function (options) {
+
+ if (options.id) {
+ if (isNaN(options.id)) {
+ options.id = this.getDefaults().id;
+ console.warn('Id is not a number: ' + options.id);
+ } else {
+ options.id = Number(options.id);
+ }
+ }
+
+ if (options.title) {
+ options.title = options.title.toString();
+ }
+
+ if (options.text) {
+ options.text = options.text.toString();
+ }
+
+ if (options.badge) {
+ if (isNaN(options.badge)) {
+ options.badge = this.getDefaults().badge;
+ console.warn('Badge number is not a number: ' + options.id);
+ } else {
+ options.badge = Number(options.badge);
+ }
+ }
+
+ if (options.at) {
+ if (typeof options.at == 'object') {
+ options.at = options.at.getTime();
+ }
+
+ options.at = Math.round(options.at/1000);
+ }
+
+ if (typeof options.data == 'object') {
+ options.data = JSON.stringify(options.data);
+ }
+
+ return options;
+};
+
+/**
+ * Create callback, which will be executed within a specific scope.
+ *
+ * @param {Function} callbackFn
+ * The callback function
+ * @param {Object} scope
+ * The scope for the function
+ *
+ * @return {Function}
+ * The new callback function
+ */
+exports.createCallbackFn = function (callbackFn, scope) {
+
+ if (typeof callbackFn != 'function')
+ return;
+
+ return function () {
+ callbackFn.apply(scope || this, arguments);
+ };
+};
+
+/**
+ * Convert the IDs to numbers.
+ *
+ * @param {String/Number[]} ids
+ *
+ * @return Array of Numbers
+ */
+exports.convertIds = function (ids) {
+ var convertedIds = [];
+
+ for (var i = 0; i < ids.length; i++) {
+ convertedIds.push(Number(ids[i]));
+ }
+
+ return convertedIds;
+};
+
+/**
+ * First found value for the given keys.
+ *
+ * @param {Object} options
+ * Object with key-value properties
+ * @param {String[]} keys*
+ * Key list
+ */
+exports.getValueFor = function (options) {
+ var keys = Array.apply(null, arguments).slice(1);
+
+ for (var i = 0; i < keys.length; i++) {
+ var key = keys[i];
+
+ if (options.hasOwnProperty(key)) {
+ return options[key];
+ }
+ }
+};
+
+/**
+ * Fire event with given arguments.
+ *
+ * @param {String} event
+ * The event's name
+ * @param {args*}
+ * The callback's arguments
+ */
+exports.fireEvent = function (event) {
+ var args = Array.apply(null, arguments).slice(1),
+ listener = this._listener[event];
+
+ if (!listener)
+ return;
+
+ for (var i = 0; i < listener.length; i++) {
+ var fn = listener[i][0],
+ scope = listener[i][1];
+
+ fn.apply(scope, args);
+ }
+};
+
+/**
+ * Execute the native counterpart.
+ *
+ * @param {String} action
+ * The name of the action
+ * @param args[]
+ * Array of arguments
+ * @param {Function} callback
+ * The callback function
+ * @param {Object} scope
+ * The scope for the function
+ */
+exports.exec = function (action, args, callback, scope) {
+ var fn = this.createCallbackFn(callback, scope),
+ params = [];
+
+ if (Array.isArray(args)) {
+ params = args;
+ } else if (args) {
+ params.push(args);
+ }
+
+ exec(fn, null, 'LocalNotification', action, params);
+};
+
+
+/*********
+ * HOOKS *
+ *********/
+
+// Called after 'deviceready' event
+channel.deviceready.subscribe(function () {
+ // Device is ready now, the listeners are registered
+ // and all queued events can be executed.
+ exec(null, null, 'LocalNotification', 'deviceready', []);
+});
+
+// Called before 'deviceready' event
+channel.onCordovaReady.subscribe(function () {
+ // Device plugin is ready now
+ channel.onCordovaInfoReady.subscribe(function () {
+ // Merge platform specifics into defaults
+ exports.applyPlatformSpecificOptions();
+ });
+});
diff --git a/plugins/de.appplant.cordova.plugin.local-notification/www/local-notification.js b/plugins/de.appplant.cordova.plugin.local-notification/www/local-notification.js
new file mode 100644
index 00000000..9e9bd284
--- /dev/null
+++ b/plugins/de.appplant.cordova.plugin.local-notification/www/local-notification.js
@@ -0,0 +1,370 @@
+/*
+ * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
+ *
+ * @APPPLANT_LICENSE_HEADER_START@
+ *
+ * This file contains Original Code and/or Modifications of Original Code
+ * as defined in and that are subject to the Apache License
+ * Version 2.0 (the 'License'). You may not use this file except in
+ * compliance with the License. Please obtain a copy of the License at
+ * http://opensource.org/licenses/Apache-2.0/ and read it before using this
+ * file.
+ *
+ * The Original Code and all software distributed under the License are
+ * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
+ * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
+ * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
+ * Please see the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * @APPPLANT_LICENSE_HEADER_END@
+ */
+
+
+/*************
+ * INTERFACE *
+ *************/
+
+/**
+ * Returns the default settings.
+ *
+ * @return {Object}
+ */
+exports.getDefaults = function () {
+ return this.core.getDefaults();
+};
+
+/**
+ * Overwrite default settings.
+ *
+ * @param {Object} defaults
+ */
+exports.setDefaults = function (defaults) {
+ this.core.setDefaults(defaults);
+};
+
+/**
+ * Schedule a new local notification.
+ *
+ * @param {Object} opts
+ * The notification properties
+ * @param {Function} callback
+ * A function to be called after the notification has been canceled
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.schedule = function (opts, callback, scope) {
+ this.core.schedule(opts, callback, scope);
+};
+
+/**
+ * Update existing notifications specified by IDs in options.
+ *
+ * @param {Object} options
+ * The notification properties to update
+ * @param {Function} callback
+ * A function to be called after the notification has been updated
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.update = function (opts, callback, scope) {
+ this.core.update(opts, callback, scope);
+};
+
+/**
+ * Clear the specified notification.
+ *
+ * @param {String} id
+ * The ID of the notification
+ * @param {Function} callback
+ * A function to be called after the notification has been cleared
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.clear = function (ids, callback, scope) {
+ this.core.clear(ids, callback, scope);
+};
+
+/**
+ * Clear all previously sheduled notifications.
+ *
+ * @param {Function} callback
+ * A function to be called after all notifications have been cleared
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.clearAll = function (callback, scope) {
+ this.core.clearAll(callback, scope);
+};
+
+/**
+ * Cancel the specified notifications.
+ *
+ * @param {String[]} ids
+ * The IDs of the notifications
+ * @param {Function} callback
+ * A function to be called after the notifications has been canceled
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.cancel = function (ids, callback, scope) {
+ this.core.cancel(ids, callback, scope);
+};
+
+/**
+ * Remove all previously registered notifications.
+ *
+ * @param {Function} callback
+ * A function to be called after all notifications have been canceled
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.cancelAll = function (callback, scope) {
+ this.core.cancelAll(callback, scope);
+};
+
+/**
+ * Check if a notification with an ID is present.
+ *
+ * @param {String} id
+ * The ID of the notification
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.isPresent = function (id, callback, scope) {
+ this.core.isPresent(id, callback, scope);
+};
+
+/**
+ * Check if a notification with an ID is scheduled.
+ *
+ * @param {String} id
+ * The ID of the notification
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.isScheduled = function (id, callback, scope) {
+ this.core.isScheduled(id, callback, scope);
+};
+
+/**
+ * Check if a notification with an ID was triggered.
+ *
+ * @param {String} id
+ * The ID of the notification
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.isTriggered = function (id, callback, scope) {
+ this.core.isTriggered(id, callback, scope);
+};
+
+/**
+ * List all local notification IDs.
+ *
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getAllIds = function (callback, scope) {
+ this.core.getAllIds(callback, scope);
+};
+
+/**
+ * Alias for `getAllIds`.
+ */
+exports.getIds = function () {
+ this.getAllIds.apply(this, arguments);
+};
+
+/**
+ * List all scheduled notification IDs.
+ *
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getScheduledIds = function (callback, scope) {
+ this.core.getScheduledIds(callback, scope);
+};
+
+/**
+ * List all triggered notification IDs.
+ *
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getTriggeredIds = function (callback, scope) {
+ this.core.getTriggeredIds(callback, scope);
+};
+
+/**
+ * Property list for given local notifications.
+ * If called without IDs, all notification will be returned.
+ *
+ * @param {Number[]?} ids
+ * Set of notification IDs
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.get = function () {
+ this.core.get.apply(this.core, arguments);
+};
+
+/**
+ * Property list for all local notifications.
+ *
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getAll = function (callback, scope) {
+ this.core.getAll(callback, scope);
+};
+
+/**
+ * Property list for given scheduled notifications.
+ * If called without IDs, all notification will be returned.
+ *
+ * @param {Number[]?} ids
+ * Set of notification IDs
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getScheduled = function () {
+ this.core.getScheduled.apply(this.core, arguments);
+};
+
+/**
+ * Property list for all scheduled notifications.
+ *
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getAllScheduled = function (callback, scope) {
+ this.core.getAllScheduled(callback, scope);
+};
+
+/**
+ * Property list for given triggered notifications.
+ * If called without IDs, all notification will be returned.
+ *
+ * @param {Number[]?} ids
+ * Set of notification IDs
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getTriggered = function () {
+ this.core.getTriggered.apply(this.core, arguments);
+};
+
+/**
+ * Property list for all triggered notifications.
+ *
+ * @param {Function} callback
+ * A callback function to be called with the list
+ * @param {Object?} scope
+ * The scope for the callback function
+ */
+exports.getAllTriggered = function (callback, scope) {
+ this.core.getAllTriggered(callback, scope);
+};
+
+/**
+ * Informs if the app has the permission to show notifications.
+ *
+ * @param {Function} callback
+ * The function to be exec as the callback
+ * @param {Object?} scope
+ * The callback function's scope
+ */
+exports.hasPermission = function (callback, scope) {
+ this.core.hasPermission(callback, scope);
+};
+
+/**
+ * Register permission to show notifications if not already granted.
+ *
+ * @param {Function} callback
+ * The function to be exec as the callback
+ * @param {Object?} scope
+ * The callback function's scope
+ */
+exports.registerPermission = function (callback, scope) {
+ this.core.registerPermission(callback, scope);
+};
+
+
+/****************
+ * DEPRECATIONS *
+ ****************/
+
+/**
+ * Schedule a new local notification.
+ */
+exports.add = function () {
+ console.warn('Depreated: Please use `notification.local.schedule` instead.');
+
+ this.schedule.apply(this, arguments);
+};
+
+/**
+ * Register permission to show notifications
+ * if not already granted.
+ */
+exports.promptForPermission = function () {
+ console.warn('Depreated: Please use `notification.local.registerPermission` instead.');
+
+ this.registerPermission.apply(this, arguments);
+};
+
+
+/**********
+ * EVENTS *
+ **********/
+
+/**
+ * Register callback for given event.
+ *
+ * @param {String} event
+ * The event's name
+ * @param {Function} callback
+ * The function to be exec as callback
+ * @param {Object?} scope
+ * The callback function's scope
+ */
+exports.on = function (event, callback, scope) {
+ this.core.on(event, callback, scope);
+};
+
+/**
+ * Unregister callback for given event.
+ *
+ * @param {String} event
+ * The event's name
+ * @param {Function} callback
+ * The function to be exec as callback
+ */
+exports.un = function (event, callback) {
+ this.core.un(event, callback, scope);
+};