Commit aa24cd44 by Sebastián Katzer

Update example

parent 4a81b72a
......@@ -98,20 +98,20 @@ exports.setDefaults = function (newDefaults) {
/**
* Add a new entry to the registry
*
* @param {Object} props
* @param {Object} opts
* The notification properties
* @param {Function} callback
* A function to be called after the notification has been canceled
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.add = function (props, callback, scope) {
exports.add = function (opts, callback, scope) {
this.registerPermission(function(granted) {
if (!granted)
return;
var notifications = Array.isArray(props) ? props : [props];
var notifications = Array.isArray(opts) ? opts : [opts];
for (var i = 0; i < notifications.length; i++) {
var properties = notifications[i];
......@@ -120,50 +120,56 @@ exports.add = function (props, callback, scope) {
this.convertProperties(properties);
}
if (device.platform != 'iOS') {
notifications = notifications[0];
}
this.exec('add', notifications, callback, scope);
}, this);
};
/**
* Update existing notification specified by ID in options.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.update = function (options, callback, scope) {
this.exec('update', options, callback, scope);
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);
};
/**
* Clears the specified notification.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.clear = function (id, callback, scope) {
var notId = (id || '0').toString();
exports.clear = function (ids, callback, scope) {
ids = Array.isArray(ids) ? ids : [ids];
this.exec('clear', notId, callback, scope);
ids = this.convertIds(ids);
this.exec('clear', ids, callback, scope);
};
/**
* Clears all previously sheduled notifications.
* Clear all previously sheduled notifications.
*
* @param {Function} callback
* A function to be called after all notifications have been cleared
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.clearAll = function (callback, scope) {
......@@ -171,36 +177,30 @@ exports.clearAll = function (callback, scope) {
};
/**
* Cancels the specified notifications.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.cancel = function (ids, callback, scope) {
ids = Array.isArray(ids) ? ids : [ids];
for (var i = 0; i < ids.length; i++) {
ids[i] = ids[i].toString();
}
if (device.platform != 'iOS') {
ids = ids[0];
}
ids = this.convertIds(ids);
this.exec('cancel', ids, callback, scope);
};
/**
* Removes all previously registered notifications.
* Remove all previously registered notifications.
*
* @param {Function} callback
* A function to be called after all notifications have been canceled
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.cancelAll = function (callback, scope) {
......@@ -208,39 +208,55 @@ exports.cancelAll = function (callback, scope) {
};
/**
* Retrieves a list with all currently pending notifications.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.getScheduledIds = function (callback, scope) {
this.exec('getScheduledIds', null, callback, scope);
exports.isScheduled = function (id, callback, scope) {
var notId = (id || '0').toString();
this.exec('isScheduled', notId, callback, scope);
};
/**
* Checks wether a notification with an ID is scheduled.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.isScheduled = function (id, callback, scope) {
exports.isTriggered = function (id, callback, scope) {
var notId = (id || '0').toString();
this.exec('isScheduled', notId, callback, scope);
this.exec('isTriggered', notId, callback, scope);
};
/**
* Retrieves a list with all triggered notifications.
* List all currently pending notifications.
*
* @param {Function} callback
* A callback function to be called with the list
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.getScheduledIds = function (callback, scope) {
this.exec('getScheduledIds', null, callback, scope);
};
/**
* List 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.getTriggeredIds = function (callback, scope) {
......@@ -248,19 +264,89 @@ exports.getTriggeredIds = function (callback, scope) {
};
/**
* Checks wether a notification with an ID was triggered.
* List all properties for given scheduled notifications.
* If called without IDs, all notification will be returned.
*
* @param {String} id
* The ID of the notification
* @param {Number[]?} ids
* Set of notification IDs
* @param {Function} callback
* A callback function to be called with the list
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.isTriggered = function (id, callback, scope) {
var notId = (id || '0').toString();
exports.getScheduled = function () {
var args = Array.apply(null, arguments);
this.exec('isTriggered', notId, callback, scope);
if (typeof args[0] == 'function') {
args.unshift([]);
}
var ids = args[0],
callback = args[1],
scope = args[2];
if (!Array.isArray(ids)) {
ids = [ids];
}
ids = this.convertIds(ids);
this.exec('getScheduled', ids, callback, scope);
};
/**
* Retrieve the properties 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);
};
/**
* List all properties 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];
}
ids = this.convertIds(ids);
this.exec('getTriggered', ids, callback, scope);
};
/**
* Retrieve the properties 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);
};
/**
......@@ -318,102 +404,6 @@ exports.promptForPermission = function (callback, scope) {
};
/**
* Add new entries to the registry (more than one)
*
* @param {Object} options
* The notification properties
* @param {Function} callback
* A function to be called after the notification has been added
* @param {Object} scope
* The scope for the callback function
*
* @return {Number}
* The notification's ID
*/
exports.addMultiple = function (notifications, callback, scope) {
var length = notifications.length;
var notificationsMerged = new Array(),
callbackFn = this.createCallbackFn(callback, scope);
for (var i=0;i<length;i++){
var options = this.mergeWithDefaults(notifications[i]);
if (options.id) {
options.id = options.id.toString();
}
if (options.date === undefined) {
options.date = new Date();
}
if (options.title) {
options.title = options.title.toString();
}
if (options.message) {
options.message = options.message.toString();
}
if (typeof options.date == 'object') {
options.date = Math.round(options.date.getTime()/1000);
}
if (['WinCE', 'Win32NT'].indexOf(device.platform) > -1) {
callbackFn = function (cmd) {
eval(cmd);
};
}
notificationsMerged.push(options);
}
cordova.exec(callbackFn, null, 'LocalNotification', 'addMultiple', notificationsMerged);
return options.id;
};
/**
* Clear the specified notifications (more than one).
*
* @param {String} id
* The ID of the notification
* @param {Function} callback
* A function to be called after the notifications has been cleared.
* @param {Object} scope
* The scope for the callback function
*/
exports.clearMultiple = function (ids, callback, scope) {
var length = ids.length;
var idArray = new Array(),
callbackFn = this.createCallbackFn(callback, scope);
for (var i=0;i<length;i++){
var id = ids[i].toString();
idArray.push(id);
}
var callbackFn = this.createCallbackFn(callback, scope);
cordova.exec(callbackFn, null, 'LocalNotification', 'clearMultiple', [ids]);
};
/**
* Cancel the specified notifications (more than one).
*
* @param {String} id
* The ID of the notification
* @param {Function} callback
* A function to be called after the notifications has been canceled
* @param {Object} scope
* The scope for the callback function
*/
exports.cancelMultiple = function (ids, callback, scope) {
var length = ids.length;
var idArray = new Array(),
callbackFn = this.createCallbackFn(callback, scope);
for (var i=0;i<length;i++){
var id = ids[i].toString();
idArray.push(id);
}
var callbackFn = this.createCallbackFn(callback, scope);
cordova.exec(callbackFn, null, 'LocalNotification', 'cancelMultiple', [ids]);
};
/**
* Occurs when a notification was added.
*
* @param {String} id
......@@ -604,6 +594,25 @@ exports.createCallbackFn = function (callbackFn, scope) {
/**
* @private
*
* Convert the IDs to Strings.
*
* @param {String/Number[]} ids
*
* @return Array of Strings
*/
exports.convertIds = function (ids) {
var convertedIds = [];
for (var i = 0; i < ids.length; i++) {
convertedIds.push(ids[i].toString());
}
return convertedIds;
};
/**
* @private
*
* Executes the native counterpart.
*
* @param {String} action
......
......@@ -23,6 +23,7 @@ package de.appplant.cordova.plugin.localnotification;
import java.util.Date;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
......@@ -31,10 +32,15 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import de.appplant.cordova.plugin.notification.Options;
public class DeleteIntentReceiver extends BroadcastReceiver {
public static final String OPTIONS = "LOCAL_NOTIFICATION_OPTIONS";
/**
* Is called when a Notification is cleared manualy by the User
*/
@Override
public void onReceive(Context context, Intent intent) {
Options options = null;
......@@ -53,7 +59,8 @@ public class DeleteIntentReceiver extends BroadcastReceiver {
Date now = new Date();
if ((options.getInterval()!=0)){
LocalNotification.persist(options.getId(), setInitDate(args));
options.setInitDate();
LocalNotification.persist(options.getId(), options.getJSONObject());
}
else if((new Date(options.getDate()).before(now))){
LocalNotification.unpersist(options.getId());
......@@ -62,21 +69,12 @@ public class DeleteIntentReceiver extends BroadcastReceiver {
fireClearEvent(options);
}
private JSONObject setInitDate(JSONObject arguments){
long initialDate = arguments.optLong("date", 0) * 1000;
try {
arguments.put("initialDate", initialDate);
} catch (JSONException e) {
e.printStackTrace();
}
return arguments;
}
/**
* Fires onclear event.
*/
private void fireClearEvent (Options options) {
LocalNotification.fireEvent("clear", options.getId(), options.getJSON());
JSONArray data = new JSONArray().put(options.getJSONObject());
LocalNotification.fireEvent("clear", options.getId(), options.getJSON(),data);
}
}
......@@ -22,14 +22,12 @@
package de.appplant.cordova.plugin.localnotification;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
......@@ -38,13 +36,13 @@ import org.json.JSONObject;
import android.app.Activity;
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.content.SharedPreferences.Editor;
import android.os.Build;
import android.widget.Toast;
import android.annotation.TargetApi;
import de.appplant.cordova.plugin.notification.*;
/**
* This plugin utilizes the Android AlarmManager in combination with StatusBar
......@@ -55,13 +53,16 @@ import android.widget.Toast;
public class LocalNotification extends CordovaPlugin {
protected final static String PLUGIN_NAME = "LocalNotification";
static protected final String STORAGE_FOLDER = "/localnotification";
private static CordovaWebView webView = null;
private static Boolean deviceready = false;
protected static Context context = null;
protected static Boolean isInBackground = true;
private static ArrayList<String> eventQueue = new ArrayList<String>();
static Activity activity;
Asset asset;
Manager manager;
NotificationWrapper nWrapper;
@Override
public void initialize (CordovaInterface cordova, CordovaWebView webView) {
......@@ -70,29 +71,27 @@ public class LocalNotification extends CordovaPlugin {
LocalNotification.webView = super.webView;
LocalNotification.context = super.cordova.getActivity().getApplicationContext();
LocalNotification.activity = super.cordova.getActivity();
this.asset = new Asset(activity,STORAGE_FOLDER);
this.manager = new Manager(context, PLUGIN_NAME);
this.nWrapper = new NotificationWrapper(context,Receiver.class,PLUGIN_NAME,Receiver.OPTIONS);
}
@Override
public boolean execute (String action, final JSONArray args, final CallbackContext command) throws JSONException {
if (action.equalsIgnoreCase("add")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
JSONObject arguments = setInitDate(args.optJSONObject(0));
Options options = new Options(context).parse(arguments);
add(options, true);
command.success();
}
});
}
if (action.equalsIgnoreCase("addMultiple")) {
if (action.equalsIgnoreCase("add")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
JSONArray notifications = args.optJSONArray(0);
for (int i =0; i<notifications.length();i++){
JSONObject arguments = setInitDate(notifications.optJSONObject(i));
JSONObject arguments;
for(int i=0;i<notifications.length();i++){
arguments = notifications.optJSONObject(i);
LOG.d("LocalNotification", arguments.toString());
arguments = asset.parseURIs(arguments);
Options options = new Options(context).parse(arguments);
add(options, true);
options.setInitDate();
nWrapper.schedule(options);
JSONArray data = new JSONArray().put(options.getJSONObject());
fireEvent("add", options.getId(), options.getJSON(), data);
}
command.success();
}
......@@ -102,75 +101,84 @@ public class LocalNotification extends CordovaPlugin {
if (action.equalsIgnoreCase("update")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
JSONObject updates = args.optJSONObject(0);
JSONArray updates = args.optJSONArray(0);
JSONObject updateContent;
for(int i=0;i<updates.length();i++){
updateContent = args.optJSONObject(i);
update(updates);
command.success();
}
});
nWrapper.update(updateContent);
}
if (action.equalsIgnoreCase("clear")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
String id = args.optString(0);
clear(id);
command.success();
}
});
}
if (action.equalsIgnoreCase("clearMultiple")) {
if (action.equalsIgnoreCase("cancel")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
JSONArray ids = args.optJSONArray(0);
for (int i =0; i<ids.length();i++){
clear(ids.optString(i));
String id;
for(int i=0;i<ids.length();i++){
id = args.optString(i);
nWrapper.cancel(id);
JSONArray managerId = new JSONArray().put(id);
JSONArray data = new JSONArray().put(manager.getAll(managerId));
fireEvent("cancel", id, "",data);
}
command.success();
}
});
}
if (action.equalsIgnoreCase("clearAll")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
clearAll();
command.success();
}
});
}
if (action.equalsIgnoreCase("cancel")) {
if (action.equalsIgnoreCase("cancelAll")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
String id = args.optString(0);
cancel(id);
unpersist(id);
JSONArray options = manager.getAll();
nWrapper.cancelAll();
String id;
JSONObject arguments;
for(int i=0;i<options.length();i++){
arguments= (JSONObject) options.opt(i);
JSONArray data = new JSONArray().put(arguments);
id = arguments.optString("id");
fireEvent("cancel", id, "",data);
}
command.success();
}
});
}
if (action.equalsIgnoreCase("cancelMultiple")) {
if (action.equalsIgnoreCase("clear")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
JSONArray ids = args.optJSONArray(0);
for (int i =0; i<ids.length();i++){
cancel(ids.optString(i));
String id;
for(int i=0;i<ids.length();i++){
id = args.optString(i);
nWrapper.clear(id);
JSONArray managerId = new JSONArray().put(id);
JSONArray data = new JSONArray().put(manager.getAll(managerId));
fireEvent("clear", id, "",data);
}
command.success();
}
});
}
if (action.equalsIgnoreCase("cancelAll")) {
if (action.equalsIgnoreCase("clearAll")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
cancelAll();
unpersistAll();
JSONArray options = manager.getAll();
nWrapper.clearAll();
String id;
JSONObject arguments;
for(int i=0;i<options.length();i++){
arguments= (JSONObject) options.opt(i);
JSONArray data = new JSONArray().put(arguments);
id = arguments.optString("id");
fireEvent("clear", id, "",data);
}
command.success();
}
});
......@@ -178,22 +186,74 @@ public class LocalNotification extends CordovaPlugin {
if (action.equalsIgnoreCase("isScheduled")) {
String id = args.optString(0);
isScheduled(id, command);
boolean isScheduled = manager.isScheduled(id);
PluginResult result = new PluginResult(PluginResult.Status.OK, (isScheduled));
command.sendPluginResult(result);
}
if (action.equalsIgnoreCase("getScheduledIds")) {
getScheduledIds(command);
if (action.equalsIgnoreCase("isTriggered")) {
String id = args.optString(0);
boolean isTriggered = manager.isTriggered(id);
PluginResult result = new PluginResult(PluginResult.Status.OK, isTriggered);
command.sendPluginResult(result);
}
if (action.equalsIgnoreCase("isTriggered")) {
if (action.equalsIgnoreCase("exist")) {
String id = args.optString(0);
boolean exist = manager.exist(id);
PluginResult result = new PluginResult(PluginResult.Status.OK, exist);
command.sendPluginResult(result);
}
isTriggered(id, command);
if (action.equalsIgnoreCase("getScheduledIds")) {
JSONArray scheduledIds = manager.getScheduledIds();
command.success(scheduledIds);
}
if (action.equalsIgnoreCase("getTriggeredIds")) {
getTriggeredIds(command);
JSONArray triggeredIds = manager.getTriggeredIds();
command.success(triggeredIds);
}
if (action.equalsIgnoreCase("getAllIds")) {
JSONArray allIds = manager.getAllIds();
command.success(allIds);
}
if (action.equalsIgnoreCase("getAll")) {
JSONArray ids;
JSONArray all;
try{
ids = args.getJSONArray(0);
all = manager.getAll(ids);
} catch (JSONException jse){
all = manager.getAll();
}
command.success(all);
}
if (action.equalsIgnoreCase("getTriggered")) {
JSONArray ids;
JSONArray triggered;
try{
ids = args.getJSONArray(0);
triggered = manager.getTriggered(ids);
} catch (JSONException jse){
triggered = manager.getTriggered();
}
command.success(triggered);
}
if (action.equalsIgnoreCase("getScheduled")) {
JSONArray ids;
JSONArray scheduled;
try{
ids = args.getJSONArray(0);
scheduled = manager.getScheduled(ids);
} catch (JSONException jse){
scheduled = manager.getScheduled();
}
command.success(scheduled);
}
if (action.equalsIgnoreCase("deviceready")) {
......@@ -222,311 +282,13 @@ public class LocalNotification extends CordovaPlugin {
deviceready = true;
for (String js : eventQueue) {
webView.sendJavascript(js);
sendJavascript(js);
}
eventQueue.clear();
}
/**
* Set an alarm.
*
* @param options
* The options that can be specified per alarm.
* @param doFireEvent
* If the onadd callback shall be called.
*/
public static void add (Options options, boolean doFireEvent) {
long triggerTime = options.getDate();
persist(options.getId(), options.getJSONObject());
//Intent is called when the Notification gets fired
Intent intent = new Intent(context, Receiver.class)
.setAction("" + options.getId())
.putExtra(Receiver.OPTIONS, options.getJSONObject().toString());
AlarmManager am = getAlarmManager();
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
if (doFireEvent) {
fireEvent("add", options.getId(), options.getJSON());
}
am.set(AlarmManager.RTC_WAKEUP, triggerTime, pi);
}
/**
* Update an existing notification
*
* @param updates JSONObject with update-content
*/
public static void update (JSONObject updates){
String id = updates.optString("id", "0");
// update shared preferences
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
JSONObject arguments;
try {
arguments = new JSONObject(alarms.get(id).toString());
} catch (JSONException e) {
e.printStackTrace();
return;
}
arguments = updateArguments(arguments, updates);
// cancel existing alarm
Intent intent = new Intent(context, Receiver.class)
.setAction("" + id);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager am = getAlarmManager();
am.cancel(pi);
//add new alarm
Options options = new Options(context).parse(arguments);
add(options,false);
}
/**
* Clear a specific notification without canceling repeating alarms
*
* @param notificationID
* The original ID of the notification that was used when it was
* registered using add()
*/
public static void clear (String notificationId){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
NotificationManager nc = getNotificationManager();
try {
nc.cancel(Integer.parseInt(notificationId));
} catch (Exception e) {}
JSONObject arguments;
try {
arguments = new JSONObject(alarms.get(notificationId).toString());
Options options = new Options(context).parse(arguments);
Date now = new Date();
if ((options.getInterval()!=0)){
persist(notificationId, setInitDate(arguments));
}
else if((new Date(options.getDate()).before(now))){
unpersist(notificationId);
}
} catch (JSONException e) {
e.printStackTrace();
return;
}
fireEvent("clear", notificationId, "");
}
/**
* Clear all notifications without canceling repeating alarms
*/
public static void clearAll (){
SharedPreferences settings = getSharedPreferences();
NotificationManager nc = getNotificationManager();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
for (String alarmId : alarmIds) {
clear(alarmId);
}
nc.cancelAll();
}
/**
* Cancel a specific notification that was previously registered.
*
* @param notificationId
* The original ID of the notification that was used when it was
* registered using add()
*/
public static void cancel (String notificationId) {
/*
* Create an intent that looks similar, to the one that was registered
* using add. 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.
*/
Intent intent = new Intent(context, Receiver.class)
.setAction("" + notificationId);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager am = getAlarmManager();
NotificationManager nc = getNotificationManager();
am.cancel(pi);
try {
nc.cancel(Integer.parseInt(notificationId));
} catch (Exception e) {}
fireEvent("cancel", notificationId, "");
}
/**
* Cancel all notifications that were created by this plugin.
*
* Android can only unregister a specific alarm. There is no such thing
* as cancelAll. Therefore we rely on the Shared Preferences which holds
* all our alarms to loop through these alarms and unregister them one
* by one.
*/
public static void cancelAll() {
SharedPreferences settings = getSharedPreferences();
NotificationManager nc = getNotificationManager();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
for (String alarmId : alarmIds) {
cancel(alarmId);
}
nc.cancelAll();
}
/**
* Checks if a notification with an ID is scheduled.
*
* @param id
* The notification ID to be check.
* @param callbackContext
*/
public static void isScheduled (String id, CallbackContext command) {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
boolean isScheduled = alarms.containsKey(id);
boolean isNotTriggered = false;
if (isScheduled) {
JSONObject arguments;
try {
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getDate());
isNotTriggered = new Date().before(fireDate);
} catch (JSONException e) {
isNotTriggered = false;
e.printStackTrace();
}
}
PluginResult result = new PluginResult(PluginResult.Status.OK, (isScheduled && isNotTriggered));
command.sendPluginResult(result);
}
/**
* Retrieves a list with all currently pending notifications.
*
* @param callbackContext
*/
public static void getScheduledIds (CallbackContext command) {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray scheduledIds = new JSONArray();
for (String id : alarmIds) {
boolean isScheduled;
JSONObject arguments;
try {
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getDate());
isScheduled = new Date().before(fireDate);
} catch (JSONException e) {
isScheduled = false;
e.printStackTrace();
}
if (isScheduled){
scheduledIds.put(id);
}
}
command.success(scheduledIds);
}
/**
* Checks if a notification with an ID was triggered.
*
* @param id
* The notification ID to be check.
* @param callbackContext
*/
public static void isTriggered (String id, CallbackContext command) {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
boolean isScheduled = alarms.containsKey(id);
boolean isTriggered = isScheduled;
if (isScheduled) {
JSONObject arguments;
try {
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getInitialDate());
isTriggered = new Date().after(fireDate);
} catch (JSONException e) {
isTriggered = false;
e.printStackTrace();
}
}
PluginResult result = new PluginResult(PluginResult.Status.OK, isTriggered);
command.sendPluginResult(result);
}
/**
* Retrieves a list with all currently triggered notifications.
*
* @param callbackContext
*/
public static void getTriggeredIds (CallbackContext command) {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray triggeredIds = new JSONArray();
Date now = new Date();
for (String id : alarmIds) {
boolean isTriggered;
JSONObject arguments;
try{
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getInitialDate());
isTriggered = now.after(fireDate);
} catch(ClassCastException cce) {
cce.printStackTrace();
isTriggered = false;
}
catch(JSONException jse) {
jse.printStackTrace();
isTriggered = false;
}
if (isTriggered == true) {
triggeredIds.put(id);
}
}
command.success(triggeredIds);
}
/**
* Persist the information of this alarm to the Android Shared Preferences.
* This will allow the application to restore the alarm upon device reboot.
* Also this is used by the cancelAll method.
......@@ -582,6 +344,7 @@ public class LocalNotification extends CordovaPlugin {
}
}
//
/**
* Fires the given event.
*
......@@ -589,9 +352,11 @@ public class LocalNotification extends CordovaPlugin {
* @param {String} id The ID of the notification
* @param {String} json A custom (JSON) string
*/
public static void fireEvent (String event, String id, String json) {
public static void fireEvent (String event, String id, String json, JSONArray data) {
String state = getApplicationState();
//TODO dataArray handling
String params = "\"" + id + "\",\"" + state + "\",\\'" + JSONObject.quote(json) + "\\'.replace(/(^\"|\"$)/g, \\'\\')";
// params = params + "," + dataArray;
String js = "setTimeout('plugin.notification.local.on" + event + "(" + params + ")',0)";
// webview may available, but callbacks needs to be executed
......@@ -599,7 +364,7 @@ public class LocalNotification extends CordovaPlugin {
if (deviceready == false) {
eventQueue.add(js);
} else {
webView.sendJavascript(js);
sendJavascript(js);
}
}
......@@ -643,54 +408,21 @@ public class LocalNotification extends CordovaPlugin {
return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
/**
* Function to set the value of "initialDate" in the JSONArray
* @param args The given JSONArray
* @return A new JSONArray with the parameter "initialDate" set.
* Use this instead of deprecated sendJavascript
*/
private static JSONObject setInitDate(JSONObject arguments){
long initialDate = arguments.optLong("date", 0) * 1000;
try {
arguments.put("initialDate", initialDate);
} catch (JSONException e) {
e.printStackTrace();
}
return arguments;
}
private static JSONObject updateArguments(JSONObject arguments,JSONObject updates){
try {
if(!updates.isNull("message")){
arguments.put("message", updates.get("message"));
}
if(!updates.isNull("title")){
arguments.put("title", updates.get("title"));
}
if(!updates.isNull("badge")){
arguments.put("badge", updates.get("badge"));
}
if(!updates.isNull("sound")){
arguments.put("sound", updates.get("sound"));
}
if(!updates.isNull("icon")){
arguments.put("icon", updates.get("icon"));
}
} catch (JSONException jse){
jse.printStackTrace();
}
return arguments;
@TargetApi(Build.VERSION_CODES.KITKAT)
private static void sendJavascript(final String js){
webView.post(new Runnable(){
public void run(){
if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.KITKAT){
webView.evaluateJavascript(js, null);
} else {
webView.loadUrl("javascript:" + js);
}
public static void showNotification(String title,String notification){
int duration = Toast.LENGTH_LONG;
if(title.equals("")){
title = "Notification";
}
String text = title + " \n " + notification;
Toast notificationToast = Toast.makeText(context, text, duration);
notificationToast.show();
});
}
......
/*
Copyright 2013-2014 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.
*/
package de.appplant.cordova.plugin.localnotification;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.AlarmManager;
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.os.StrictMode.ThreadPolicy;
import android.util.Log;
/**
* Class that helps to store the options that can be specified per alarm.
*/
public class Options {
static protected final String STORAGE_FOLDER = "/localnotification";
private JSONObject options = new JSONObject();
private String packageName = null;
private long interval = 0;
Options (Activity activity) {
packageName = activity.getPackageName();
}
Options (Context context) {
packageName = context.getPackageName();
}
/**
* Parses the given properties
*/
public Options parse (JSONObject options) {
String repeat = options.optString("repeat");
this.options = options;
if (repeat.equalsIgnoreCase("secondly")) {
interval = 1000;
} if (repeat.equalsIgnoreCase("minutely")) {
interval = AlarmManager.INTERVAL_FIFTEEN_MINUTES / 15;
} if (repeat.equalsIgnoreCase("hourly")) {
interval = AlarmManager.INTERVAL_HOUR;
} if (repeat.equalsIgnoreCase("daily")) {
interval = AlarmManager.INTERVAL_DAY;
} else if (repeat.equalsIgnoreCase("weekly")) {
interval = AlarmManager.INTERVAL_DAY*7;
} else if (repeat.equalsIgnoreCase("monthly")) {
interval = AlarmManager.INTERVAL_DAY*31; // 31 days
} else if (repeat.equalsIgnoreCase("yearly")) {
interval = AlarmManager.INTERVAL_DAY*365;
} else {
try {
interval = Integer.parseInt(repeat) * 60000;
} catch (Exception e) {};
}
return this;
}
/**
* Set new time according to interval
*/
public Options moveDate () {
try {
options.put("date", (getDate() + interval) / 1000);
} catch (JSONException e) {}
return this;
}
/**
* Returns options as JSON object
*/
public JSONObject getJSONObject() {
return options;
}
/**
* Returns time in milliseconds when notification is scheduled to fire
*/
public long getDate() {
return options.optLong("date", 0) * 1000;
}
/**
* Returns time in milliseconds when the notification was scheduled first
*/
public long getInitialDate() {
return options.optLong("initialDate", 0);
}
/**
* Returns time as calender
*/
public Calendar getCalendar () {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(getDate()));
return calendar;
}
/**
* Returns the notification's message
*/
public String getMessage () {
return options.optString("message", "");
}
/**
* Returns the notification's title
*/
public String getTitle () {
return options.optString("title", "");
}
/**
* Returns the path of the notification's sound file
*/
public Uri getSound () {
String sound = options.optString("sound", null);
if (sound != null) {
try {
int soundId = (Integer) RingtoneManager.class.getDeclaredField(sound).get(Integer.class);
return RingtoneManager.getDefaultUri(soundId);
} catch (Exception e) {
return getURIfromPath(sound);
}
}
return null;
}
/**
* Returns the icon's ID
*/
public Bitmap getIcon () {
String icon = options.optString("icon", "icon");
Bitmap bmp = null;
if (icon.startsWith("http")) {
bmp = getIconFromURL(icon);
} else if (icon.startsWith("file://") || (icon.startsWith("res"))) {
bmp = getIconFromURI(icon);
}
if (bmp == null) {
bmp = getIconFromRes(icon);
}
return bmp;
}
/**
* Returns the small icon's ID
*/
public int getSmallIcon () {
int resId = 0;
String iconName = options.optString("smallIcon", "");
resId = getIconValue(packageName, iconName);
if (resId == 0) {
resId = getIconValue("android", iconName);
}
if (resId == 0) {
resId = getIconValue(packageName, "icon");
}
return options.optInt("smallIcon", resId);
}
/**
* Returns notification repetition interval (daily, weekly, monthly, yearly)
*/
public long getInterval () {
return interval;
}
/**
* Returns notification badge number
*/
public int getBadge () {
return options.optInt("badge", 0);
}
/**
* Returns PluginResults' callback ID
*/
public String getId () {
return options.optString("id", "0");
}
/**
* Returns whether notification is cancelled automatically when clicked.
*/
public Boolean getAutoCancel () {
return options.optBoolean("autoCancel", false);
}
/**
* Returns whether the notification is ongoing (uncancellable). Android only.
*/
public Boolean getOngoing () {
return options.optBoolean("ongoing", false);
}
/**
* Returns additional data as string
*/
public String getJSON () {
return options.optString("json", "");
}
/**
* @return
* The notification color for LED
*/
public int getColor () {
String hexColor = options.optString("led", "000000");
int aRGB = Integer.parseInt(hexColor,16);
aRGB += 0xFF000000;
return aRGB;
}
/**
* Returns numerical icon Value
*
* @param {String} className
* @param {String} iconName
*/
private int getIconValue (String className, String iconName) {
int icon = 0;
try {
Class<?> klass = Class.forName(className + ".R$drawable");
icon = (Integer) klass.getDeclaredField(iconName).get(Integer.class);
} catch (Exception e) {}
return icon;
}
/**
* Converts an resource to Bitmap.
*
* @param icon
* The resource name
* @return
* The corresponding bitmap
*/
private Bitmap getIconFromRes (String icon) {
Resources res = LocalNotification.context.getResources();
int iconId = 0;
iconId = getIconValue(packageName, icon);
if (iconId == 0) {
iconId = getIconValue("android", icon);
}
if (iconId == 0) {
iconId = android.R.drawable.ic_menu_info_details;
}
Bitmap bmp = BitmapFactory.decodeResource(res, iconId);
return bmp;
}
/**
* Converts an Image URL to Bitmap.
*
* @param src
* The external image URL
* @return
* The corresponding bitmap
*/
private Bitmap getIconFromURL (String src) {
Bitmap bmp = null;
ThreadPolicy origMode = StrictMode.getThreadPolicy();
try {
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
bmp = BitmapFactory.decodeStream(input);
} catch (Exception e) {
e.printStackTrace();
}
StrictMode.setThreadPolicy(origMode);
return bmp;
}
/**
* Converts an Image URI to Bitmap.
*
* @param src
* The internal image URI
* @return
* The corresponding bitmap
*/
private Bitmap getIconFromURI (String src) {
Bitmap bmp = null;
Uri uri = getURIfromPath(src);
try {
InputStream input = LocalNotification.activity.getContentResolver().openInputStream(uri);
bmp = BitmapFactory.decodeStream(input);
} catch (IOException e) {
e.printStackTrace();
}
return bmp;
}
/**
* The URI for a path.
*
* @param path The given path
*
* @return The URI pointing to the given path
*/
private Uri getURIfromPath(String path){
if (path.startsWith("res:")) {
return getUriForResourcePath(path);
} else if (path.startsWith("file:///")) {
return getUriForAbsolutePath(path);
} else if (path.startsWith("file://")) {
return getUriForAssetPath(path);
}
return Uri.parse(path);
}
/**
* The URI for a file.
*
* @param path
* The given absolute path
*
* @return The URI pointing to the given path
*/
private Uri getUriForAbsolutePath(String path) {
String absPath = path.replaceFirst("file://", "");
File file = new File(absPath);
if (!file.exists()) {
Log.e("LocalNotifocation", "File not found: " + file.getAbsolutePath());
}
return Uri.fromFile(file);
}
/**
* The URI for an asset.
*
* @param path
* The given asset path
*
* @return The URI pointing to the given path
*/
private Uri getUriForAssetPath(String path) {
String resPath = path.replaceFirst("file:/", "www");
String fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
File dir = LocalNotification.activity.getExternalCacheDir();
if (dir == null) {
Log.e("LocalNotifocation", "Missing external cache dir");
return Uri.EMPTY;
}
String storage = dir.toString() + STORAGE_FOLDER;
File file = new File(storage, fileName);
new File(storage).mkdir();
try {
AssetManager assets = LocalNotification.activity.getAssets();
FileOutputStream outStream = new FileOutputStream(file);
InputStream inputStream = assets.open(resPath);
copyFile(inputStream, outStream);
outStream.flush();
outStream.close();
} catch (Exception e) {
Log.e("LocalNotifocation", "File not found: assets/" + resPath);
e.printStackTrace();
}
return Uri.fromFile(file);
}
/**
* The URI for a resource.
*
* @param path
* The given relative path
*
* @return The URI pointing to the given path
*/
private Uri getUriForResourcePath(String path) {
String resPath = path.replaceFirst("res://", "");
String fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
String resName = fileName.substring(0, fileName.lastIndexOf('.'));
String extension = resPath.substring(resPath.lastIndexOf('.'));
File dir = LocalNotification.activity.getExternalCacheDir();
if (dir == null) {
Log.e("LocalNotifocation", "Missing external cache dir");
return Uri.EMPTY;
}
String storage = dir.toString() + STORAGE_FOLDER;
int resId = getResId(resPath);
File file = new File(storage, resName + extension);
if (resId == 0) {
Log.e("LocalNotifocation", "File not found: " + resPath);
}
new File(storage).mkdir();
try {
Resources res = LocalNotification.activity.getResources();
FileOutputStream outStream = new FileOutputStream(file);
InputStream inputStream = res.openRawResource(resId);
copyFile(inputStream, outStream);
outStream.flush();
outStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return Uri.fromFile(file);
}
/**
* Writes an InputStream to an OutputStream
*
* @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);
}
}
/**
* @return The resource ID for the given resource.
*/
private int getResId(String resPath) {
Resources res = LocalNotification.activity.getResources();
int resId;
String pkgName = getPackageName();
String dirName = "drawable";
String fileName = resPath;
if (resPath.contains("/")) {
dirName = resPath.substring(0, resPath.lastIndexOf('/'));
fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
}
String resName = fileName.substring(0, fileName.lastIndexOf('.'));
resId = res.getIdentifier(resName, dirName, pkgName);
if (resId == 0) {
resId = res.getIdentifier(resName, "drawable", pkgName);
}
return resId;
}
/**
* The name for the package.
*
* @return The package name
*/
private String getPackageName() {
return LocalNotification.activity.getPackageName();
}
/**
* Shows the behavior of notifications when the application is in foreground
*
*
*/
public boolean getForegroundMode(){
return options.optBoolean("foregroundMode",false);
}
}
......@@ -22,23 +22,18 @@
package de.appplant.cordova.plugin.localnotification;
import java.util.Calendar;
import java.util.Random;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.*;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import 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
......@@ -49,11 +44,12 @@ public class Receiver extends BroadcastReceiver {
public static final String OPTIONS = "LOCAL_NOTIFICATION_OPTIONS";
private Context context;
private Options options;
@Override
public void onReceive (Context context, Intent intent) {
NotificationWrapper nWrapper = new NotificationWrapper(context,
Receiver.class,LocalNotification.PLUGIN_NAME,OPTIONS);
Options options = null;
Bundle bundle = intent.getExtras();
JSONObject args;
......@@ -64,10 +60,11 @@ public class Receiver extends BroadcastReceiver {
} catch (JSONException e) {
return;
}
this.context = context;
this.options = options;
NotificationBuilder builder = new NotificationBuilder(options,context,OPTIONS,
DeleteIntentReceiver.class,ReceiverActivity.class);
// The context may got lost if the app was not running before
LocalNotification.setContext(context);
......@@ -77,18 +74,18 @@ public class Receiver extends BroadcastReceiver {
} else if (isFirstAlarmInFuture()) {
return;
} else {
LocalNotification.add(options.moveDate(), false);
nWrapper.schedule(options.moveDate());
}
if (!LocalNotification.isInBackground && options.getForegroundMode()){
if (options.getInterval() == 0) {
LocalNotification.unpersist(options.getId());
}
LocalNotification.showNotification(options.getTitle(), options.getMessage());
builder.showNotificationToast();
fireTriggerEvent();
} else {
Builder notification = buildNotification();
builder.buildNotification();
showNotification(notification);
builder.showNotification();
}
}
......@@ -118,85 +115,10 @@ public class Receiver extends BroadcastReceiver {
}
/**
* Creates the notification.
*/
@SuppressLint("NewApi")
private Builder buildNotification () {
Uri sound = options.getSound();
//DeleteIntent is called when the user clears a notification manually
Intent deleteIntent = new Intent(context, DeleteIntentReceiver.class)
.setAction("" + options.getId())
.putExtra(Receiver.OPTIONS, options.getJSONObject().toString());
PendingIntent dpi = PendingIntent.getBroadcast(context, 0, deleteIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Builder notification = new NotificationCompat.Builder(context)
.setDefaults(0) // Do not inherit any defaults
.setContentTitle(options.getTitle())
.setContentText(options.getMessage())
.setNumber(options.getBadge())
.setTicker(options.getMessage())
.setSmallIcon(options.getSmallIcon())
.setLargeIcon(options.getIcon())
.setAutoCancel(options.getAutoCancel())
.setOngoing(options.getOngoing())
.setLights(options.getColor(), 500, 500)
.setDeleteIntent(dpi);
if (sound != null) {
notification.setSound(sound);
}
if (Build.VERSION.SDK_INT > 16) {
notification.setStyle(new NotificationCompat.BigTextStyle()
.bigText(options.getMessage()));
}
setClickEvent(notification);
return notification;
}
/**
* Adds an onclick handler to the notification
*/
private Builder setClickEvent (Builder notification) {
Intent intent = new Intent(context, ReceiverActivity.class)
.putExtra(OPTIONS, options.getJSONObject().toString())
.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
int requestCode = new Random().nextInt();
PendingIntent contentIntent = PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
return notification.setContentIntent(contentIntent);
}
/**
* Shows the notification
*/
@SuppressWarnings("deprecation")
private void showNotification (Builder notification) {
NotificationManager mgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
int id = 0;
try {
id = Integer.parseInt(options.getId());
} catch (Exception e) {}
if (Build.VERSION.SDK_INT<16) {
// build notification for HoneyComb to ICS
mgr.notify(id, notification.getNotification());
} else if (Build.VERSION.SDK_INT>15) {
// Notification for Jellybean and above
mgr.notify(id, notification.build());
}
}
/**
* Fires ontrigger event.
*/
private void fireTriggerEvent () {
LocalNotification.fireEvent("trigger", options.getId(), options.getJSON());
JSONArray data = new JSONArray().put(options.getJSONObject());
LocalNotification.fireEvent("trigger", options.getId(), options.getJSON(),data);
}
}
......@@ -23,12 +23,15 @@ package de.appplant.cordova.plugin.localnotification;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONArray;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import de.appplant.cordova.plugin.notification.*;
public class ReceiverActivity extends Activity {
/** Called when the activity is first created. */
......@@ -65,10 +68,11 @@ public class ReceiverActivity extends Activity {
* Fires the onclick event.
*/
private void fireClickEvent (Options options) {
LocalNotification.fireEvent("click", options.getId(), options.getJSON());
JSONArray data = new JSONArray().put(options.getJSONObject());
LocalNotification.fireEvent("click", options.getId(), options.getJSON(),data);
if (options.getAutoCancel()) {
LocalNotification.fireEvent("cancel", options.getId(), options.getJSON());
LocalNotification.fireEvent("cancel", options.getId(), options.getJSON(),data);
}
}
}
......@@ -31,6 +31,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import de.appplant.cordova.plugin.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
......@@ -42,6 +44,9 @@ public class Restore extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
// The application context needs to be set as first
LocalNotification.setContext(context);
//Create NotificationWrapper
NotificationWrapper nWrapper = new NotificationWrapper(context,
Receiver.class,LocalNotification.PLUGIN_NAME,Receiver.OPTIONS);
// Obtain alarm details form Shared Preferences
SharedPreferences alarms = LocalNotification.getSharedPreferences();
......@@ -59,7 +64,7 @@ public class Restore extends BroadcastReceiver {
/*
* If the trigger date was in the past, the notification will be displayed immediately.
*/
LocalNotification.add(options, false);
nWrapper.schedule(options);
} catch (JSONException e) {}
}
......
......@@ -5,13 +5,10 @@
};
objectVersion = 46;
objects = {
/* Begin PBXBuildFile section */
0B33C5FC1B224A91B96FDE79 /* CDVDevice.m in Sources */ = {isa = PBXBuildFile; fileRef = 212EBD1D7BCB4409838CD818 /* CDVDevice.m */; };
0FFC7382D3B74FADB62619F0 /* UIApplication+APPLocalNotification.h in Sources */ = {isa = PBXBuildFile; fileRef = 5ABA551B6BA54E6885F278AA /* UIApplication+APPLocalNotification.h */; };
1D3623260D0F684500981E51 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 1D3623250D0F684500981E51 /* AppDelegate.m */; };
1D60589B0D05DD56006BFB54 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; };
26914B69E52E40E893E4C399 /* APPLocalNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 9C396B7AA36E4F79A25451A3 /* APPLocalNotification.m */; };
288765FD0DF74451002DB57D /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 288765FC0DF74451002DB57D /* CoreGraphics.framework */; };
301BF552109A68D80062928A /* libCordova.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 301BF535109A57CC0062928A /* libCordova.a */; };
302D95F114D2391D003F00A1 /* MainViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 302D95EF14D2391D003F00A1 /* MainViewController.m */; };
......@@ -44,13 +41,15 @@
7E7966E51810823500FA85AD /* icon-76@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7E7966DB1810823500FA85AD /* icon-76@2x.png */; };
7E7966E61810823500FA85AD /* icon-small.png in Resources */ = {isa = PBXBuildFile; fileRef = 7E7966DC1810823500FA85AD /* icon-small.png */; };
7E7966E71810823500FA85AD /* icon-small@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = 7E7966DD1810823500FA85AD /* icon-small@2x.png */; };
979DDA8725D74CA3A4E545F8 /* APPLocalNotificationOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = 51E3BEE46964498795BC65EC /* APPLocalNotificationOptions.m */; };
9E1A68381A55FA1B00FBCA66 /* beep.caf in Resources */ = {isa = PBXBuildFile; fileRef = 9E1A68371A55FA1B00FBCA66 /* beep.caf */; };
9E5A62291A52DE07002E41A3 /* (null) in Sources */ = {isa = PBXBuildFile; };
9EE7232C1A5939070081D0D2 /* AppDelegate+APPLocalNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 9EE7232B1A5939070081D0D2 /* AppDelegate+APPLocalNotification.m */; };
B806D27D183342679EFA5FDA /* UIApplication+APPLocalNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 4AED74474D334999971FB4EC /* UIApplication+APPLocalNotification.m */; };
C6FCBB7BC1B947B699E811A8 /* UILocalNotification+APPLocalNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 276D2A95483249CBA0DAE4F5 /* UILocalNotification+APPLocalNotification.m */; };
D4A0D8761607E02300AEF8BB /* Default-568h@2x~iphone.png in Resources */ = {isa = PBXBuildFile; fileRef = D4A0D8751607E02300AEF8BB /* Default-568h@2x~iphone.png */; };
CA0BCB16FD114E5D98BB8665 /* APPLocalNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = B7A9F628139346BE899623CA /* APPLocalNotification.m */; };
8D642299F02F486292B3C76E /* APPLocalNotificationOptions.m in Sources */ = {isa = PBXBuildFile; fileRef = EEBC8449D0FA45AD8BED33D9 /* APPLocalNotificationOptions.m */; };
210AC435FA28427D89EF30B0 /* AppDelegate+APPLocalNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 05D703B6E20A498E8D8AE569 /* AppDelegate+APPLocalNotification.m */; };
9D4370C7345340D7A4AA7847 /* UIApplication+APPLocalNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = C8655474DBF6499D9A190B41 /* UIApplication+APPLocalNotification.m */; };
915750F942AB41089D8C019C /* UILocalNotification+APPLocalNotification.m in Sources */ = {isa = PBXBuildFile; fileRef = 84C3C8CF254E4643AA6619F8 /* UILocalNotification+APPLocalNotification.m */; };
/* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */
......@@ -71,14 +70,11 @@
/* End PBXContainerItemProxy section */
/* Begin PBXFileReference section */
0CEF91E2548247489CAFC744 /* AppDelegate+APPLocalNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "AppDelegate+APPLocalNotification.h"; path = "de.appplant.cordova.plugin.local-notification/AppDelegate+APPLocalNotification.h"; sourceTree = "<group>"; };
1D3623240D0F684500981E51 /* AppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = "<group>"; };
1D3623250D0F684500981E51 /* AppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = "<group>"; };
1D6058910D05DD3D006BFB54 /* NotificationExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = NotificationExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
212EBD1D7BCB4409838CD818 /* CDVDevice.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = CDVDevice.m; path = org.apache.cordova.device/CDVDevice.m; sourceTree = "<group>"; };
276D2A95483249CBA0DAE4F5 /* UILocalNotification+APPLocalNotification.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UILocalNotification+APPLocalNotification.m"; path = "de.appplant.cordova.plugin.local-notification/UILocalNotification+APPLocalNotification.m"; sourceTree = "<group>"; };
288765FC0DF74451002DB57D /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; };
2957C36784934F95AA71AD0C /* APPLocalNotificationOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = APPLocalNotificationOptions.h; path = "de.appplant.cordova.plugin.local-notification/APPLocalNotificationOptions.h"; sourceTree = "<group>"; };
29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = "<group>"; };
301BF52D109A57CC0062928A /* CordovaLib.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = CordovaLib.xcodeproj; path = CordovaLib/CordovaLib.xcodeproj; sourceTree = "<group>"; };
301BF56E109A69640062928A /* www */ = {isa = PBXFileReference; lastKnownFileType = folder; path = www; sourceTree = SOURCE_ROOT; };
......@@ -101,11 +97,7 @@
30C1856519D5FC0A00212699 /* icon-60@3x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-60@3x.png"; sourceTree = "<group>"; };
30FC414816E50CA1004E6F35 /* icon-72@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-72@2x.png"; sourceTree = "<group>"; };
32CA4F630368D1EE00C91783 /* NotificationExample-Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NotificationExample-Prefix.pch"; sourceTree = "<group>"; };
3BC46FA50763408493A28CD0 /* UILocalNotification+APPLocalNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UILocalNotification+APPLocalNotification.h"; path = "de.appplant.cordova.plugin.local-notification/UILocalNotification+APPLocalNotification.h"; sourceTree = "<group>"; };
3C888438876C480D8B36E11A /* APPBackgroundMode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = APPBackgroundMode.h; path = "de.appplant.cordova.plugin.background-mode/APPBackgroundMode.h"; sourceTree = "<group>"; };
4AED74474D334999971FB4EC /* UIApplication+APPLocalNotification.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "UIApplication+APPLocalNotification.m"; path = "de.appplant.cordova.plugin.local-notification/UIApplication+APPLocalNotification.m"; sourceTree = "<group>"; };
51E3BEE46964498795BC65EC /* APPLocalNotificationOptions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = APPLocalNotificationOptions.m; path = "de.appplant.cordova.plugin.local-notification/APPLocalNotificationOptions.m"; sourceTree = "<group>"; };
5ABA551B6BA54E6885F278AA /* UIApplication+APPLocalNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = "UIApplication+APPLocalNotification.h"; path = "de.appplant.cordova.plugin.local-notification/UIApplication+APPLocalNotification.h"; sourceTree = "<group>"; };
5B1594DC16A7569C00FEF299 /* AssetsLibrary.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AssetsLibrary.framework; path = System/Library/Frameworks/AssetsLibrary.framework; sourceTree = SDKROOT; };
7E7966D41810823500FA85AD /* icon-40.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-40.png"; sourceTree = "<group>"; };
7E7966D51810823500FA85AD /* icon-40@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-40@2x.png"; sourceTree = "<group>"; };
......@@ -118,10 +110,7 @@
7E7966DC1810823500FA85AD /* icon-small.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-small.png"; sourceTree = "<group>"; };
7E7966DD1810823500FA85AD /* icon-small@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "icon-small@2x.png"; sourceTree = "<group>"; };
8D1107310486CEB800E47090 /* NotificationExample-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = "NotificationExample-Info.plist"; path = "../NotificationExample-Info.plist"; plistStructureDefinitionIdentifier = "com.apple.xcode.plist.structure-definition.iphone.info-plist"; sourceTree = "<group>"; };
9C396B7AA36E4F79A25451A3 /* APPLocalNotification.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = APPLocalNotification.m; path = "de.appplant.cordova.plugin.local-notification/APPLocalNotification.m"; sourceTree = "<group>"; };
9E1A68371A55FA1B00FBCA66 /* beep.caf */ = {isa = PBXFileReference; lastKnownFileType = file; path = beep.caf; sourceTree = "<group>"; };
9EE7232B1A5939070081D0D2 /* AppDelegate+APPLocalNotification.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "AppDelegate+APPLocalNotification.m"; path = "de.appplant.cordova.plugin.local-notification/AppDelegate+APPLocalNotification.m"; sourceTree = "<group>"; };
B03D3EA8EA7D4F8A8A9A1E6A /* APPLocalNotification.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = APPLocalNotification.h; path = "de.appplant.cordova.plugin.local-notification/APPLocalNotification.h"; sourceTree = "<group>"; };
D4A0D8751607E02300AEF8BB /* Default-568h@2x~iphone.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "Default-568h@2x~iphone.png"; sourceTree = "<group>"; };
DDDFCE9D76CA4692A1F4A984 /* APPBackgroundMode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = APPBackgroundMode.m; path = "de.appplant.cordova.plugin.background-mode/APPBackgroundMode.m"; sourceTree = "<group>"; };
E02030E711134A5D8215D2F0 /* appbeep.wav */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = unknown; path = appbeep.wav; sourceTree = "<group>"; };
......@@ -129,6 +118,16 @@
EB87FDF41871DAF40020F90C /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = config.xml; path = ../../config.xml; sourceTree = "<group>"; };
F042F1C3B49D4E2699FF5E1D /* CDVDevice.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = CDVDevice.h; path = org.apache.cordova.device/CDVDevice.h; sourceTree = "<group>"; };
F840E1F0165FE0F500CFE078 /* config.xml */ = {isa = PBXFileReference; lastKnownFileType = text.xml; name = config.xml; path = NotificationExample/config.xml; sourceTree = "<group>"; };
B7A9F628139346BE899623CA /* APPLocalNotification.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "APPLocalNotification.m"; path = "de.appplant.cordova.plugin.local-notification/APPLocalNotification.m"; sourceTree = "<group>"; fileEncoding = 4; };
EEBC8449D0FA45AD8BED33D9 /* APPLocalNotificationOptions.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "APPLocalNotificationOptions.m"; path = "de.appplant.cordova.plugin.local-notification/APPLocalNotificationOptions.m"; sourceTree = "<group>"; fileEncoding = 4; };
05D703B6E20A498E8D8AE569 /* AppDelegate+APPLocalNotification.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "AppDelegate+APPLocalNotification.m"; path = "de.appplant.cordova.plugin.local-notification/AppDelegate+APPLocalNotification.m"; sourceTree = "<group>"; fileEncoding = 4; };
C8655474DBF6499D9A190B41 /* UIApplication+APPLocalNotification.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "UIApplication+APPLocalNotification.m"; path = "de.appplant.cordova.plugin.local-notification/UIApplication+APPLocalNotification.m"; sourceTree = "<group>"; fileEncoding = 4; };
84C3C8CF254E4643AA6619F8 /* UILocalNotification+APPLocalNotification.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; name = "UILocalNotification+APPLocalNotification.m"; path = "de.appplant.cordova.plugin.local-notification/UILocalNotification+APPLocalNotification.m"; sourceTree = "<group>"; fileEncoding = 4; };
127A135649D64CABB0063273 /* APPLocalNotification.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "APPLocalNotification.h"; path = "de.appplant.cordova.plugin.local-notification/APPLocalNotification.h"; sourceTree = "<group>"; fileEncoding = 4; };
B3D907064563496780573DE7 /* APPLocalNotificationOptions.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "APPLocalNotificationOptions.h"; path = "de.appplant.cordova.plugin.local-notification/APPLocalNotificationOptions.h"; sourceTree = "<group>"; fileEncoding = 4; };
FB8D07B5AA2E400F9E8F513D /* AppDelegate+APPLocalNotification.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "AppDelegate+APPLocalNotification.h"; path = "de.appplant.cordova.plugin.local-notification/AppDelegate+APPLocalNotification.h"; sourceTree = "<group>"; fileEncoding = 4; };
D98538C2D7AC4EDC9D924184 /* UIApplication+APPLocalNotification.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "UIApplication+APPLocalNotification.h"; path = "de.appplant.cordova.plugin.local-notification/UIApplication+APPLocalNotification.h"; sourceTree = "<group>"; fileEncoding = 4; };
EF204AFEDEC24A64A5F26DF6 /* UILocalNotification+APPLocalNotification.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; name = "UILocalNotification+APPLocalNotification.h"; path = "de.appplant.cordova.plugin.local-notification/UILocalNotification+APPLocalNotification.h"; sourceTree = "<group>"; fileEncoding = 4; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
......@@ -232,16 +231,16 @@
212EBD1D7BCB4409838CD818 /* CDVDevice.m */,
3C888438876C480D8B36E11A /* APPBackgroundMode.h */,
DDDFCE9D76CA4692A1F4A984 /* APPBackgroundMode.m */,
0CEF91E2548247489CAFC744 /* AppDelegate+APPLocalNotification.h */,
9EE7232B1A5939070081D0D2 /* AppDelegate+APPLocalNotification.m */,
B03D3EA8EA7D4F8A8A9A1E6A /* APPLocalNotification.h */,
9C396B7AA36E4F79A25451A3 /* APPLocalNotification.m */,
2957C36784934F95AA71AD0C /* APPLocalNotificationOptions.h */,
51E3BEE46964498795BC65EC /* APPLocalNotificationOptions.m */,
5ABA551B6BA54E6885F278AA /* UIApplication+APPLocalNotification.h */,
4AED74474D334999971FB4EC /* UIApplication+APPLocalNotification.m */,
3BC46FA50763408493A28CD0 /* UILocalNotification+APPLocalNotification.h */,
276D2A95483249CBA0DAE4F5 /* UILocalNotification+APPLocalNotification.m */,
B7A9F628139346BE899623CA /* APPLocalNotification.m */,
EEBC8449D0FA45AD8BED33D9 /* APPLocalNotificationOptions.m */,
05D703B6E20A498E8D8AE569 /* AppDelegate+APPLocalNotification.m */,
C8655474DBF6499D9A190B41 /* UIApplication+APPLocalNotification.m */,
84C3C8CF254E4643AA6619F8 /* UILocalNotification+APPLocalNotification.m */,
127A135649D64CABB0063273 /* APPLocalNotification.h */,
B3D907064563496780573DE7 /* APPLocalNotificationOptions.h */,
FB8D07B5AA2E400F9E8F513D /* AppDelegate+APPLocalNotification.h */,
D98538C2D7AC4EDC9D924184 /* UIApplication+APPLocalNotification.h */,
EF204AFEDEC24A64A5F26DF6 /* UILocalNotification+APPLocalNotification.h */,
);
name = Plugins;
path = NotificationExample/Plugins;
......@@ -432,11 +431,12 @@
9E5A62291A52DE07002E41A3 /* (null) in Sources */,
0B33C5FC1B224A91B96FDE79 /* CDVDevice.m in Sources */,
3DBE1CCC022B412AA9E356AF /* APPBackgroundMode.m in Sources */,
26914B69E52E40E893E4C399 /* APPLocalNotification.m in Sources */,
979DDA8725D74CA3A4E545F8 /* APPLocalNotificationOptions.m in Sources */,
0FFC7382D3B74FADB62619F0 /* UIApplication+APPLocalNotification.h in Sources */,
B806D27D183342679EFA5FDA /* UIApplication+APPLocalNotification.m in Sources */,
C6FCBB7BC1B947B699E811A8 /* UILocalNotification+APPLocalNotification.m in Sources */,
CA0BCB16FD114E5D98BB8665 /* APPLocalNotification.m in Sources */,
8D642299F02F486292B3C76E /* APPLocalNotificationOptions.m in Sources */,
210AC435FA28427D89EF30B0 /* AppDelegate+APPLocalNotification.m in Sources */,
9D4370C7345340D7A4AA7847 /* UIApplication+APPLocalNotification.m in Sources */,
915750F942AB41089D8C019C /* UILocalNotification+APPLocalNotification.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
......
......@@ -24,21 +24,31 @@
@interface APPLocalNotification : CDVPlugin
// Executes all queued events
// Execute all queued events
- (void) deviceready:(CDVInvokedUrlCommand*)command;
// Schedules a new local notification
// Schedule a new notification
- (void) add:(CDVInvokedUrlCommand*)command;
// Cancels a given local notification
// Update a notification
- (void) update:(CDVInvokedUrlCommand*)command;
// Cancel a given notification
- (void) cancel:(CDVInvokedUrlCommand*)command;
// Cancels all currently scheduled notifications
// Cancel all currently scheduled notifications
- (void) cancelAll:(CDVInvokedUrlCommand*)command;
// Checks wether a notification with an ID is scheduled
// Check if a notification with an ID is scheduled
- (void) isScheduled:(CDVInvokedUrlCommand*)command;
// Retrieves a list of ids from all currently pending notifications
// Check if a notification with an ID was triggered
- (void) isTriggered:(CDVInvokedUrlCommand*)command;
// List all ids from all pending notifications
- (void) getScheduledIds:(CDVInvokedUrlCommand*)command;
// Informs if the app has the permission to show notifications
// List all ids from all triggered notifications
- (void) getTriggeredIds:(CDVInvokedUrlCommand*)command;
// List all properties for given scheduled notifications
- (void) getScheduled:(CDVInvokedUrlCommand*)command;
// List all properties for given triggered notifications
- (void) getTriggered:(CDVInvokedUrlCommand*)command;
// Inform if the app has the permission to show notifications
- (void) hasPermission:(CDVInvokedUrlCommand*)command;
// Registers permission to show notifications
// Register permission to show notifications
- (void) registerPermission:(CDVInvokedUrlCommand*)command;
@end
......@@ -72,7 +72,7 @@
NSArray* notifications = command.arguments;
[self.commandDelegate runInBackground:^{
for (NSMutableDictionary* options in notifications) {
for (NSDictionary* options in notifications) {
UILocalNotification* notification;
notification = [[UILocalNotification alloc]
......@@ -91,6 +91,39 @@
}
/**
* 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) {
NSString* id = [options objectForKey:@"id"];
UILocalNotification* notification;
notification = [[UIApplication sharedApplication]
scheduledLocalNotificationWithId:id];
if (!notification)
continue;
[self updateLocalNotification:[notification copy]
withOptions:options];
if (notifications.count > 1) {
[NSThread sleepForTimeInterval:0.01];
}
}
[self execCallback:command];
}];
}
/**
* Cancel a set of notifications.
*
* @param ids
......@@ -117,7 +150,7 @@
}
/**
* Cancels all currently scheduled notifications.
* Cancel all currently scheduled notifications.
*/
- (void) cancelAll:(CDVInvokedUrlCommand*)command
{
......@@ -157,7 +190,35 @@
}
/**
* List of ids from all currently pending notifications.
* Check if a notification with an ID was triggered.
*
* @param id
* The ID of the notification
*/
- (void) isTriggered:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
NSString* id = [[command arguments]
objectAtIndex:0];
CDVPluginResult* result;
UILocalNotification* notification;
notification = [[UIApplication sharedApplication]
triggeredLocalNotificationWithId:id];
bool isTriggered = notification != NULL;
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsBool:isTriggered];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
}
/**
* List all ids from all pending notifications.
*/
- (void) getScheduledIds:(CDVInvokedUrlCommand*)command
{
......@@ -177,27 +238,48 @@
}
/**
* Checks wether a notification with an ID was triggered.
*
* @param id
* The ID of the notification
* List all ids from all triggered notifications.
*/
- (void) isTriggered:(CDVInvokedUrlCommand*)command
- (void) getTriggeredIds:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
NSString* id = [[command arguments]
objectAtIndex:0];
CDVPluginResult* result;
UILocalNotification* notification;
NSArray* triggeredIds;
notification = [[UIApplication sharedApplication]
triggeredLocalNotificationWithId:id];
triggeredIds = [[UIApplication sharedApplication]
triggeredLocalNotificationIds];
bool isTriggered = notification != NULL;
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:triggeredIds];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
}
/**
* List all properties for given scheduled notifications.
*
* @param ids
* The IDs of the notifications
*/
- (void) getScheduled:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
NSArray* ids = command.arguments;
NSArray* notifications;
CDVPluginResult* result;
if (ids.count == 0) {
notifications = [[UIApplication sharedApplication]
scheduledLocalNotificationOptions];
} else {
notifications = [[UIApplication sharedApplication]
scheduledLocalNotificationOptions:ids];
}
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsBool:isTriggered];
messageAsArray:notifications];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
......@@ -205,19 +287,28 @@
}
/**
* Retrieves a list of ids from all currently triggered notifications.
* List all properties for given triggered notifications.
*
* @param ids
* The IDs of the notifications
*/
- (void) getTriggeredIds:(CDVInvokedUrlCommand*)command
- (void) getTriggered:(CDVInvokedUrlCommand *)command
{
[self.commandDelegate runInBackground:^{
NSArray* ids = command.arguments;
NSArray* notifications;
CDVPluginResult* result;
NSArray* triggeredIds;
triggeredIds = [[UIApplication sharedApplication]
triggeredLocalNotificationIds];
if (ids.count == 0) {
notifications = [[UIApplication sharedApplication]
triggeredLocalNotificationOptions];
} else {
notifications = [[UIApplication sharedApplication]
triggeredLocalNotificationOptions:ids];
}
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:triggeredIds];
messageAsArray:notifications];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
......@@ -278,13 +369,28 @@
}
/**
* 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 the local notification.
*/
- (void) cancelLocalNotification:(UILocalNotification*)notification
{
if (!notification)
return;
[[UIApplication sharedApplication]
cancelLocalNotification:notification];
......@@ -297,15 +403,6 @@
*/
- (void) cancelAllLocalNotifications
{
NSArray* notifications;
notifications = [[UIApplication sharedApplication]
scheduledLocalNotifications];
for (UILocalNotification* notification in notifications) {
[self cancelLocalNotification:notification];
}
[[UIApplication sharedApplication]
cancelAllLocalNotifications];
......@@ -343,7 +440,7 @@
for (UILocalNotification* notification in notifications)
{
if (notification && notification.repeatInterval == NSCalendarUnitEra
if (notification && [notification isRepeating]
&& notification.timeIntervalSinceFireDate > seconds)
{
[self cancelLocalNotification:notification];
......@@ -363,8 +460,11 @@
{
UILocalNotification* notification = [localNotification object];
if ([notification wasUpdated])
return;
BOOL autoCancel = notification.options.autoCancel;
NSTimeInterval timeInterval = notification.timeIntervalSinceFireDate;
NSTimeInterval timeInterval = [notification timeIntervalSinceFireDate];
NSString* event = (timeInterval <= 1 && deviceready) ? @"trigger" : @"click";
......@@ -502,7 +602,7 @@
if (notification) {
NSString* id = notification.options.id;
NSString* json = notification.options.json;
NSString* args = [notification.options encodeToJSON];
NSString* args = [notification encodeToJSON];
params = [NSString stringWithFormat:
@"\"%@\",\"%@\",\\'%@\\',JSON.parse(\\'%@\\')",
......
......@@ -33,8 +33,6 @@
@property (readonly, getter=repeatInterval) NSCalendarUnit repeatInterval;
@property (readonly, getter=userInfo) NSDictionary* userInfo;
// Encode the user info dict to JSON
- (NSString*) encodeToJSON;
// If it's a repeating notification
- (BOOL) isRepeating;
......
......@@ -213,28 +213,6 @@
}
/**
* Encode the user info dict to JSON.
*/
- (NSString*) encodeToJSON
{
NSString* json;
NSData* data;
NSMutableDictionary* obj = [dict mutableCopy];
[obj removeObjectForKey:@"json"];
data = [NSJSONSerialization dataWithJSONObject:obj
options:NSJSONWritingPrettyPrinted
error:Nil];
json = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
return [json stringByReplacingOccurrencesOfString:@"\n"
withString:@""];
}
/**
* If it's a repeating notification.
*/
- (BOOL) isRepeating
......
......@@ -33,5 +33,13 @@
- (UILocalNotification*) scheduledLocalNotificationWithId:(NSString*)id;
// Get the triggered local notification by ID
- (UILocalNotification*) triggeredLocalNotificationWithId:(NSString*)id;
// List of properties from all scheduled notifications
- (NSArray*) scheduledLocalNotificationOptions;
// List of properties from given scheduled notifications
- (NSArray*) scheduledLocalNotificationOptions:(NSArray*)ids;
// List of properties from all triggered notifications
- (NSArray*) triggeredLocalNotificationOptions;
// List of properties from given triggered notifications
- (NSArray*) triggeredLocalNotificationOptions:(NSArray*)ids;
@end
......@@ -97,15 +97,15 @@
*/
- (NSArray*) triggeredLocalNotificationIds
{
NSArray* triggeredNotifications = self.triggeredLocalNotifications;
NSMutableArray* triggeredNotificationIds = [[NSMutableArray alloc] init];
NSArray* notifications = self.triggeredLocalNotifications;
NSMutableArray* ids = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in triggeredNotifications)
for (UILocalNotification* notification in notifications)
{
[triggeredNotificationIds addObject:notification.options.id];
[ids addObject:notification.options.id];
}
return triggeredNotificationIds;
return ids;
}
/**
......@@ -113,22 +113,24 @@
*/
- (NSArray*) scheduledLocalNotificationIds
{
NSArray* scheduledNotifications = self.scheduledLocalNotifications;
NSMutableArray* scheduledNotificationIds = [[NSMutableArray alloc] init];
NSArray* notifications = self.scheduledLocalNotifications;
NSMutableArray* ids = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in scheduledNotifications)
{
if (notification)
for (UILocalNotification* notification in notifications)
{
[scheduledNotificationIds addObject:notification.options.id];
if (notification) {
[ids addObject:notification.options.id];
}
}
return scheduledNotificationIds;
return ids;
}
/**
* Get the scheduled local notification by ID.
*
* @param id
* Notification ID
*/
- (UILocalNotification*) scheduledLocalNotificationWithId:(NSString*)id
{
......@@ -136,8 +138,7 @@
for (UILocalNotification* notification in notifications)
{
if (notification && [notification.options.id isEqualToString:id])
{
if (notification && [notification.options.id isEqualToString:id]) {
return notification;
}
}
......@@ -147,6 +148,9 @@
/**
* Get the triggered local notification by ID.
*
* @param id
* Notification ID
*/
- (UILocalNotification*) triggeredLocalNotificationWithId:(NSString*)id
{
......@@ -159,4 +163,84 @@
return NULL;
}
/**
* List of properties from all scheduled notifications.
*/
- (NSArray*) scheduledLocalNotificationOptions
{
NSArray* notifications = self.scheduledLocalNotifications;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications)
{
if (notification) {
[options addObject:notification.userInfo];
}
}
return options;
}
/**
* List of properties from given scheduled notifications.
*
* @param ids
* Notification IDs
*/
- (NSArray*) scheduledLocalNotificationOptions:(NSArray*)ids
{
UILocalNotification* notification;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (NSString* id in ids)
{
notification = [self scheduledLocalNotificationWithId:id];
if (notification) {
[options addObject:notification.userInfo];
}
}
return options;
}
/**
* List of properties from all triggered notifications.
*/
- (NSArray*) triggeredLocalNotificationOptions
{
NSArray* notifications = self.triggeredLocalNotifications;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications)
{
[options addObject:notification.userInfo];
}
return options;
}
/**
* List of properties from given triggered notifications.
*
* @param ids
* Notification IDs
*/
- (NSArray*) triggeredLocalNotificationOptions:(NSArray*)ids
{
UILocalNotification* notification;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (NSString* id in ids)
{
notification = [self triggeredLocalNotificationWithId:id];
if (notification) {
[options addObject:notification.userInfo];
}
}
return options;
}
@end
......@@ -33,7 +33,11 @@
- (BOOL) wasInThePast;
// If the notification was already triggered
- (BOOL) wasTriggered;
// If the notification was updated
- (BOOL) wasUpdated;
// If it's a repeating notification
- (BOOL) isRepeating;
// Encode the user info dict to JSON
- (NSString*) encodeToJSON;
@end
......@@ -28,7 +28,7 @@ static char optionsKey;
@implementation UILocalNotification (APPLocalNotification)
#pragma mark -
#pragma mark Init methods
#pragma mark Init
/**
* Initialize a local notification with the given options when calling on JS side:
......@@ -59,6 +59,10 @@ static char optionsKey;
self.repeatInterval = options.repeatInterval;
self.alertBody = options.alertBody;
self.soundName = options.soundName;
if ([self wasInThePast]) {
self.fireDate = [NSDate date];
}
}
#pragma mark -
......@@ -143,7 +147,7 @@ static char optionsKey;
*/
- (BOOL) wasInThePast
{
return [self timeIntervalSinceFireDate] < 0;
return [self timeIntervalSinceFireDate] > 0;
}
/**
......@@ -160,6 +164,22 @@ static char optionsKey;
}
/**
* 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
......@@ -167,4 +187,27 @@ static char optionsKey;
return [self.options isRepeating];
}
/**
* Encode the user info dict to JSON.
*/
- (NSString*) encodeToJSON
{
NSString* json;
NSData* data;
NSMutableDictionary* obj = [self.userInfo mutableCopy];
[obj removeObjectForKey:@"json"];
[obj removeObjectForKey:@"updatedAt"];
data = [NSJSONSerialization dataWithJSONObject:obj
options:NSJSONWritingPrettyPrinted
error:Nil];
json = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
return [json stringByReplacingOccurrencesOfString:@"\n"
withString:@""];
}
@end
......@@ -95,6 +95,7 @@
<a href="#" class="button" onclick="scheduleMultiple()">Schedule multiple<br/><span class="hint">notification.local.add()</span></a>
<a href="#" class="button" onclick="scheduleDelayed()">Schedule in 5 sec<br/><span class="hint">notification.local.add([])</span></a>
<a href="#" class="button" onclick="scheduleMinutely()">Schedule every min<br/><span class="hint">notification.local.add()</span></a>
<a href="#" class="button" onclick="update()">Update<br/><span class="hint">notification.local.update()</span></a>
<a href="#" class="button" onclick="cancel()">Cancel<br/><span class="hint">notification.local.cancel()</span></a>
<a href="#" class="button" onclick="cancelMultiple()">Cancel multiple<br/><span class="hint">notification.local.cancel([])</span></a>
<a href="#" class="button" onclick="cancelAll()">Cancel all<br/><span class="hint">notification.local.cancelAll()</span></a>
......@@ -112,7 +113,7 @@
var counter = 0, id = 1;
var callback = function () {
alert('finished or canceled');
getScheduledIds();
};
hasPermission = function () {
......@@ -131,23 +132,20 @@
plugin.notification.local.add({
id: id,
message: 'Test Message ' + (++counter),
json: { test: id }
json: { test:id }
});
};
scheduleMultiple = function () {
plugin.notification.local.add([{
id: id,
message: 'Multi Message ' + (++counter),
json: { test: id }
message: 'Multi Message ' + (++counter)
},{
id: id+1,
message: 'Multi Message ' + (++counter),
json: { test: id+1 }
message: 'Multi Message ' + (++counter)
},{
id: id+2,
message: 'Multi Message ' + (++counter),
json: { test: id+2 }
message: 'Multi Message ' + (++counter)
}]);
};
......@@ -173,6 +171,14 @@
});
};
update = function () {
plugin.notification.local.update({
id: id,
message: 'Updated Message ' + (counter),
json: { updated:true }
});
};
cancel = function () {
counter = 0;
plugin.notification.local.cancel(id,callback);
......
......@@ -98,20 +98,20 @@ exports.setDefaults = function (newDefaults) {
/**
* Add a new entry to the registry
*
* @param {Object} props
* @param {Object} opts
* The notification properties
* @param {Function} callback
* A function to be called after the notification has been canceled
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.add = function (props, callback, scope) {
exports.add = function (opts, callback, scope) {
this.registerPermission(function(granted) {
if (!granted)
return;
var notifications = Array.isArray(props) ? props : [props];
var notifications = Array.isArray(opts) ? opts : [opts];
for (var i = 0; i < notifications.length; i++) {
var properties = notifications[i];
......@@ -120,50 +120,56 @@ exports.add = function (props, callback, scope) {
this.convertProperties(properties);
}
if (device.platform != 'iOS') {
notifications = notifications[0];
}
this.exec('add', notifications, callback, scope);
}, this);
};
/**
* Update existing notification specified by ID in options.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.update = function (options, callback, scope) {
this.exec('update', options, callback, scope);
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);
};
/**
* Clears the specified notification.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.clear = function (id, callback, scope) {
var notId = (id || '0').toString();
exports.clear = function (ids, callback, scope) {
ids = Array.isArray(ids) ? ids : [ids];
this.exec('clear', notId, callback, scope);
ids = this.convertIds(ids);
this.exec('clear', ids, callback, scope);
};
/**
* Clears all previously sheduled notifications.
* Clear all previously sheduled notifications.
*
* @param {Function} callback
* A function to be called after all notifications have been cleared
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.clearAll = function (callback, scope) {
......@@ -171,36 +177,30 @@ exports.clearAll = function (callback, scope) {
};
/**
* Cancels the specified notifications.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.cancel = function (ids, callback, scope) {
ids = Array.isArray(ids) ? ids : [ids];
for (var i = 0; i < ids.length; i++) {
ids[i] = ids[i].toString();
}
if (device.platform != 'iOS') {
ids = ids[0];
}
ids = this.convertIds(ids);
this.exec('cancel', ids, callback, scope);
};
/**
* Removes all previously registered notifications.
* Remove all previously registered notifications.
*
* @param {Function} callback
* A function to be called after all notifications have been canceled
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.cancelAll = function (callback, scope) {
......@@ -208,39 +208,55 @@ exports.cancelAll = function (callback, scope) {
};
/**
* Retrieves a list with all currently pending notifications.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.getScheduledIds = function (callback, scope) {
this.exec('getScheduledIds', null, callback, scope);
exports.isScheduled = function (id, callback, scope) {
var notId = (id || '0').toString();
this.exec('isScheduled', notId, callback, scope);
};
/**
* Checks wether a notification with an ID is scheduled.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.isScheduled = function (id, callback, scope) {
exports.isTriggered = function (id, callback, scope) {
var notId = (id || '0').toString();
this.exec('isScheduled', notId, callback, scope);
this.exec('isTriggered', notId, callback, scope);
};
/**
* Retrieves a list with all triggered notifications.
* List all currently pending notifications.
*
* @param {Function} callback
* A callback function to be called with the list
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.getScheduledIds = function (callback, scope) {
this.exec('getScheduledIds', null, callback, scope);
};
/**
* List 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.getTriggeredIds = function (callback, scope) {
......@@ -248,19 +264,89 @@ exports.getTriggeredIds = function (callback, scope) {
};
/**
* Checks wether a notification with an ID was triggered.
* List all properties for given scheduled notifications.
* If called without IDs, all notification will be returned.
*
* @param {String} id
* The ID of the notification
* @param {Number[]?} ids
* Set of notification IDs
* @param {Function} callback
* A callback function to be called with the list
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.isTriggered = function (id, callback, scope) {
var notId = (id || '0').toString();
exports.getScheduled = function () {
var args = Array.apply(null, arguments);
this.exec('isTriggered', notId, callback, scope);
if (typeof args[0] == 'function') {
args.unshift([]);
}
var ids = args[0],
callback = args[1],
scope = args[2];
if (!Array.isArray(ids)) {
ids = [ids];
}
ids = this.convertIds(ids);
this.exec('getScheduled', ids, callback, scope);
};
/**
* Retrieve the properties 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);
};
/**
* List all properties 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];
}
ids = this.convertIds(ids);
this.exec('getTriggered', ids, callback, scope);
};
/**
* Retrieve the properties 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);
};
/**
......@@ -318,102 +404,6 @@ exports.promptForPermission = function (callback, scope) {
};
/**
* Add new entries to the registry (more than one)
*
* @param {Object} options
* The notification properties
* @param {Function} callback
* A function to be called after the notification has been added
* @param {Object} scope
* The scope for the callback function
*
* @return {Number}
* The notification's ID
*/
exports.addMultiple = function (notifications, callback, scope) {
var length = notifications.length;
var notificationsMerged = new Array(),
callbackFn = this.createCallbackFn(callback, scope);
for (var i=0;i<length;i++){
var options = this.mergeWithDefaults(notifications[i]);
if (options.id) {
options.id = options.id.toString();
}
if (options.date === undefined) {
options.date = new Date();
}
if (options.title) {
options.title = options.title.toString();
}
if (options.message) {
options.message = options.message.toString();
}
if (typeof options.date == 'object') {
options.date = Math.round(options.date.getTime()/1000);
}
if (['WinCE', 'Win32NT'].indexOf(device.platform) > -1) {
callbackFn = function (cmd) {
eval(cmd);
};
}
notificationsMerged.push(options);
}
cordova.exec(callbackFn, null, 'LocalNotification', 'addMultiple', notificationsMerged);
return options.id;
};
/**
* Clear the specified notifications (more than one).
*
* @param {String} id
* The ID of the notification
* @param {Function} callback
* A function to be called after the notifications has been cleared.
* @param {Object} scope
* The scope for the callback function
*/
exports.clearMultiple = function (ids, callback, scope) {
var length = ids.length;
var idArray = new Array(),
callbackFn = this.createCallbackFn(callback, scope);
for (var i=0;i<length;i++){
var id = ids[i].toString();
idArray.push(id);
}
var callbackFn = this.createCallbackFn(callback, scope);
cordova.exec(callbackFn, null, 'LocalNotification', 'clearMultiple', [ids]);
};
/**
* Cancel the specified notifications (more than one).
*
* @param {String} id
* The ID of the notification
* @param {Function} callback
* A function to be called after the notifications has been canceled
* @param {Object} scope
* The scope for the callback function
*/
exports.cancelMultiple = function (ids, callback, scope) {
var length = ids.length;
var idArray = new Array(),
callbackFn = this.createCallbackFn(callback, scope);
for (var i=0;i<length;i++){
var id = ids[i].toString();
idArray.push(id);
}
var callbackFn = this.createCallbackFn(callback, scope);
cordova.exec(callbackFn, null, 'LocalNotification', 'cancelMultiple', [ids]);
};
/**
* Occurs when a notification was added.
*
* @param {String} id
......@@ -604,6 +594,25 @@ exports.createCallbackFn = function (callbackFn, scope) {
/**
* @private
*
* Convert the IDs to Strings.
*
* @param {String/Number[]} ids
*
* @return Array of Strings
*/
exports.convertIds = function (ids) {
var convertedIds = [];
for (var i = 0; i < ids.length; i++) {
convertedIds.push(ids[i].toString());
}
return convertedIds;
};
/**
* @private
*
* Executes the native counterpart.
*
* @param {String} action
......
......@@ -40,9 +40,9 @@
<source-file src="src/ios/APPLocalNotificationOptions.m" />
<header-file src="src/ios/AppDelegate+APPLocalNotification.h" />
<header-file src="src/ios/AppDelegate+APPLocalNotification.m" />
<source-file src="src/ios/AppDelegate+APPLocalNotification.m" />
<source-file src="src/ios/UIApplication+APPLocalNotification.h" />
<header-file src="src/ios/UIApplication+APPLocalNotification.h" />
<source-file src="src/ios/UIApplication+APPLocalNotification.m" />
<header-file src="src/ios/UILocalNotification+APPLocalNotification.h" />
......@@ -100,14 +100,19 @@
<source-file src="src/android/LocalNotification.java" target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/Receiver.java" target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/Options.java" target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/Restore.java" target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/ReceiverActivity.java" target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/DeleteIntentReceiver.java" target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file src="src/android/notification/Options.java" target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file src="src/android/notification/Asset.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/NotificationBuilder.java" target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file src="src/android/notification/NotificationWrapper.java" target-dir="src/de/appplant/cordova/plugin/notification" />
</platform>
<!-- wp8 -->
<platform name="wp8">
<!-- <platform name="wp8">
<config-file target="config.xml" parent="/*">
<feature name="LocalNotification">
<param name="wp-package" value="LocalNotification"/>
......@@ -116,6 +121,6 @@
<source-file src="src/wp8/LocalNotification.cs" />
<source-file src="src/wp8/Options.cs" />
</platform>
</platform> -->
</plugin>
......@@ -23,6 +23,7 @@ package de.appplant.cordova.plugin.localnotification;
import java.util.Date;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
......@@ -31,10 +32,15 @@ import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import de.appplant.cordova.plugin.notification.Options;
public class DeleteIntentReceiver extends BroadcastReceiver {
public static final String OPTIONS = "LOCAL_NOTIFICATION_OPTIONS";
/**
* Is called when a Notification is cleared manualy by the User
*/
@Override
public void onReceive(Context context, Intent intent) {
Options options = null;
......@@ -53,7 +59,8 @@ public class DeleteIntentReceiver extends BroadcastReceiver {
Date now = new Date();
if ((options.getInterval()!=0)){
LocalNotification.persist(options.getId(), setInitDate(args));
options.setInitDate();
LocalNotification.persist(options.getId(), options.getJSONObject());
}
else if((new Date(options.getDate()).before(now))){
LocalNotification.unpersist(options.getId());
......@@ -62,21 +69,12 @@ public class DeleteIntentReceiver extends BroadcastReceiver {
fireClearEvent(options);
}
private JSONObject setInitDate(JSONObject arguments){
long initialDate = arguments.optLong("date", 0) * 1000;
try {
arguments.put("initialDate", initialDate);
} catch (JSONException e) {
e.printStackTrace();
}
return arguments;
}
/**
* Fires onclear event.
*/
private void fireClearEvent (Options options) {
LocalNotification.fireEvent("clear", options.getId(), options.getJSON());
JSONArray data = new JSONArray().put(options.getJSONObject());
LocalNotification.fireEvent("clear", options.getId(), options.getJSON(),data);
}
}
......@@ -22,14 +22,12 @@
package de.appplant.cordova.plugin.localnotification;
import java.util.ArrayList;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView;
import org.apache.cordova.LOG;
import org.apache.cordova.PluginResult;
import org.json.JSONArray;
import org.json.JSONException;
......@@ -38,13 +36,13 @@ import org.json.JSONObject;
import android.app.Activity;
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.content.SharedPreferences.Editor;
import android.os.Build;
import android.widget.Toast;
import android.annotation.TargetApi;
import de.appplant.cordova.plugin.notification.*;
/**
* This plugin utilizes the Android AlarmManager in combination with StatusBar
......@@ -55,13 +53,16 @@ import android.widget.Toast;
public class LocalNotification extends CordovaPlugin {
protected final static String PLUGIN_NAME = "LocalNotification";
static protected final String STORAGE_FOLDER = "/localnotification";
private static CordovaWebView webView = null;
private static Boolean deviceready = false;
protected static Context context = null;
protected static Boolean isInBackground = true;
private static ArrayList<String> eventQueue = new ArrayList<String>();
static Activity activity;
Asset asset;
Manager manager;
NotificationWrapper nWrapper;
@Override
public void initialize (CordovaInterface cordova, CordovaWebView webView) {
......@@ -70,29 +71,27 @@ public class LocalNotification extends CordovaPlugin {
LocalNotification.webView = super.webView;
LocalNotification.context = super.cordova.getActivity().getApplicationContext();
LocalNotification.activity = super.cordova.getActivity();
this.asset = new Asset(activity,STORAGE_FOLDER);
this.manager = new Manager(context, PLUGIN_NAME);
this.nWrapper = new NotificationWrapper(context,Receiver.class,PLUGIN_NAME,Receiver.OPTIONS);
}
@Override
public boolean execute (String action, final JSONArray args, final CallbackContext command) throws JSONException {
if (action.equalsIgnoreCase("add")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
JSONObject arguments = setInitDate(args.optJSONObject(0));
Options options = new Options(context).parse(arguments);
add(options, true);
command.success();
}
});
}
if (action.equalsIgnoreCase("addMultiple")) {
if (action.equalsIgnoreCase("add")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
JSONArray notifications = args.optJSONArray(0);
for (int i =0; i<notifications.length();i++){
JSONObject arguments = setInitDate(notifications.optJSONObject(i));
JSONObject arguments;
for(int i=0;i<notifications.length();i++){
arguments = notifications.optJSONObject(i);
LOG.d("LocalNotification", arguments.toString());
arguments = asset.parseURIs(arguments);
Options options = new Options(context).parse(arguments);
add(options, true);
options.setInitDate();
nWrapper.schedule(options);
JSONArray data = new JSONArray().put(options.getJSONObject());
fireEvent("add", options.getId(), options.getJSON(), data);
}
command.success();
}
......@@ -102,75 +101,84 @@ public class LocalNotification extends CordovaPlugin {
if (action.equalsIgnoreCase("update")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
JSONObject updates = args.optJSONObject(0);
JSONArray updates = args.optJSONArray(0);
JSONObject updateContent;
for(int i=0;i<updates.length();i++){
updateContent = args.optJSONObject(i);
update(updates);
command.success();
}
});
nWrapper.update(updateContent);
}
if (action.equalsIgnoreCase("clear")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
String id = args.optString(0);
clear(id);
command.success();
}
});
}
if (action.equalsIgnoreCase("clearMultiple")) {
if (action.equalsIgnoreCase("cancel")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
JSONArray ids = args.optJSONArray(0);
for (int i =0; i<ids.length();i++){
clear(ids.optString(i));
String id;
for(int i=0;i<ids.length();i++){
id = args.optString(i);
nWrapper.cancel(id);
JSONArray managerId = new JSONArray().put(id);
JSONArray data = new JSONArray().put(manager.getAll(managerId));
fireEvent("cancel", id, "",data);
}
command.success();
}
});
}
if (action.equalsIgnoreCase("clearAll")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
clearAll();
command.success();
}
});
}
if (action.equalsIgnoreCase("cancel")) {
if (action.equalsIgnoreCase("cancelAll")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
String id = args.optString(0);
cancel(id);
unpersist(id);
JSONArray options = manager.getAll();
nWrapper.cancelAll();
String id;
JSONObject arguments;
for(int i=0;i<options.length();i++){
arguments= (JSONObject) options.opt(i);
JSONArray data = new JSONArray().put(arguments);
id = arguments.optString("id");
fireEvent("cancel", id, "",data);
}
command.success();
}
});
}
if (action.equalsIgnoreCase("cancelMultiple")) {
if (action.equalsIgnoreCase("clear")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
JSONArray ids = args.optJSONArray(0);
for (int i =0; i<ids.length();i++){
cancel(ids.optString(i));
String id;
for(int i=0;i<ids.length();i++){
id = args.optString(i);
nWrapper.clear(id);
JSONArray managerId = new JSONArray().put(id);
JSONArray data = new JSONArray().put(manager.getAll(managerId));
fireEvent("clear", id, "",data);
}
command.success();
}
});
}
if (action.equalsIgnoreCase("cancelAll")) {
if (action.equalsIgnoreCase("clearAll")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
cancelAll();
unpersistAll();
JSONArray options = manager.getAll();
nWrapper.clearAll();
String id;
JSONObject arguments;
for(int i=0;i<options.length();i++){
arguments= (JSONObject) options.opt(i);
JSONArray data = new JSONArray().put(arguments);
id = arguments.optString("id");
fireEvent("clear", id, "",data);
}
command.success();
}
});
......@@ -178,22 +186,74 @@ public class LocalNotification extends CordovaPlugin {
if (action.equalsIgnoreCase("isScheduled")) {
String id = args.optString(0);
isScheduled(id, command);
boolean isScheduled = manager.isScheduled(id);
PluginResult result = new PluginResult(PluginResult.Status.OK, (isScheduled));
command.sendPluginResult(result);
}
if (action.equalsIgnoreCase("getScheduledIds")) {
getScheduledIds(command);
if (action.equalsIgnoreCase("isTriggered")) {
String id = args.optString(0);
boolean isTriggered = manager.isTriggered(id);
PluginResult result = new PluginResult(PluginResult.Status.OK, isTriggered);
command.sendPluginResult(result);
}
if (action.equalsIgnoreCase("isTriggered")) {
if (action.equalsIgnoreCase("exist")) {
String id = args.optString(0);
boolean exist = manager.exist(id);
PluginResult result = new PluginResult(PluginResult.Status.OK, exist);
command.sendPluginResult(result);
}
isTriggered(id, command);
if (action.equalsIgnoreCase("getScheduledIds")) {
JSONArray scheduledIds = manager.getScheduledIds();
command.success(scheduledIds);
}
if (action.equalsIgnoreCase("getTriggeredIds")) {
getTriggeredIds(command);
JSONArray triggeredIds = manager.getTriggeredIds();
command.success(triggeredIds);
}
if (action.equalsIgnoreCase("getAllIds")) {
JSONArray allIds = manager.getAllIds();
command.success(allIds);
}
if (action.equalsIgnoreCase("getAll")) {
JSONArray ids;
JSONArray all;
try{
ids = args.getJSONArray(0);
all = manager.getAll(ids);
} catch (JSONException jse){
all = manager.getAll();
}
command.success(all);
}
if (action.equalsIgnoreCase("getTriggered")) {
JSONArray ids;
JSONArray triggered;
try{
ids = args.getJSONArray(0);
triggered = manager.getTriggered(ids);
} catch (JSONException jse){
triggered = manager.getTriggered();
}
command.success(triggered);
}
if (action.equalsIgnoreCase("getScheduled")) {
JSONArray ids;
JSONArray scheduled;
try{
ids = args.getJSONArray(0);
scheduled = manager.getScheduled(ids);
} catch (JSONException jse){
scheduled = manager.getScheduled();
}
command.success(scheduled);
}
if (action.equalsIgnoreCase("deviceready")) {
......@@ -222,311 +282,13 @@ public class LocalNotification extends CordovaPlugin {
deviceready = true;
for (String js : eventQueue) {
webView.sendJavascript(js);
sendJavascript(js);
}
eventQueue.clear();
}
/**
* Set an alarm.
*
* @param options
* The options that can be specified per alarm.
* @param doFireEvent
* If the onadd callback shall be called.
*/
public static void add (Options options, boolean doFireEvent) {
long triggerTime = options.getDate();
persist(options.getId(), options.getJSONObject());
//Intent is called when the Notification gets fired
Intent intent = new Intent(context, Receiver.class)
.setAction("" + options.getId())
.putExtra(Receiver.OPTIONS, options.getJSONObject().toString());
AlarmManager am = getAlarmManager();
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
if (doFireEvent) {
fireEvent("add", options.getId(), options.getJSON());
}
am.set(AlarmManager.RTC_WAKEUP, triggerTime, pi);
}
/**
* Update an existing notification
*
* @param updates JSONObject with update-content
*/
public static void update (JSONObject updates){
String id = updates.optString("id", "0");
// update shared preferences
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
JSONObject arguments;
try {
arguments = new JSONObject(alarms.get(id).toString());
} catch (JSONException e) {
e.printStackTrace();
return;
}
arguments = updateArguments(arguments, updates);
// cancel existing alarm
Intent intent = new Intent(context, Receiver.class)
.setAction("" + id);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager am = getAlarmManager();
am.cancel(pi);
//add new alarm
Options options = new Options(context).parse(arguments);
add(options,false);
}
/**
* Clear a specific notification without canceling repeating alarms
*
* @param notificationID
* The original ID of the notification that was used when it was
* registered using add()
*/
public static void clear (String notificationId){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
NotificationManager nc = getNotificationManager();
try {
nc.cancel(Integer.parseInt(notificationId));
} catch (Exception e) {}
JSONObject arguments;
try {
arguments = new JSONObject(alarms.get(notificationId).toString());
Options options = new Options(context).parse(arguments);
Date now = new Date();
if ((options.getInterval()!=0)){
persist(notificationId, setInitDate(arguments));
}
else if((new Date(options.getDate()).before(now))){
unpersist(notificationId);
}
} catch (JSONException e) {
e.printStackTrace();
return;
}
fireEvent("clear", notificationId, "");
}
/**
* Clear all notifications without canceling repeating alarms
*/
public static void clearAll (){
SharedPreferences settings = getSharedPreferences();
NotificationManager nc = getNotificationManager();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
for (String alarmId : alarmIds) {
clear(alarmId);
}
nc.cancelAll();
}
/**
* Cancel a specific notification that was previously registered.
*
* @param notificationId
* The original ID of the notification that was used when it was
* registered using add()
*/
public static void cancel (String notificationId) {
/*
* Create an intent that looks similar, to the one that was registered
* using add. 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.
*/
Intent intent = new Intent(context, Receiver.class)
.setAction("" + notificationId);
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, 0);
AlarmManager am = getAlarmManager();
NotificationManager nc = getNotificationManager();
am.cancel(pi);
try {
nc.cancel(Integer.parseInt(notificationId));
} catch (Exception e) {}
fireEvent("cancel", notificationId, "");
}
/**
* Cancel all notifications that were created by this plugin.
*
* Android can only unregister a specific alarm. There is no such thing
* as cancelAll. Therefore we rely on the Shared Preferences which holds
* all our alarms to loop through these alarms and unregister them one
* by one.
*/
public static void cancelAll() {
SharedPreferences settings = getSharedPreferences();
NotificationManager nc = getNotificationManager();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
for (String alarmId : alarmIds) {
cancel(alarmId);
}
nc.cancelAll();
}
/**
* Checks if a notification with an ID is scheduled.
*
* @param id
* The notification ID to be check.
* @param callbackContext
*/
public static void isScheduled (String id, CallbackContext command) {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
boolean isScheduled = alarms.containsKey(id);
boolean isNotTriggered = false;
if (isScheduled) {
JSONObject arguments;
try {
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getDate());
isNotTriggered = new Date().before(fireDate);
} catch (JSONException e) {
isNotTriggered = false;
e.printStackTrace();
}
}
PluginResult result = new PluginResult(PluginResult.Status.OK, (isScheduled && isNotTriggered));
command.sendPluginResult(result);
}
/**
* Retrieves a list with all currently pending notifications.
*
* @param callbackContext
*/
public static void getScheduledIds (CallbackContext command) {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray scheduledIds = new JSONArray();
for (String id : alarmIds) {
boolean isScheduled;
JSONObject arguments;
try {
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getDate());
isScheduled = new Date().before(fireDate);
} catch (JSONException e) {
isScheduled = false;
e.printStackTrace();
}
if (isScheduled){
scheduledIds.put(id);
}
}
command.success(scheduledIds);
}
/**
* Checks if a notification with an ID was triggered.
*
* @param id
* The notification ID to be check.
* @param callbackContext
*/
public static void isTriggered (String id, CallbackContext command) {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
boolean isScheduled = alarms.containsKey(id);
boolean isTriggered = isScheduled;
if (isScheduled) {
JSONObject arguments;
try {
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getInitialDate());
isTriggered = new Date().after(fireDate);
} catch (JSONException e) {
isTriggered = false;
e.printStackTrace();
}
}
PluginResult result = new PluginResult(PluginResult.Status.OK, isTriggered);
command.sendPluginResult(result);
}
/**
* Retrieves a list with all currently triggered notifications.
*
* @param callbackContext
*/
public static void getTriggeredIds (CallbackContext command) {
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray triggeredIds = new JSONArray();
Date now = new Date();
for (String id : alarmIds) {
boolean isTriggered;
JSONObject arguments;
try{
arguments = new JSONObject(alarms.get(id).toString());
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getInitialDate());
isTriggered = now.after(fireDate);
} catch(ClassCastException cce) {
cce.printStackTrace();
isTriggered = false;
}
catch(JSONException jse) {
jse.printStackTrace();
isTriggered = false;
}
if (isTriggered == true) {
triggeredIds.put(id);
}
}
command.success(triggeredIds);
}
/**
* Persist the information of this alarm to the Android Shared Preferences.
* This will allow the application to restore the alarm upon device reboot.
* Also this is used by the cancelAll method.
......@@ -582,6 +344,7 @@ public class LocalNotification extends CordovaPlugin {
}
}
//
/**
* Fires the given event.
*
......@@ -589,9 +352,11 @@ public class LocalNotification extends CordovaPlugin {
* @param {String} id The ID of the notification
* @param {String} json A custom (JSON) string
*/
public static void fireEvent (String event, String id, String json) {
public static void fireEvent (String event, String id, String json, JSONArray data) {
String state = getApplicationState();
//TODO dataArray handling
String params = "\"" + id + "\",\"" + state + "\",\\'" + JSONObject.quote(json) + "\\'.replace(/(^\"|\"$)/g, \\'\\')";
// params = params + "," + dataArray;
String js = "setTimeout('plugin.notification.local.on" + event + "(" + params + ")',0)";
// webview may available, but callbacks needs to be executed
......@@ -599,7 +364,7 @@ public class LocalNotification extends CordovaPlugin {
if (deviceready == false) {
eventQueue.add(js);
} else {
webView.sendJavascript(js);
sendJavascript(js);
}
}
......@@ -643,54 +408,21 @@ public class LocalNotification extends CordovaPlugin {
return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
/**
* Function to set the value of "initialDate" in the JSONArray
* @param args The given JSONArray
* @return A new JSONArray with the parameter "initialDate" set.
* Use this instead of deprecated sendJavascript
*/
private static JSONObject setInitDate(JSONObject arguments){
long initialDate = arguments.optLong("date", 0) * 1000;
try {
arguments.put("initialDate", initialDate);
} catch (JSONException e) {
e.printStackTrace();
}
return arguments;
}
private static JSONObject updateArguments(JSONObject arguments,JSONObject updates){
try {
if(!updates.isNull("message")){
arguments.put("message", updates.get("message"));
}
if(!updates.isNull("title")){
arguments.put("title", updates.get("title"));
}
if(!updates.isNull("badge")){
arguments.put("badge", updates.get("badge"));
}
if(!updates.isNull("sound")){
arguments.put("sound", updates.get("sound"));
}
if(!updates.isNull("icon")){
arguments.put("icon", updates.get("icon"));
}
} catch (JSONException jse){
jse.printStackTrace();
}
return arguments;
@TargetApi(Build.VERSION_CODES.KITKAT)
private static void sendJavascript(final String js){
webView.post(new Runnable(){
public void run(){
if(Build.VERSION.SDK_INT>= Build.VERSION_CODES.KITKAT){
webView.evaluateJavascript(js, null);
} else {
webView.loadUrl("javascript:" + js);
}
public static void showNotification(String title,String notification){
int duration = Toast.LENGTH_LONG;
if(title.equals("")){
title = "Notification";
}
String text = title + " \n " + notification;
Toast notificationToast = Toast.makeText(context, text, duration);
notificationToast.show();
});
}
......
/*
Copyright 2013-2014 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.
*/
package de.appplant.cordova.plugin.localnotification;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Calendar;
import java.util.Date;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.app.AlarmManager;
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.os.StrictMode.ThreadPolicy;
import android.util.Log;
/**
* Class that helps to store the options that can be specified per alarm.
*/
public class Options {
static protected final String STORAGE_FOLDER = "/localnotification";
private JSONObject options = new JSONObject();
private String packageName = null;
private long interval = 0;
Options (Activity activity) {
packageName = activity.getPackageName();
}
Options (Context context) {
packageName = context.getPackageName();
}
/**
* Parses the given properties
*/
public Options parse (JSONObject options) {
String repeat = options.optString("repeat");
this.options = options;
if (repeat.equalsIgnoreCase("secondly")) {
interval = 1000;
} if (repeat.equalsIgnoreCase("minutely")) {
interval = AlarmManager.INTERVAL_FIFTEEN_MINUTES / 15;
} if (repeat.equalsIgnoreCase("hourly")) {
interval = AlarmManager.INTERVAL_HOUR;
} if (repeat.equalsIgnoreCase("daily")) {
interval = AlarmManager.INTERVAL_DAY;
} else if (repeat.equalsIgnoreCase("weekly")) {
interval = AlarmManager.INTERVAL_DAY*7;
} else if (repeat.equalsIgnoreCase("monthly")) {
interval = AlarmManager.INTERVAL_DAY*31; // 31 days
} else if (repeat.equalsIgnoreCase("yearly")) {
interval = AlarmManager.INTERVAL_DAY*365;
} else {
try {
interval = Integer.parseInt(repeat) * 60000;
} catch (Exception e) {};
}
return this;
}
/**
* Set new time according to interval
*/
public Options moveDate () {
try {
options.put("date", (getDate() + interval) / 1000);
} catch (JSONException e) {}
return this;
}
/**
* Returns options as JSON object
*/
public JSONObject getJSONObject() {
return options;
}
/**
* Returns time in milliseconds when notification is scheduled to fire
*/
public long getDate() {
return options.optLong("date", 0) * 1000;
}
/**
* Returns time in milliseconds when the notification was scheduled first
*/
public long getInitialDate() {
return options.optLong("initialDate", 0);
}
/**
* Returns time as calender
*/
public Calendar getCalendar () {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date(getDate()));
return calendar;
}
/**
* Returns the notification's message
*/
public String getMessage () {
return options.optString("message", "");
}
/**
* Returns the notification's title
*/
public String getTitle () {
return options.optString("title", "");
}
/**
* Returns the path of the notification's sound file
*/
public Uri getSound () {
String sound = options.optString("sound", null);
if (sound != null) {
try {
int soundId = (Integer) RingtoneManager.class.getDeclaredField(sound).get(Integer.class);
return RingtoneManager.getDefaultUri(soundId);
} catch (Exception e) {
return getURIfromPath(sound);
}
}
return null;
}
/**
* Returns the icon's ID
*/
public Bitmap getIcon () {
String icon = options.optString("icon", "icon");
Bitmap bmp = null;
if (icon.startsWith("http")) {
bmp = getIconFromURL(icon);
} else if (icon.startsWith("file://") || (icon.startsWith("res"))) {
bmp = getIconFromURI(icon);
}
if (bmp == null) {
bmp = getIconFromRes(icon);
}
return bmp;
}
/**
* Returns the small icon's ID
*/
public int getSmallIcon () {
int resId = 0;
String iconName = options.optString("smallIcon", "");
resId = getIconValue(packageName, iconName);
if (resId == 0) {
resId = getIconValue("android", iconName);
}
if (resId == 0) {
resId = getIconValue(packageName, "icon");
}
return options.optInt("smallIcon", resId);
}
/**
* Returns notification repetition interval (daily, weekly, monthly, yearly)
*/
public long getInterval () {
return interval;
}
/**
* Returns notification badge number
*/
public int getBadge () {
return options.optInt("badge", 0);
}
/**
* Returns PluginResults' callback ID
*/
public String getId () {
return options.optString("id", "0");
}
/**
* Returns whether notification is cancelled automatically when clicked.
*/
public Boolean getAutoCancel () {
return options.optBoolean("autoCancel", false);
}
/**
* Returns whether the notification is ongoing (uncancellable). Android only.
*/
public Boolean getOngoing () {
return options.optBoolean("ongoing", false);
}
/**
* Returns additional data as string
*/
public String getJSON () {
return options.optString("json", "");
}
/**
* @return
* The notification color for LED
*/
public int getColor () {
String hexColor = options.optString("led", "000000");
int aRGB = Integer.parseInt(hexColor,16);
aRGB += 0xFF000000;
return aRGB;
}
/**
* Returns numerical icon Value
*
* @param {String} className
* @param {String} iconName
*/
private int getIconValue (String className, String iconName) {
int icon = 0;
try {
Class<?> klass = Class.forName(className + ".R$drawable");
icon = (Integer) klass.getDeclaredField(iconName).get(Integer.class);
} catch (Exception e) {}
return icon;
}
/**
* Converts an resource to Bitmap.
*
* @param icon
* The resource name
* @return
* The corresponding bitmap
*/
private Bitmap getIconFromRes (String icon) {
Resources res = LocalNotification.context.getResources();
int iconId = 0;
iconId = getIconValue(packageName, icon);
if (iconId == 0) {
iconId = getIconValue("android", icon);
}
if (iconId == 0) {
iconId = android.R.drawable.ic_menu_info_details;
}
Bitmap bmp = BitmapFactory.decodeResource(res, iconId);
return bmp;
}
/**
* Converts an Image URL to Bitmap.
*
* @param src
* The external image URL
* @return
* The corresponding bitmap
*/
private Bitmap getIconFromURL (String src) {
Bitmap bmp = null;
ThreadPolicy origMode = StrictMode.getThreadPolicy();
try {
URL url = new URL(src);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
connection.setDoInput(true);
connection.connect();
InputStream input = connection.getInputStream();
bmp = BitmapFactory.decodeStream(input);
} catch (Exception e) {
e.printStackTrace();
}
StrictMode.setThreadPolicy(origMode);
return bmp;
}
/**
* Converts an Image URI to Bitmap.
*
* @param src
* The internal image URI
* @return
* The corresponding bitmap
*/
private Bitmap getIconFromURI (String src) {
Bitmap bmp = null;
Uri uri = getURIfromPath(src);
try {
InputStream input = LocalNotification.activity.getContentResolver().openInputStream(uri);
bmp = BitmapFactory.decodeStream(input);
} catch (IOException e) {
e.printStackTrace();
}
return bmp;
}
/**
* The URI for a path.
*
* @param path The given path
*
* @return The URI pointing to the given path
*/
private Uri getURIfromPath(String path){
if (path.startsWith("res:")) {
return getUriForResourcePath(path);
} else if (path.startsWith("file:///")) {
return getUriForAbsolutePath(path);
} else if (path.startsWith("file://")) {
return getUriForAssetPath(path);
}
return Uri.parse(path);
}
/**
* The URI for a file.
*
* @param path
* The given absolute path
*
* @return The URI pointing to the given path
*/
private Uri getUriForAbsolutePath(String path) {
String absPath = path.replaceFirst("file://", "");
File file = new File(absPath);
if (!file.exists()) {
Log.e("LocalNotifocation", "File not found: " + file.getAbsolutePath());
}
return Uri.fromFile(file);
}
/**
* The URI for an asset.
*
* @param path
* The given asset path
*
* @return The URI pointing to the given path
*/
private Uri getUriForAssetPath(String path) {
String resPath = path.replaceFirst("file:/", "www");
String fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
File dir = LocalNotification.activity.getExternalCacheDir();
if (dir == null) {
Log.e("LocalNotifocation", "Missing external cache dir");
return Uri.EMPTY;
}
String storage = dir.toString() + STORAGE_FOLDER;
File file = new File(storage, fileName);
new File(storage).mkdir();
try {
AssetManager assets = LocalNotification.activity.getAssets();
FileOutputStream outStream = new FileOutputStream(file);
InputStream inputStream = assets.open(resPath);
copyFile(inputStream, outStream);
outStream.flush();
outStream.close();
} catch (Exception e) {
Log.e("LocalNotifocation", "File not found: assets/" + resPath);
e.printStackTrace();
}
return Uri.fromFile(file);
}
/**
* The URI for a resource.
*
* @param path
* The given relative path
*
* @return The URI pointing to the given path
*/
private Uri getUriForResourcePath(String path) {
String resPath = path.replaceFirst("res://", "");
String fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
String resName = fileName.substring(0, fileName.lastIndexOf('.'));
String extension = resPath.substring(resPath.lastIndexOf('.'));
File dir = LocalNotification.activity.getExternalCacheDir();
if (dir == null) {
Log.e("LocalNotifocation", "Missing external cache dir");
return Uri.EMPTY;
}
String storage = dir.toString() + STORAGE_FOLDER;
int resId = getResId(resPath);
File file = new File(storage, resName + extension);
if (resId == 0) {
Log.e("LocalNotifocation", "File not found: " + resPath);
}
new File(storage).mkdir();
try {
Resources res = LocalNotification.activity.getResources();
FileOutputStream outStream = new FileOutputStream(file);
InputStream inputStream = res.openRawResource(resId);
copyFile(inputStream, outStream);
outStream.flush();
outStream.close();
} catch (Exception e) {
e.printStackTrace();
}
return Uri.fromFile(file);
}
/**
* Writes an InputStream to an OutputStream
*
* @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);
}
}
/**
* @return The resource ID for the given resource.
*/
private int getResId(String resPath) {
Resources res = LocalNotification.activity.getResources();
int resId;
String pkgName = getPackageName();
String dirName = "drawable";
String fileName = resPath;
if (resPath.contains("/")) {
dirName = resPath.substring(0, resPath.lastIndexOf('/'));
fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
}
String resName = fileName.substring(0, fileName.lastIndexOf('.'));
resId = res.getIdentifier(resName, dirName, pkgName);
if (resId == 0) {
resId = res.getIdentifier(resName, "drawable", pkgName);
}
return resId;
}
/**
* The name for the package.
*
* @return The package name
*/
private String getPackageName() {
return LocalNotification.activity.getPackageName();
}
/**
* Shows the behavior of notifications when the application is in foreground
*
*
*/
public boolean getForegroundMode(){
return options.optBoolean("foregroundMode",false);
}
}
......@@ -22,23 +22,18 @@
package de.appplant.cordova.plugin.localnotification;
import java.util.Calendar;
import java.util.Random;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.*;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import 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
......@@ -49,11 +44,12 @@ public class Receiver extends BroadcastReceiver {
public static final String OPTIONS = "LOCAL_NOTIFICATION_OPTIONS";
private Context context;
private Options options;
@Override
public void onReceive (Context context, Intent intent) {
NotificationWrapper nWrapper = new NotificationWrapper(context,
Receiver.class,LocalNotification.PLUGIN_NAME,OPTIONS);
Options options = null;
Bundle bundle = intent.getExtras();
JSONObject args;
......@@ -64,10 +60,11 @@ public class Receiver extends BroadcastReceiver {
} catch (JSONException e) {
return;
}
this.context = context;
this.options = options;
NotificationBuilder builder = new NotificationBuilder(options,context,OPTIONS,
DeleteIntentReceiver.class,ReceiverActivity.class);
// The context may got lost if the app was not running before
LocalNotification.setContext(context);
......@@ -77,18 +74,18 @@ public class Receiver extends BroadcastReceiver {
} else if (isFirstAlarmInFuture()) {
return;
} else {
LocalNotification.add(options.moveDate(), false);
nWrapper.schedule(options.moveDate());
}
if (!LocalNotification.isInBackground && options.getForegroundMode()){
if (options.getInterval() == 0) {
LocalNotification.unpersist(options.getId());
}
LocalNotification.showNotification(options.getTitle(), options.getMessage());
builder.showNotificationToast();
fireTriggerEvent();
} else {
Builder notification = buildNotification();
builder.buildNotification();
showNotification(notification);
builder.showNotification();
}
}
......@@ -118,85 +115,10 @@ public class Receiver extends BroadcastReceiver {
}
/**
* Creates the notification.
*/
@SuppressLint("NewApi")
private Builder buildNotification () {
Uri sound = options.getSound();
//DeleteIntent is called when the user clears a notification manually
Intent deleteIntent = new Intent(context, DeleteIntentReceiver.class)
.setAction("" + options.getId())
.putExtra(Receiver.OPTIONS, options.getJSONObject().toString());
PendingIntent dpi = PendingIntent.getBroadcast(context, 0, deleteIntent, PendingIntent.FLAG_CANCEL_CURRENT);
Builder notification = new NotificationCompat.Builder(context)
.setDefaults(0) // Do not inherit any defaults
.setContentTitle(options.getTitle())
.setContentText(options.getMessage())
.setNumber(options.getBadge())
.setTicker(options.getMessage())
.setSmallIcon(options.getSmallIcon())
.setLargeIcon(options.getIcon())
.setAutoCancel(options.getAutoCancel())
.setOngoing(options.getOngoing())
.setLights(options.getColor(), 500, 500)
.setDeleteIntent(dpi);
if (sound != null) {
notification.setSound(sound);
}
if (Build.VERSION.SDK_INT > 16) {
notification.setStyle(new NotificationCompat.BigTextStyle()
.bigText(options.getMessage()));
}
setClickEvent(notification);
return notification;
}
/**
* Adds an onclick handler to the notification
*/
private Builder setClickEvent (Builder notification) {
Intent intent = new Intent(context, ReceiverActivity.class)
.putExtra(OPTIONS, options.getJSONObject().toString())
.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
int requestCode = new Random().nextInt();
PendingIntent contentIntent = PendingIntent.getActivity(context, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
return notification.setContentIntent(contentIntent);
}
/**
* Shows the notification
*/
@SuppressWarnings("deprecation")
private void showNotification (Builder notification) {
NotificationManager mgr = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
int id = 0;
try {
id = Integer.parseInt(options.getId());
} catch (Exception e) {}
if (Build.VERSION.SDK_INT<16) {
// build notification for HoneyComb to ICS
mgr.notify(id, notification.getNotification());
} else if (Build.VERSION.SDK_INT>15) {
// Notification for Jellybean and above
mgr.notify(id, notification.build());
}
}
/**
* Fires ontrigger event.
*/
private void fireTriggerEvent () {
LocalNotification.fireEvent("trigger", options.getId(), options.getJSON());
JSONArray data = new JSONArray().put(options.getJSONObject());
LocalNotification.fireEvent("trigger", options.getId(), options.getJSON(),data);
}
}
......@@ -23,12 +23,15 @@ package de.appplant.cordova.plugin.localnotification;
import org.json.JSONException;
import org.json.JSONObject;
import org.json.JSONArray;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import de.appplant.cordova.plugin.notification.*;
public class ReceiverActivity extends Activity {
/** Called when the activity is first created. */
......@@ -65,10 +68,11 @@ public class ReceiverActivity extends Activity {
* Fires the onclick event.
*/
private void fireClickEvent (Options options) {
LocalNotification.fireEvent("click", options.getId(), options.getJSON());
JSONArray data = new JSONArray().put(options.getJSONObject());
LocalNotification.fireEvent("click", options.getId(), options.getJSON(),data);
if (options.getAutoCancel()) {
LocalNotification.fireEvent("cancel", options.getId(), options.getJSON());
LocalNotification.fireEvent("cancel", options.getId(), options.getJSON(),data);
}
}
}
......@@ -31,6 +31,8 @@ import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import de.appplant.cordova.plugin.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
......@@ -42,6 +44,9 @@ public class Restore extends BroadcastReceiver {
public void onReceive(Context context, Intent intent) {
// The application context needs to be set as first
LocalNotification.setContext(context);
//Create NotificationWrapper
NotificationWrapper nWrapper = new NotificationWrapper(context,
Receiver.class,LocalNotification.PLUGIN_NAME,Receiver.OPTIONS);
// Obtain alarm details form Shared Preferences
SharedPreferences alarms = LocalNotification.getSharedPreferences();
......@@ -59,7 +64,7 @@ public class Restore extends BroadcastReceiver {
/*
* If the trigger date was in the past, the notification will be displayed immediately.
*/
LocalNotification.add(options, false);
nWrapper.schedule(options);
} catch (JSONException e) {}
}
......
......@@ -24,21 +24,31 @@
@interface APPLocalNotification : CDVPlugin
// Executes all queued events
// Execute all queued events
- (void) deviceready:(CDVInvokedUrlCommand*)command;
// Schedules a new local notification
// Schedule a new notification
- (void) add:(CDVInvokedUrlCommand*)command;
// Cancels a given local notification
// Update a notification
- (void) update:(CDVInvokedUrlCommand*)command;
// Cancel a given notification
- (void) cancel:(CDVInvokedUrlCommand*)command;
// Cancels all currently scheduled notifications
// Cancel all currently scheduled notifications
- (void) cancelAll:(CDVInvokedUrlCommand*)command;
// Checks wether a notification with an ID is scheduled
// Check if a notification with an ID is scheduled
- (void) isScheduled:(CDVInvokedUrlCommand*)command;
// Retrieves a list of ids from all currently pending notifications
// Check if a notification with an ID was triggered
- (void) isTriggered:(CDVInvokedUrlCommand*)command;
// List all ids from all pending notifications
- (void) getScheduledIds:(CDVInvokedUrlCommand*)command;
// Informs if the app has the permission to show notifications
// List all ids from all triggered notifications
- (void) getTriggeredIds:(CDVInvokedUrlCommand*)command;
// List all properties for given scheduled notifications
- (void) getScheduled:(CDVInvokedUrlCommand*)command;
// List all properties for given triggered notifications
- (void) getTriggered:(CDVInvokedUrlCommand*)command;
// Inform if the app has the permission to show notifications
- (void) hasPermission:(CDVInvokedUrlCommand*)command;
// Registers permission to show notifications
// Register permission to show notifications
- (void) registerPermission:(CDVInvokedUrlCommand*)command;
@end
......@@ -69,15 +69,54 @@
*/
- (void) add:(CDVInvokedUrlCommand*)command
{
NSArray* notifications = command.arguments;
[self.commandDelegate runInBackground:^{
for (NSDictionary* options in command.arguments) {
for (NSDictionary* options in notifications) {
UILocalNotification* notification;
notification = [[UILocalNotification alloc]
initWithOptions:options];
[self scheduleLocalNotification:notification];
[self scheduleLocalNotification:[notification copy]];
[self fireEvent:@"add" localNotification: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) {
NSString* id = [options objectForKey:@"id"];
UILocalNotification* notification;
notification = [[UIApplication sharedApplication]
scheduledLocalNotificationWithId:id];
if (!notification)
continue;
[self updateLocalNotification:[notification copy]
withOptions:options];
if (notifications.count > 1) {
[NSThread sleepForTimeInterval:0.01];
}
}
[self execCallback:command];
......@@ -111,7 +150,7 @@
}
/**
* Cancels all currently scheduled notifications.
* Cancel all currently scheduled notifications.
*/
- (void) cancelAll:(CDVInvokedUrlCommand*)command
{
......@@ -151,7 +190,35 @@
}
/**
* List of ids from all currently pending notifications.
* Check if a notification with an ID was triggered.
*
* @param id
* The ID of the notification
*/
- (void) isTriggered:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
NSString* id = [[command arguments]
objectAtIndex:0];
CDVPluginResult* result;
UILocalNotification* notification;
notification = [[UIApplication sharedApplication]
triggeredLocalNotificationWithId:id];
bool isTriggered = notification != NULL;
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsBool:isTriggered];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
}
/**
* List all ids from all pending notifications.
*/
- (void) getScheduledIds:(CDVInvokedUrlCommand*)command
{
......@@ -171,27 +238,48 @@
}
/**
* Checks wether a notification with an ID was triggered.
*
* @param id
* The ID of the notification
* List all ids from all triggered notifications.
*/
- (void) isTriggered:(CDVInvokedUrlCommand*)command
- (void) getTriggeredIds:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
NSString* id = [[command arguments]
objectAtIndex:0];
CDVPluginResult* result;
UILocalNotification* notification;
NSArray* triggeredIds;
notification = [[UIApplication sharedApplication]
triggeredLocalNotificationWithId:id];
triggeredIds = [[UIApplication sharedApplication]
triggeredLocalNotificationIds];
bool isTriggered = notification != NULL;
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:triggeredIds];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
}
/**
* List all properties for given scheduled notifications.
*
* @param ids
* The IDs of the notifications
*/
- (void) getScheduled:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
NSArray* ids = command.arguments;
NSArray* notifications;
CDVPluginResult* result;
if (ids.count == 0) {
notifications = [[UIApplication sharedApplication]
scheduledLocalNotificationOptions];
} else {
notifications = [[UIApplication sharedApplication]
scheduledLocalNotificationOptions:ids];
}
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsBool:isTriggered];
messageAsArray:notifications];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
......@@ -199,19 +287,28 @@
}
/**
* Retrieves a list of ids from all currently triggered notifications.
* List all properties for given triggered notifications.
*
* @param ids
* The IDs of the notifications
*/
- (void) getTriggeredIds:(CDVInvokedUrlCommand*)command
- (void) getTriggered:(CDVInvokedUrlCommand *)command
{
[self.commandDelegate runInBackground:^{
NSArray* ids = command.arguments;
NSArray* notifications;
CDVPluginResult* result;
NSArray* triggeredIds;
triggeredIds = [[UIApplication sharedApplication]
triggeredLocalNotificationIds];
if (ids.count == 0) {
notifications = [[UIApplication sharedApplication]
triggeredLocalNotificationOptions];
} else {
notifications = [[UIApplication sharedApplication]
triggeredLocalNotificationOptions:ids];
}
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:triggeredIds];
messageAsArray:notifications];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
......@@ -267,25 +364,33 @@
{
[self cancelForerunnerLocalNotification:notification];
NSString* state = self.applicationState;
if ([state isEqualToString:@"background"]) {
[[UIApplication sharedApplication]
presentLocalNotificationNow:notification];
}
[[UIApplication sharedApplication]
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 the local notification.
*/
- (void) cancelLocalNotification:(UILocalNotification*)notification
{
if (!notification)
return;
[[UIApplication sharedApplication]
cancelLocalNotification:notification];
......@@ -298,15 +403,6 @@
*/
- (void) cancelAllLocalNotifications
{
NSArray* notifications;
notifications = [[UIApplication sharedApplication]
scheduledLocalNotifications];
for (UILocalNotification* notification in notifications) {
[self cancelLocalNotification:notification];
}
[[UIApplication sharedApplication]
cancelAllLocalNotifications];
......@@ -344,7 +440,7 @@
for (UILocalNotification* notification in notifications)
{
if (notification && notification.repeatInterval == NSCalendarUnitEra
if (notification && [notification isRepeating]
&& notification.timeIntervalSinceFireDate > seconds)
{
[self cancelLocalNotification:notification];
......@@ -364,8 +460,11 @@
{
UILocalNotification* notification = [localNotification object];
if ([notification wasUpdated])
return;
BOOL autoCancel = notification.options.autoCancel;
NSTimeInterval timeInterval = notification.timeIntervalSinceFireDate;
NSTimeInterval timeInterval = [notification timeIntervalSinceFireDate];
NSString* event = (timeInterval <= 1 && deviceready) ? @"trigger" : @"click";
......@@ -503,7 +602,7 @@
if (notification) {
NSString* id = notification.options.id;
NSString* json = notification.options.json;
NSString* args = [notification.options encodeToJSON];
NSString* args = [notification encodeToJSON];
params = [NSString stringWithFormat:
@"\"%@\",\"%@\",\\'%@\\',JSON.parse(\\'%@\\')",
......
......@@ -33,7 +33,7 @@
@property (readonly, getter=repeatInterval) NSCalendarUnit repeatInterval;
@property (readonly, getter=userInfo) NSDictionary* userInfo;
// Encode the user info dict to JSON
- (NSString*) encodeToJSON;
// If it's a repeating notification
- (BOOL) isRepeating;
@end
......@@ -82,7 +82,7 @@
- (BOOL) autoCancel
{
if (IsAtLeastiOSVersion(@"8.0")){
return self.repeatInterval == NSCalendarUnitEra;
return ![self isRepeating];
} else {
return [[dict objectForKey:@"autoCancel"] boolValue];
}
......@@ -201,6 +201,9 @@
return NSCalendarUnitEra;
}
#pragma mark -
#pragma mark Methods
/**
* The notification's user info dict.
*/
......@@ -210,25 +213,13 @@
}
/**
* Encode the user info dict to JSON.
* If it's a repeating notification.
*/
- (NSString*) encodeToJSON
- (BOOL) isRepeating
{
NSString* json;
NSData* data;
NSMutableDictionary* obj = [dict mutableCopy];
[obj removeObjectForKey:@"json"];
data = [NSJSONSerialization dataWithJSONObject:obj
options:NSJSONWritingPrettyPrinted
error:Nil];
json = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
NSCalendarUnit interval = self.repeatInterval;
return [json stringByReplacingOccurrencesOfString:@"\n"
withString:@""];
return !(interval == NSCalendarUnitEra || interval == 0);
}
#pragma mark -
......
......@@ -33,5 +33,13 @@
- (UILocalNotification*) scheduledLocalNotificationWithId:(NSString*)id;
// Get the triggered local notification by ID
- (UILocalNotification*) triggeredLocalNotificationWithId:(NSString*)id;
// List of properties from all scheduled notifications
- (NSArray*) scheduledLocalNotificationOptions;
// List of properties from given scheduled notifications
- (NSArray*) scheduledLocalNotificationOptions:(NSArray*)ids;
// List of properties from all triggered notifications
- (NSArray*) triggeredLocalNotificationOptions;
// List of properties from given triggered notifications
- (NSArray*) triggeredLocalNotificationOptions:(NSArray*)ids;
@end
......@@ -97,15 +97,15 @@
*/
- (NSArray*) triggeredLocalNotificationIds
{
NSArray* triggeredNotifications = self.triggeredLocalNotifications;
NSMutableArray* triggeredNotificationIds = [[NSMutableArray alloc] init];
NSArray* notifications = self.triggeredLocalNotifications;
NSMutableArray* ids = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in triggeredNotifications)
for (UILocalNotification* notification in notifications)
{
[triggeredNotificationIds addObject:notification.options.id];
[ids addObject:notification.options.id];
}
return triggeredNotificationIds;
return ids;
}
/**
......@@ -113,22 +113,24 @@
*/
- (NSArray*) scheduledLocalNotificationIds
{
NSArray* scheduledNotifications = self.scheduledLocalNotifications;
NSMutableArray* scheduledNotificationIds = [[NSMutableArray alloc] init];
NSArray* notifications = self.scheduledLocalNotifications;
NSMutableArray* ids = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in scheduledNotifications)
{
if (notification)
for (UILocalNotification* notification in notifications)
{
[scheduledNotificationIds addObject:notification.options.id];
if (notification) {
[ids addObject:notification.options.id];
}
}
return scheduledNotificationIds;
return ids;
}
/**
* Get the scheduled local notification by ID.
*
* @param id
* Notification ID
*/
- (UILocalNotification*) scheduledLocalNotificationWithId:(NSString*)id
{
......@@ -136,8 +138,7 @@
for (UILocalNotification* notification in notifications)
{
if (notification && [notification.options.id isEqualToString:id])
{
if (notification && [notification.options.id isEqualToString:id]) {
return notification;
}
}
......@@ -147,6 +148,9 @@
/**
* Get the triggered local notification by ID.
*
* @param id
* Notification ID
*/
- (UILocalNotification*) triggeredLocalNotificationWithId:(NSString*)id
{
......@@ -159,4 +163,84 @@
return NULL;
}
/**
* List of properties from all scheduled notifications.
*/
- (NSArray*) scheduledLocalNotificationOptions
{
NSArray* notifications = self.scheduledLocalNotifications;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications)
{
if (notification) {
[options addObject:notification.userInfo];
}
}
return options;
}
/**
* List of properties from given scheduled notifications.
*
* @param ids
* Notification IDs
*/
- (NSArray*) scheduledLocalNotificationOptions:(NSArray*)ids
{
UILocalNotification* notification;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (NSString* id in ids)
{
notification = [self scheduledLocalNotificationWithId:id];
if (notification) {
[options addObject:notification.userInfo];
}
}
return options;
}
/**
* List of properties from all triggered notifications.
*/
- (NSArray*) triggeredLocalNotificationOptions
{
NSArray* notifications = self.triggeredLocalNotifications;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications)
{
[options addObject:notification.userInfo];
}
return options;
}
/**
* List of properties from given triggered notifications.
*
* @param ids
* Notification IDs
*/
- (NSArray*) triggeredLocalNotificationOptions:(NSArray*)ids
{
UILocalNotification* notification;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (NSString* id in ids)
{
notification = [self triggeredLocalNotificationWithId:id];
if (notification) {
[options addObject:notification.userInfo];
}
}
return options;
}
@end
......@@ -33,5 +33,11 @@
- (BOOL) wasInThePast;
// If the notification was already triggered
- (BOOL) wasTriggered;
// If the notification was updated
- (BOOL) wasUpdated;
// If it's a repeating notification
- (BOOL) isRepeating;
// Encode the user info dict to JSON
- (NSString*) encodeToJSON;
@end
......@@ -28,7 +28,7 @@ static char optionsKey;
@implementation UILocalNotification (APPLocalNotification)
#pragma mark -
#pragma mark Init methods
#pragma mark Init
/**
* Initialize a local notification with the given options when calling on JS side:
......@@ -59,8 +59,15 @@ static char optionsKey;
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.
*/
......@@ -128,7 +135,7 @@ static char optionsKey;
int timespan = [now timeIntervalSinceDate:fireDate];
if (self.repeatInterval != NSCalendarUnitEra) {
if ([self isRepeating]) {
timespan = timespan % [self repeatIntervalInSeconds];
}
......@@ -140,7 +147,7 @@ static char optionsKey;
*/
- (BOOL) wasInThePast
{
return [self timeIntervalSinceFireDate] < 0;
return [self timeIntervalSinceFireDate] > 0;
}
/**
......@@ -156,4 +163,51 @@ static char optionsKey;
return isLaterThanOrEqualTo;
}
/**
* 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];
}
/**
* Encode the user info dict to JSON.
*/
- (NSString*) encodeToJSON
{
NSString* json;
NSData* data;
NSMutableDictionary* obj = [self.userInfo mutableCopy];
[obj removeObjectForKey:@"json"];
[obj removeObjectForKey:@"updatedAt"];
data = [NSJSONSerialization dataWithJSONObject:obj
options:NSJSONWritingPrettyPrinted
error:Nil];
json = [[NSString alloc] initWithData:data
encoding:NSUTF8StringEncoding];
return [json stringByReplacingOccurrencesOfString:@"\n"
withString:@""];
}
@end
......@@ -98,20 +98,20 @@ exports.setDefaults = function (newDefaults) {
/**
* Add a new entry to the registry
*
* @param {Object} props
* @param {Object} opts
* The notification properties
* @param {Function} callback
* A function to be called after the notification has been canceled
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.add = function (props, callback, scope) {
exports.add = function (opts, callback, scope) {
this.registerPermission(function(granted) {
if (!granted)
return;
var notifications = Array.isArray(props) ? props : [props];
var notifications = Array.isArray(opts) ? opts : [opts];
for (var i = 0; i < notifications.length; i++) {
var properties = notifications[i];
......@@ -120,50 +120,56 @@ exports.add = function (props, callback, scope) {
this.convertProperties(properties);
}
if (device.platform != 'iOS') {
notifications = notifications[0];
}
this.exec('add', notifications, callback, scope);
}, this);
};
/**
* Update existing notification specified by ID in options.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.update = function (options, callback, scope) {
this.exec('update', options, callback, scope);
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);
};
/**
* Clears the specified notification.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.clear = function (id, callback, scope) {
var notId = (id || '0').toString();
exports.clear = function (ids, callback, scope) {
ids = Array.isArray(ids) ? ids : [ids];
this.exec('clear', notId, callback, scope);
ids = this.convertIds(ids);
this.exec('clear', ids, callback, scope);
};
/**
* Clears all previously sheduled notifications.
* Clear all previously sheduled notifications.
*
* @param {Function} callback
* A function to be called after all notifications have been cleared
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.clearAll = function (callback, scope) {
......@@ -171,36 +177,30 @@ exports.clearAll = function (callback, scope) {
};
/**
* Cancels the specified notifications.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.cancel = function (ids, callback, scope) {
ids = Array.isArray(ids) ? ids : [ids];
for (var i = 0; i < ids.length; i++) {
ids[i] = ids[i].toString();
}
if (device.platform != 'iOS') {
ids = ids[0];
}
ids = this.convertIds(ids);
this.exec('cancel', ids, callback, scope);
};
/**
* Removes all previously registered notifications.
* Remove all previously registered notifications.
*
* @param {Function} callback
* A function to be called after all notifications have been canceled
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.cancelAll = function (callback, scope) {
......@@ -208,39 +208,55 @@ exports.cancelAll = function (callback, scope) {
};
/**
* Retrieves a list with all currently pending notifications.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.getScheduledIds = function (callback, scope) {
this.exec('getScheduledIds', null, callback, scope);
exports.isScheduled = function (id, callback, scope) {
var notId = (id || '0').toString();
this.exec('isScheduled', notId, callback, scope);
};
/**
* Checks wether a notification with an ID is scheduled.
* 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
* @param {Object?} scope
* The scope for the callback function
*/
exports.isScheduled = function (id, callback, scope) {
exports.isTriggered = function (id, callback, scope) {
var notId = (id || '0').toString();
this.exec('isScheduled', notId, callback, scope);
this.exec('isTriggered', notId, callback, scope);
};
/**
* Retrieves a list with all triggered notifications.
* List all currently pending notifications.
*
* @param {Function} callback
* A callback function to be called with the list
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.getScheduledIds = function (callback, scope) {
this.exec('getScheduledIds', null, callback, scope);
};
/**
* List 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.getTriggeredIds = function (callback, scope) {
......@@ -248,19 +264,89 @@ exports.getTriggeredIds = function (callback, scope) {
};
/**
* Checks wether a notification with an ID was triggered.
* List all properties for given scheduled notifications.
* If called without IDs, all notification will be returned.
*
* @param {String} id
* The ID of the notification
* @param {Number[]?} ids
* Set of notification IDs
* @param {Function} callback
* A callback function to be called with the list
* @param {Object} scope
* @param {Object?} scope
* The scope for the callback function
*/
exports.isTriggered = function (id, callback, scope) {
var notId = (id || '0').toString();
exports.getScheduled = function () {
var args = Array.apply(null, arguments);
this.exec('isTriggered', notId, callback, scope);
if (typeof args[0] == 'function') {
args.unshift([]);
}
var ids = args[0],
callback = args[1],
scope = args[2];
if (!Array.isArray(ids)) {
ids = [ids];
}
ids = this.convertIds(ids);
this.exec('getScheduled', ids, callback, scope);
};
/**
* Retrieve the properties 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);
};
/**
* List all properties 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];
}
ids = this.convertIds(ids);
this.exec('getTriggered', ids, callback, scope);
};
/**
* Retrieve the properties 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);
};
/**
......@@ -318,102 +404,6 @@ exports.promptForPermission = function (callback, scope) {
};
/**
* Add new entries to the registry (more than one)
*
* @param {Object} options
* The notification properties
* @param {Function} callback
* A function to be called after the notification has been added
* @param {Object} scope
* The scope for the callback function
*
* @return {Number}
* The notification's ID
*/
exports.addMultiple = function (notifications, callback, scope) {
var length = notifications.length;
var notificationsMerged = new Array(),
callbackFn = this.createCallbackFn(callback, scope);
for (var i=0;i<length;i++){
var options = this.mergeWithDefaults(notifications[i]);
if (options.id) {
options.id = options.id.toString();
}
if (options.date === undefined) {
options.date = new Date();
}
if (options.title) {
options.title = options.title.toString();
}
if (options.message) {
options.message = options.message.toString();
}
if (typeof options.date == 'object') {
options.date = Math.round(options.date.getTime()/1000);
}
if (['WinCE', 'Win32NT'].indexOf(device.platform) > -1) {
callbackFn = function (cmd) {
eval(cmd);
};
}
notificationsMerged.push(options);
}
cordova.exec(callbackFn, null, 'LocalNotification', 'addMultiple', notificationsMerged);
return options.id;
};
/**
* Clear the specified notifications (more than one).
*
* @param {String} id
* The ID of the notification
* @param {Function} callback
* A function to be called after the notifications has been cleared.
* @param {Object} scope
* The scope for the callback function
*/
exports.clearMultiple = function (ids, callback, scope) {
var length = ids.length;
var idArray = new Array(),
callbackFn = this.createCallbackFn(callback, scope);
for (var i=0;i<length;i++){
var id = ids[i].toString();
idArray.push(id);
}
var callbackFn = this.createCallbackFn(callback, scope);
cordova.exec(callbackFn, null, 'LocalNotification', 'clearMultiple', [ids]);
};
/**
* Cancel the specified notifications (more than one).
*
* @param {String} id
* The ID of the notification
* @param {Function} callback
* A function to be called after the notifications has been canceled
* @param {Object} scope
* The scope for the callback function
*/
exports.cancelMultiple = function (ids, callback, scope) {
var length = ids.length;
var idArray = new Array(),
callbackFn = this.createCallbackFn(callback, scope);
for (var i=0;i<length;i++){
var id = ids[i].toString();
idArray.push(id);
}
var callbackFn = this.createCallbackFn(callback, scope);
cordova.exec(callbackFn, null, 'LocalNotification', 'cancelMultiple', [ids]);
};
/**
* Occurs when a notification was added.
*
* @param {String} id
......@@ -604,6 +594,25 @@ exports.createCallbackFn = function (callbackFn, scope) {
/**
* @private
*
* Convert the IDs to Strings.
*
* @param {String/Number[]} ids
*
* @return Array of Strings
*/
exports.convertIds = function (ids) {
var convertedIds = [];
for (var i = 0; i < ids.length; i++) {
convertedIds.push(ids[i].toString());
}
return convertedIds;
};
/**
* @private
*
* Executes the native counterpart.
*
* @param {String} action
......
......@@ -95,6 +95,7 @@
<a href="#" class="button" onclick="scheduleMultiple()">Schedule multiple<br/><span class="hint">notification.local.add()</span></a>
<a href="#" class="button" onclick="scheduleDelayed()">Schedule in 5 sec<br/><span class="hint">notification.local.add([])</span></a>
<a href="#" class="button" onclick="scheduleMinutely()">Schedule every min<br/><span class="hint">notification.local.add()</span></a>
<a href="#" class="button" onclick="update()">Update<br/><span class="hint">notification.local.update()</span></a>
<a href="#" class="button" onclick="cancel()">Cancel<br/><span class="hint">notification.local.cancel()</span></a>
<a href="#" class="button" onclick="cancelMultiple()">Cancel multiple<br/><span class="hint">notification.local.cancel([])</span></a>
<a href="#" class="button" onclick="cancelAll()">Cancel all<br/><span class="hint">notification.local.cancelAll()</span></a>
......@@ -112,7 +113,7 @@
var counter = 0, id = 1;
var callback = function () {
alert('finished or canceled');
getScheduledIds();
};
hasPermission = function () {
......@@ -131,23 +132,20 @@
plugin.notification.local.add({
id: id,
message: 'Test Message ' + (++counter),
json: { test: id }
json: { test:id }
});
};
scheduleMultiple = function () {
plugin.notification.local.add([{
id: id,
message: 'Multi Message ' + (++counter),
json: { test: id }
message: 'Multi Message ' + (++counter)
},{
id: id+1,
message: 'Multi Message ' + (++counter),
json: { test: id+1 }
message: 'Multi Message ' + (++counter)
},{
id: id+2,
message: 'Multi Message ' + (++counter),
json: { test: id+2 }
message: 'Multi Message ' + (++counter)
}]);
};
......@@ -173,6 +171,14 @@
});
};
update = function () {
plugin.notification.local.update({
id: id,
message: 'Updated Message ' + (counter),
json: { updated:true }
});
};
cancel = function () {
counter = 0;
plugin.notification.local.cancel(id,callback);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment