Commit 6618cb2d by Sebastián Katzer

Update example

parent 4b537731
...@@ -11,12 +11,13 @@ ...@@ -11,12 +11,13 @@
</activity> </activity>
<service android:name="de.appplant.cordova.plugin.background.ForegroundService" /> <service android:name="de.appplant.cordova.plugin.background.ForegroundService" />
<receiver android:name="de.appplant.cordova.plugin.localnotification.Receiver" /> <receiver android:name="de.appplant.cordova.plugin.localnotification.Receiver" />
<receiver android:name="de.appplant.cordova.plugin.localnotification.DeleteIntentReceiver" />
<receiver android:name="de.appplant.cordova.plugin.localnotification.Restore"> <receiver android:name="de.appplant.cordova.plugin.localnotification.Restore">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" /> <action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter> </intent-filter>
</receiver> </receiver>
<activity android:launchMode="singleInstance" android:name="de.appplant.cordova.plugin.localnotification.ReceiverActivity" /> <activity android:launchMode="singleInstance" android:name="de.appplant.cordova.plugin.localnotification.ReceiverActivity" android:theme="@android:style/Theme.NoDisplay" />
</application> </application>
<uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19" /> <uses-sdk android:minSdkVersion="10" android:targetSdkVersion="19" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" /> <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
......
...@@ -92,9 +92,11 @@ ...@@ -92,9 +92,11 @@
<a href="#" class="button" onclick="hasPermission()">Has permission?<br/><span class="hint">notification.local.hasPermission()</span></a> <a href="#" class="button" onclick="hasPermission()">Has permission?<br/><span class="hint">notification.local.hasPermission()</span></a>
<a href="#" class="button" onclick="registerPermission()">Register permission<br/><span class="hint">notification.local.registerPermission()</span></a> <a href="#" class="button" onclick="registerPermission()">Register permission<br/><span class="hint">notification.local.registerPermission()</span></a>
<a href="#" class="button" onclick="schedule()">Schedule now<br/><span class="hint">notification.local.add()</span></a> <a href="#" class="button" onclick="schedule()">Schedule now<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="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="scheduleMinutely()">Schedule every min<br/><span class="hint">notification.local.add()</span></a>
<a href="#" class="button" onclick="cancel()">Cancel<br/><span class="hint">notification.local.cancel()</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> <a href="#" class="button" onclick="cancelAll()">Cancel all<br/><span class="hint">notification.local.cancelAll()</span></a>
<a href="#" class="button" onclick="getScheduledIds()">Scheduled IDs<br/><span class="hint">notification.local.getScheduledIds()</span></a> <a href="#" class="button" onclick="getScheduledIds()">Scheduled IDs<br/><span class="hint">notification.local.getScheduledIds()</span></a>
<a href="#" class="button" onclick="isScheduled()">Is scheduled?<br/><span class="hint">notification.local.isScheduled()</span></a> <a href="#" class="button" onclick="isScheduled()">Is scheduled?<br/><span class="hint">notification.local.isScheduled()</span></a>
...@@ -107,7 +109,7 @@ ...@@ -107,7 +109,7 @@
<script type="text/javascript" src="js/index.js"></script> <script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript"> <script type="text/javascript">
var counter = 0, id = 12; var counter = 1, id = 12;
var callback = function () { var callback = function () {
alert('finished or canceled'); alert('finished or canceled');
...@@ -129,10 +131,26 @@ ...@@ -129,10 +131,26 @@
plugin.notification.local.add({ plugin.notification.local.add({
id: id, id: id,
message: 'Test Message ' + (++counter), message: 'Test Message ' + (++counter),
json: { test: 123 } json: { test: id }
}); });
}; };
scheduleMultiple = function () {
plugin.notification.local.add([{
id: id,
message: 'Test Message ' + (++counter),
json: { test: id }
},{
id: id+1,
message: 'Test Message ' + (++counter),
json: { test: id+1 }
},{
id: id+2,
message: 'Test Message ' + (++counter),
json: { test: id+2 }
}]);
};
scheduleDelayed = function () { scheduleDelayed = function () {
var now = new Date().getTime(), var now = new Date().getTime(),
_5_sec_from_now = new Date(now + 5*1000); _5_sec_from_now = new Date(now + 5*1000);
...@@ -160,6 +178,11 @@ ...@@ -160,6 +178,11 @@
plugin.notification.local.cancel(id,callback); plugin.notification.local.cancel(id,callback);
}; };
cancelMultiple = function () {
counter = 0;
plugin.notification.local.cancel([id, id+1],callback);
};
cancelAll = function () { cancelAll = function () {
counter = 0; counter = 0;
plugin.notification.local.cancelAll(callback); plugin.notification.local.cancelAll(callback);
...@@ -198,7 +221,7 @@ ...@@ -198,7 +221,7 @@
<!-- callbacks --> <!-- callbacks -->
<script type="text/javascript"> <script type="text/javascript">
document.addEventListener('deviceready', function () { document.addEventListener('sdeviceready', function () {
plugin.notification.local.onadd = function (id, state, json) { plugin.notification.local.onadd = function (id, state, json) {
alert('on add\n' + Array.apply(null, arguments).join("\n")); alert('on add\n' + Array.apply(null, arguments).join("\n"));
}; };
......
/*
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.util.Date;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class DeleteIntentReceiver extends BroadcastReceiver {
public static final String OPTIONS = "LOCAL_NOTIFICATION_OPTIONS";
@Override
public void onReceive(Context context, Intent intent) {
Options options = null;
Bundle bundle = intent.getExtras();
JSONObject args;
try {
args = new JSONObject(bundle.getString(OPTIONS));
options = new Options(context).parse(args);
} catch (JSONException e) {
return;
}
// The context may got lost if the app was not running before
LocalNotification.setContext(context);
Date now = new Date();
if ((options.getInterval()!=0)){
LocalNotification.persist(options.getId(), setInitDate(args));
}
else if((new Date(options.getDate()).before(now))){
LocalNotification.unpersist(options.getId());
}
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());
}
}
...@@ -35,6 +35,7 @@ import org.json.JSONArray; ...@@ -35,6 +35,7 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import android.app.Activity;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
...@@ -43,6 +44,7 @@ import android.content.Intent; ...@@ -43,6 +44,7 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import android.os.Build; import android.os.Build;
import android.widget.Toast;
/** /**
* This plugin utilizes the Android AlarmManager in combination with StatusBar * This plugin utilizes the Android AlarmManager in combination with StatusBar
...@@ -59,6 +61,7 @@ public class LocalNotification extends CordovaPlugin { ...@@ -59,6 +61,7 @@ public class LocalNotification extends CordovaPlugin {
protected static Context context = null; protected static Context context = null;
protected static Boolean isInBackground = true; protected static Boolean isInBackground = true;
private static ArrayList<String> eventQueue = new ArrayList<String>(); private static ArrayList<String> eventQueue = new ArrayList<String>();
static Activity activity;
@Override @Override
public void initialize (CordovaInterface cordova, CordovaWebView webView) { public void initialize (CordovaInterface cordova, CordovaWebView webView) {
...@@ -66,6 +69,7 @@ public class LocalNotification extends CordovaPlugin { ...@@ -66,6 +69,7 @@ public class LocalNotification extends CordovaPlugin {
LocalNotification.webView = super.webView; LocalNotification.webView = super.webView;
LocalNotification.context = super.cordova.getActivity().getApplicationContext(); LocalNotification.context = super.cordova.getActivity().getApplicationContext();
LocalNotification.activity = super.cordova.getActivity();
} }
@Override @Override
...@@ -73,10 +77,66 @@ public class LocalNotification extends CordovaPlugin { ...@@ -73,10 +77,66 @@ public class LocalNotification extends CordovaPlugin {
if (action.equalsIgnoreCase("add")) { if (action.equalsIgnoreCase("add")) {
cordova.getThreadPool().execute( new Runnable() { cordova.getThreadPool().execute( new Runnable() {
public void run() { public void run() {
JSONObject arguments = setInitDate(args).optJSONObject(0); JSONObject arguments = setInitDate(args.optJSONObject(0));
Options options = new Options(context).parse(arguments); Options options = new Options(context).parse(arguments);
add(options, true);
command.success();
}
});
}
if (action.equalsIgnoreCase("addMultiple")) {
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));
Options options = new Options(context).parse(arguments);
add(options, true); add(options, true);
}
command.success();
}
});
}
if (action.equalsIgnoreCase("update")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
JSONObject updates = args.optJSONObject(0);
update(updates);
command.success();
}
});
}
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")) {
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));
}
command.success();
}
});
}
if (action.equalsIgnoreCase("clearAll")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
clearAll();
command.success(); command.success();
} }
}); });
...@@ -94,6 +154,18 @@ public class LocalNotification extends CordovaPlugin { ...@@ -94,6 +154,18 @@ public class LocalNotification extends CordovaPlugin {
}); });
} }
if (action.equalsIgnoreCase("cancelMultiple")) {
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));
}
command.success();
}
});
}
if (action.equalsIgnoreCase("cancelAll")) { if (action.equalsIgnoreCase("cancelAll")) {
cordova.getThreadPool().execute( new Runnable() { cordova.getThreadPool().execute( new Runnable() {
public void run() { public void run() {
...@@ -169,6 +241,7 @@ public class LocalNotification extends CordovaPlugin { ...@@ -169,6 +241,7 @@ public class LocalNotification extends CordovaPlugin {
persist(options.getId(), options.getJSONObject()); persist(options.getId(), options.getJSONObject());
//Intent is called when the Notification gets fired
Intent intent = new Intent(context, Receiver.class) Intent intent = new Intent(context, Receiver.class)
.setAction("" + options.getId()) .setAction("" + options.getId())
.putExtra(Receiver.OPTIONS, options.getJSONObject().toString()); .putExtra(Receiver.OPTIONS, options.getJSONObject().toString());
...@@ -184,6 +257,91 @@ public class LocalNotification extends CordovaPlugin { ...@@ -184,6 +257,91 @@ public class LocalNotification extends CordovaPlugin {
} }
/** /**
* 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. * Cancel a specific notification that was previously registered.
* *
* @param notificationId * @param notificationId
...@@ -490,14 +648,49 @@ public class LocalNotification extends CordovaPlugin { ...@@ -490,14 +648,49 @@ public class LocalNotification extends CordovaPlugin {
* @param args The given JSONArray * @param args The given JSONArray
* @return A new JSONArray with the parameter "initialDate" set. * @return A new JSONArray with the parameter "initialDate" set.
*/ */
private static JSONArray setInitDate(JSONArray args){ private static JSONObject setInitDate(JSONObject arguments){
long initialDate = args.optJSONObject(0).optLong("date", 0) * 1000; long initialDate = arguments.optLong("date", 0) * 1000;
try { try {
args.optJSONObject(0).put("initialDate", initialDate); arguments.put("initialDate", initialDate);
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
} }
return args; 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;
}
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();
} }
......
...@@ -21,8 +21,11 @@ ...@@ -21,8 +21,11 @@
package de.appplant.cordova.plugin.localnotification; package de.appplant.cordova.plugin.localnotification;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.util.Calendar; import java.util.Calendar;
...@@ -42,12 +45,13 @@ import android.media.RingtoneManager; ...@@ -42,12 +45,13 @@ import android.media.RingtoneManager;
import android.net.Uri; import android.net.Uri;
import android.os.StrictMode; import android.os.StrictMode;
import android.os.StrictMode.ThreadPolicy; import android.os.StrictMode.ThreadPolicy;
import android.util.Log;
/** /**
* Class that helps to store the options that can be specified per alarm. * Class that helps to store the options that can be specified per alarm.
*/ */
public class Options { public class Options {
static protected final String STORAGE_FOLDER = "/localnotification";
private JSONObject options = new JSONObject(); private JSONObject options = new JSONObject();
private String packageName = null; private String packageName = null;
private long interval = 0; private long interval = 0;
...@@ -160,7 +164,7 @@ public class Options { ...@@ -160,7 +164,7 @@ public class Options {
return RingtoneManager.getDefaultUri(soundId); return RingtoneManager.getDefaultUri(soundId);
} catch (Exception e) { } catch (Exception e) {
return Uri.parse(sound); return getURIfromPath(sound);
} }
} }
...@@ -176,7 +180,7 @@ public class Options { ...@@ -176,7 +180,7 @@ public class Options {
if (icon.startsWith("http")) { if (icon.startsWith("http")) {
bmp = getIconFromURL(icon); bmp = getIconFromURL(icon);
} else if (icon.startsWith("file://")) { } else if (icon.startsWith("file://") || (icon.startsWith("res"))) {
bmp = getIconFromURI(icon); bmp = getIconFromURI(icon);
} }
...@@ -352,13 +356,11 @@ public class Options { ...@@ -352,13 +356,11 @@ public class Options {
* The corresponding bitmap * The corresponding bitmap
*/ */
private Bitmap getIconFromURI (String src) { private Bitmap getIconFromURI (String src) {
AssetManager assets = LocalNotification.context.getAssets();
Bitmap bmp = null; Bitmap bmp = null;
Uri uri = getURIfromPath(src);
try { try {
String path = src.replace("file:/", "www"); InputStream input = LocalNotification.activity.getContentResolver().openInputStream(uri);
InputStream input = assets.open(path);
bmp = BitmapFactory.decodeStream(input); bmp = BitmapFactory.decodeStream(input);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
...@@ -366,4 +368,166 @@ public class Options { ...@@ -366,4 +368,166 @@ public class Options {
return bmp; 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);
}
} }
...@@ -79,11 +79,18 @@ public class Receiver extends BroadcastReceiver { ...@@ -79,11 +79,18 @@ public class Receiver extends BroadcastReceiver {
} else { } else {
LocalNotification.add(options.moveDate(), false); LocalNotification.add(options.moveDate(), false);
} }
if (!LocalNotification.isInBackground && options.getForegroundMode()){
if (options.getInterval() == 0) {
LocalNotification.unpersist(options.getId());
}
LocalNotification.showNotification(options.getTitle(), options.getMessage());
fireTriggerEvent();
} else {
Builder notification = buildNotification(); Builder notification = buildNotification();
showNotification(notification); showNotification(notification);
} }
}
/* /*
* If you set a repeating alarm at 11:00 in the morning and it * If you set a repeating alarm at 11:00 in the morning and it
...@@ -117,6 +124,12 @@ public class Receiver extends BroadcastReceiver { ...@@ -117,6 +124,12 @@ public class Receiver extends BroadcastReceiver {
private Builder buildNotification () { private Builder buildNotification () {
Uri sound = options.getSound(); 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) Builder notification = new NotificationCompat.Builder(context)
.setDefaults(0) // Do not inherit any defaults .setDefaults(0) // Do not inherit any defaults
.setContentTitle(options.getTitle()) .setContentTitle(options.getTitle())
...@@ -127,7 +140,8 @@ public class Receiver extends BroadcastReceiver { ...@@ -127,7 +140,8 @@ public class Receiver extends BroadcastReceiver {
.setLargeIcon(options.getIcon()) .setLargeIcon(options.getIcon())
.setAutoCancel(options.getAutoCancel()) .setAutoCancel(options.getAutoCancel())
.setOngoing(options.getOngoing()) .setOngoing(options.getOngoing())
.setLights(options.getColor(), 500, 500); .setLights(options.getColor(), 500, 500)
.setDeleteIntent(dpi);
if (sound != null) { if (sound != null) {
notification.setSound(sound); notification.setSound(sound);
......
...@@ -2,22 +2,4 @@ ...@@ -2,22 +2,4 @@
<Bucket <Bucket
type = "1" type = "1"
version = "2.0"> version = "2.0">
<Breakpoints>
<BreakpointProxy
BreakpointExtensionID = "Xcode.Breakpoint.FileBreakpoint">
<BreakpointContent
shouldBeEnabled = "No"
ignoreCount = "0"
continueAfterRunningActions = "No"
filePath = "NotificationExample/Plugins/de.appplant.cordova.plugin.local-notification/UILocalNotification+APPLocalNotification.m"
timestampString = "441842238.113728"
startingColumnNumber = "9223372036854775807"
endingColumnNumber = "9223372036854775807"
startingLineNumber = "61"
endingLineNumber = "61"
landmarkName = "-__init"
landmarkType = "5">
</BreakpointContent>
</BreakpointProxy>
</Breakpoints>
</Bucket> </Bucket>
...@@ -62,17 +62,15 @@ ...@@ -62,17 +62,15 @@
} }
/** /**
* Schedule a new local notification. * Schedule a set of notifications.
* *
* @param properties * @param properties
* A dict of properties * A dict of properties for each notification
*/ */
- (void) add:(CDVInvokedUrlCommand*)command - (void) add:(CDVInvokedUrlCommand*)command
{ {
[self.commandDelegate runInBackground:^{ [self.commandDelegate runInBackground:^{
NSDictionary* options = [[command arguments] for (NSDictionary* options in command.arguments) {
objectAtIndex:0];
UILocalNotification* notification; UILocalNotification* notification;
notification = [[UILocalNotification alloc] notification = [[UILocalNotification alloc]
...@@ -80,29 +78,34 @@ ...@@ -80,29 +78,34 @@
[self scheduleLocalNotification:notification]; [self scheduleLocalNotification:notification];
[self fireEvent:@"add" localNotification:notification]; [self fireEvent:@"add" localNotification:notification];
}
[self execCallback:command]; [self execCallback:command];
}]; }];
} }
/** /**
* Cancels a given local notification. * Cancel a set of notifications.
* *
* @param id * @param ids
* The ID of the local notification * The IDs of the notifications
*/ */
- (void) cancel:(CDVInvokedUrlCommand*)command - (void) cancel:(CDVInvokedUrlCommand*)command
{ {
[self.commandDelegate runInBackground:^{ [self.commandDelegate runInBackground:^{
NSString* id = [[command arguments] for (NSString* id in command.arguments) {
objectAtIndex:0];
UILocalNotification* notification; UILocalNotification* notification;
notification = [[UIApplication sharedApplication] notification = [[UIApplication sharedApplication]
scheduledLocalNotificationWithId:id]; scheduledLocalNotificationWithId:id];
if (!notification)
continue;
[self cancelLocalNotification:notification]; [self cancelLocalNotification:notification];
[self fireEvent:@"cancel" localNotification:notification]; [self fireEvent:@"cancel" localNotification:notification];
}
[self execCallback:command]; [self execCallback:command];
}]; }];
} }
...@@ -328,13 +331,9 @@ ...@@ -328,13 +331,9 @@
[self cancelLocalNotification:forerunner]; [self cancelLocalNotification:forerunner];
} }
/** /**
* Cancels all local notification with are older then * Cancels all local notification with are older then
* a specific amount of seconds * a specific amount of seconds
*
* @param {float} seconds
* The time interval in seconds
*/ */
- (void) cancelAllNotificationsWhichAreOlderThen:(float)seconds - (void) cancelAllNotificationsWhichAreOlderThen:(float)seconds
{ {
...@@ -419,9 +418,7 @@ ...@@ -419,9 +418,7 @@
#pragma mark Life Cycle #pragma mark Life Cycle
/** /**
* Registers obervers for the following events after plugin was initialized. * Registers obervers after plugin was initialized.
* didReceiveLocalNotification:
* didFinishLaunchingWithOptions:
*/ */
- (void) pluginInitialize - (void) pluginInitialize
{ {
......
...@@ -92,9 +92,11 @@ ...@@ -92,9 +92,11 @@
<a href="#" class="button" onclick="hasPermission()">Has permission?<br/><span class="hint">notification.local.hasPermission()</span></a> <a href="#" class="button" onclick="hasPermission()">Has permission?<br/><span class="hint">notification.local.hasPermission()</span></a>
<a href="#" class="button" onclick="registerPermission()">Register permission<br/><span class="hint">notification.local.registerPermission()</span></a> <a href="#" class="button" onclick="registerPermission()">Register permission<br/><span class="hint">notification.local.registerPermission()</span></a>
<a href="#" class="button" onclick="schedule()">Schedule now<br/><span class="hint">notification.local.add()</span></a> <a href="#" class="button" onclick="schedule()">Schedule now<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="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="scheduleMinutely()">Schedule every min<br/><span class="hint">notification.local.add()</span></a>
<a href="#" class="button" onclick="cancel()">Cancel<br/><span class="hint">notification.local.cancel()</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> <a href="#" class="button" onclick="cancelAll()">Cancel all<br/><span class="hint">notification.local.cancelAll()</span></a>
<a href="#" class="button" onclick="getScheduledIds()">Scheduled IDs<br/><span class="hint">notification.local.getScheduledIds()</span></a> <a href="#" class="button" onclick="getScheduledIds()">Scheduled IDs<br/><span class="hint">notification.local.getScheduledIds()</span></a>
<a href="#" class="button" onclick="isScheduled()">Is scheduled?<br/><span class="hint">notification.local.isScheduled()</span></a> <a href="#" class="button" onclick="isScheduled()">Is scheduled?<br/><span class="hint">notification.local.isScheduled()</span></a>
...@@ -107,7 +109,7 @@ ...@@ -107,7 +109,7 @@
<script type="text/javascript" src="js/index.js"></script> <script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript"> <script type="text/javascript">
var counter = 0, id = 12; var counter = 1, id = 12;
var callback = function () { var callback = function () {
alert('finished or canceled'); alert('finished or canceled');
...@@ -129,10 +131,26 @@ ...@@ -129,10 +131,26 @@
plugin.notification.local.add({ plugin.notification.local.add({
id: id, id: id,
message: 'Test Message ' + (++counter), message: 'Test Message ' + (++counter),
json: { test: 123 } json: { test: id }
}); });
}; };
scheduleMultiple = function () {
plugin.notification.local.add([{
id: id,
message: 'Test Message ' + (++counter),
json: { test: id }
},{
id: id+1,
message: 'Test Message ' + (++counter),
json: { test: id+1 }
},{
id: id+2,
message: 'Test Message ' + (++counter),
json: { test: id+2 }
}]);
};
scheduleDelayed = function () { scheduleDelayed = function () {
var now = new Date().getTime(), var now = new Date().getTime(),
_5_sec_from_now = new Date(now + 5*1000); _5_sec_from_now = new Date(now + 5*1000);
...@@ -160,6 +178,11 @@ ...@@ -160,6 +178,11 @@
plugin.notification.local.cancel(id,callback); plugin.notification.local.cancel(id,callback);
}; };
cancelMultiple = function () {
counter = 0;
plugin.notification.local.cancel([id, id+1],callback);
};
cancelAll = function () { cancelAll = function () {
counter = 0; counter = 0;
plugin.notification.local.cancelAll(callback); plugin.notification.local.cancelAll(callback);
...@@ -198,7 +221,7 @@ ...@@ -198,7 +221,7 @@
<!-- callbacks --> <!-- callbacks -->
<script type="text/javascript"> <script type="text/javascript">
document.addEventListener('deviceready', function () { document.addEventListener('sdeviceready', function () {
plugin.notification.local.onadd = function (id, state, json) { plugin.notification.local.onadd = function (id, state, json) {
alert('on add\n' + Array.apply(null, arguments).join("\n")); alert('on add\n' + Array.apply(null, arguments).join("\n"));
}; };
......
...@@ -39,11 +39,15 @@ ...@@ -39,11 +39,15 @@
"count": 1 "count": 1
}, },
{ {
"xml": "<receiver android:name=\"de.appplant.cordova.plugin.localnotification.DeleteIntentReceiver\" />",
"count": 1
},
{
"xml": "<receiver android:name=\"de.appplant.cordova.plugin.localnotification.Restore\"><intent-filter><action android:name=\"android.intent.action.BOOT_COMPLETED\" /></intent-filter></receiver>", "xml": "<receiver android:name=\"de.appplant.cordova.plugin.localnotification.Restore\"><intent-filter><action android:name=\"android.intent.action.BOOT_COMPLETED\" /></intent-filter></receiver>",
"count": 1 "count": 1
}, },
{ {
"xml": "<activity android:launchMode=\"singleInstance\" android:name=\"de.appplant.cordova.plugin.localnotification.ReceiverActivity\" />", "xml": "<activity android:launchMode=\"singleInstance\" android:name=\"de.appplant.cordova.plugin.localnotification.ReceiverActivity\" android:theme=\"@android:style/Theme.NoDisplay\" />",
"count": 1 "count": 1
} }
], ],
......
...@@ -9,6 +9,14 @@ ...@@ -9,6 +9,14 @@
- [enhancement:] Scope parameter for `isScheduled` and `getScheduledIds` - [enhancement:] Scope parameter for `isScheduled` and `getScheduledIds`
- [enhancement:] Callbacks for `add`, `cancel` & `cancelAll` - [enhancement:] Callbacks for `add`, `cancel` & `cancelAll`
- [enhancement:] `image:` accepts remote URLs and local URIs (Android) - [enhancement:] `image:` accepts remote URLs and local URIs (Android)
- [enhancement:] Schedule multiple notifications at once
- [enhancement:] Cancel multiple notifications at once
- [enhancement:] Clear multiple notifications at once (Android)
- [enhancement:] `clear` & `clearAll` methods (Android)
- [enhancement:] `onclear` event (Android)
- [enhancement:] Modal dialogs when in foreground (Android)
- [enhancement:] Ability to change repeating notifications (Android)
- [enhancement:] `sound:` accepts local URIs for absolute (file:///), relative (file://) and resource path (res:). (Android)
#### Version 0.7.4 (22.03.2014) #### Version 0.7.4 (22.03.2014)
- [bugfix:] Platform specific properties were ignored. - [bugfix:] Platform specific properties were ignored.
......
...@@ -67,6 +67,12 @@ ...@@ -67,6 +67,12 @@
<receiver android:name="de.appplant.cordova.plugin.localnotification.Receiver" /> <receiver android:name="de.appplant.cordova.plugin.localnotification.Receiver" />
<!-- <!--
* The delete intent receiver is triggered when the user clears a notification
* manually. It unpersists the cleared notification from the shared preferences.
-->
<receiver android:name="de.appplant.cordova.plugin.localnotification.DeleteIntentReceiver" />
<!--
* This class is triggered upon reboot of the device. It needs to re-register * 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 * the alarms with the AlarmManager since these alarms are lost in case of
* reboot. * reboot.
...@@ -77,12 +83,13 @@ ...@@ -77,12 +83,13 @@
</intent-filter> </intent-filter>
</receiver> </receiver>
<!-- <!--
* The receiver activity is triggered when a notification is clicked by a user. * The receiver activity is triggered when a notification is clicked by a user.
* The activity calls the background callback and brings the launch inten * The activity calls the background callback and brings the launch inten
* up to foreground. * up to foreground.
--> -->
<activity android:name="de.appplant.cordova.plugin.localnotification.ReceiverActivity" android:launchMode="singleInstance" /> <activity android:name="de.appplant.cordova.plugin.localnotification.ReceiverActivity" android:launchMode="singleInstance" android:theme="@android:style/Theme.NoDisplay" />
</config-file> </config-file>
<config-file target="AndroidManifest.xml" parent="/manifest"> <config-file target="AndroidManifest.xml" parent="/manifest">
...@@ -96,6 +103,7 @@ ...@@ -96,6 +103,7 @@
<source-file src="src/android/Options.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/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/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" />
</platform> </platform>
<!-- wp8 --> <!-- wp8 -->
......
/*
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.util.Date;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
public class DeleteIntentReceiver extends BroadcastReceiver {
public static final String OPTIONS = "LOCAL_NOTIFICATION_OPTIONS";
@Override
public void onReceive(Context context, Intent intent) {
Options options = null;
Bundle bundle = intent.getExtras();
JSONObject args;
try {
args = new JSONObject(bundle.getString(OPTIONS));
options = new Options(context).parse(args);
} catch (JSONException e) {
return;
}
// The context may got lost if the app was not running before
LocalNotification.setContext(context);
Date now = new Date();
if ((options.getInterval()!=0)){
LocalNotification.persist(options.getId(), setInitDate(args));
}
else if((new Date(options.getDate()).before(now))){
LocalNotification.unpersist(options.getId());
}
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());
}
}
...@@ -35,6 +35,7 @@ import org.json.JSONArray; ...@@ -35,6 +35,7 @@ import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import android.app.Activity;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.app.NotificationManager; import android.app.NotificationManager;
import android.app.PendingIntent; import android.app.PendingIntent;
...@@ -43,6 +44,7 @@ import android.content.Intent; ...@@ -43,6 +44,7 @@ import android.content.Intent;
import android.content.SharedPreferences; import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor; import android.content.SharedPreferences.Editor;
import android.os.Build; import android.os.Build;
import android.widget.Toast;
/** /**
* This plugin utilizes the Android AlarmManager in combination with StatusBar * This plugin utilizes the Android AlarmManager in combination with StatusBar
...@@ -59,6 +61,7 @@ public class LocalNotification extends CordovaPlugin { ...@@ -59,6 +61,7 @@ public class LocalNotification extends CordovaPlugin {
protected static Context context = null; protected static Context context = null;
protected static Boolean isInBackground = true; protected static Boolean isInBackground = true;
private static ArrayList<String> eventQueue = new ArrayList<String>(); private static ArrayList<String> eventQueue = new ArrayList<String>();
static Activity activity;
@Override @Override
public void initialize (CordovaInterface cordova, CordovaWebView webView) { public void initialize (CordovaInterface cordova, CordovaWebView webView) {
...@@ -66,6 +69,7 @@ public class LocalNotification extends CordovaPlugin { ...@@ -66,6 +69,7 @@ public class LocalNotification extends CordovaPlugin {
LocalNotification.webView = super.webView; LocalNotification.webView = super.webView;
LocalNotification.context = super.cordova.getActivity().getApplicationContext(); LocalNotification.context = super.cordova.getActivity().getApplicationContext();
LocalNotification.activity = super.cordova.getActivity();
} }
@Override @Override
...@@ -73,10 +77,66 @@ public class LocalNotification extends CordovaPlugin { ...@@ -73,10 +77,66 @@ public class LocalNotification extends CordovaPlugin {
if (action.equalsIgnoreCase("add")) { if (action.equalsIgnoreCase("add")) {
cordova.getThreadPool().execute( new Runnable() { cordova.getThreadPool().execute( new Runnable() {
public void run() { public void run() {
JSONObject arguments = setInitDate(args).optJSONObject(0); JSONObject arguments = setInitDate(args.optJSONObject(0));
Options options = new Options(context).parse(arguments); Options options = new Options(context).parse(arguments);
add(options, true);
command.success();
}
});
}
if (action.equalsIgnoreCase("addMultiple")) {
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));
Options options = new Options(context).parse(arguments);
add(options, true); add(options, true);
}
command.success();
}
});
}
if (action.equalsIgnoreCase("update")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
JSONObject updates = args.optJSONObject(0);
update(updates);
command.success();
}
});
}
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")) {
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));
}
command.success();
}
});
}
if (action.equalsIgnoreCase("clearAll")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
clearAll();
command.success(); command.success();
} }
}); });
...@@ -94,6 +154,18 @@ public class LocalNotification extends CordovaPlugin { ...@@ -94,6 +154,18 @@ public class LocalNotification extends CordovaPlugin {
}); });
} }
if (action.equalsIgnoreCase("cancelMultiple")) {
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));
}
command.success();
}
});
}
if (action.equalsIgnoreCase("cancelAll")) { if (action.equalsIgnoreCase("cancelAll")) {
cordova.getThreadPool().execute( new Runnable() { cordova.getThreadPool().execute( new Runnable() {
public void run() { public void run() {
...@@ -169,6 +241,7 @@ public class LocalNotification extends CordovaPlugin { ...@@ -169,6 +241,7 @@ public class LocalNotification extends CordovaPlugin {
persist(options.getId(), options.getJSONObject()); persist(options.getId(), options.getJSONObject());
//Intent is called when the Notification gets fired
Intent intent = new Intent(context, Receiver.class) Intent intent = new Intent(context, Receiver.class)
.setAction("" + options.getId()) .setAction("" + options.getId())
.putExtra(Receiver.OPTIONS, options.getJSONObject().toString()); .putExtra(Receiver.OPTIONS, options.getJSONObject().toString());
...@@ -184,6 +257,91 @@ public class LocalNotification extends CordovaPlugin { ...@@ -184,6 +257,91 @@ public class LocalNotification extends CordovaPlugin {
} }
/** /**
* 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. * Cancel a specific notification that was previously registered.
* *
* @param notificationId * @param notificationId
...@@ -490,14 +648,49 @@ public class LocalNotification extends CordovaPlugin { ...@@ -490,14 +648,49 @@ public class LocalNotification extends CordovaPlugin {
* @param args The given JSONArray * @param args The given JSONArray
* @return A new JSONArray with the parameter "initialDate" set. * @return A new JSONArray with the parameter "initialDate" set.
*/ */
private static JSONArray setInitDate(JSONArray args){ private static JSONObject setInitDate(JSONObject arguments){
long initialDate = args.optJSONObject(0).optLong("date", 0) * 1000; long initialDate = arguments.optLong("date", 0) * 1000;
try { try {
args.optJSONObject(0).put("initialDate", initialDate); arguments.put("initialDate", initialDate);
} catch (JSONException e) { } catch (JSONException e) {
e.printStackTrace(); e.printStackTrace();
} }
return args; 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;
}
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();
} }
......
...@@ -21,8 +21,11 @@ ...@@ -21,8 +21,11 @@
package de.appplant.cordova.plugin.localnotification; package de.appplant.cordova.plugin.localnotification;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URL; import java.net.URL;
import java.util.Calendar; import java.util.Calendar;
...@@ -42,12 +45,13 @@ import android.media.RingtoneManager; ...@@ -42,12 +45,13 @@ import android.media.RingtoneManager;
import android.net.Uri; import android.net.Uri;
import android.os.StrictMode; import android.os.StrictMode;
import android.os.StrictMode.ThreadPolicy; import android.os.StrictMode.ThreadPolicy;
import android.util.Log;
/** /**
* Class that helps to store the options that can be specified per alarm. * Class that helps to store the options that can be specified per alarm.
*/ */
public class Options { public class Options {
static protected final String STORAGE_FOLDER = "/localnotification";
private JSONObject options = new JSONObject(); private JSONObject options = new JSONObject();
private String packageName = null; private String packageName = null;
private long interval = 0; private long interval = 0;
...@@ -160,7 +164,7 @@ public class Options { ...@@ -160,7 +164,7 @@ public class Options {
return RingtoneManager.getDefaultUri(soundId); return RingtoneManager.getDefaultUri(soundId);
} catch (Exception e) { } catch (Exception e) {
return Uri.parse(sound); return getURIfromPath(sound);
} }
} }
...@@ -176,7 +180,7 @@ public class Options { ...@@ -176,7 +180,7 @@ public class Options {
if (icon.startsWith("http")) { if (icon.startsWith("http")) {
bmp = getIconFromURL(icon); bmp = getIconFromURL(icon);
} else if (icon.startsWith("file://")) { } else if (icon.startsWith("file://") || (icon.startsWith("res"))) {
bmp = getIconFromURI(icon); bmp = getIconFromURI(icon);
} }
...@@ -352,13 +356,11 @@ public class Options { ...@@ -352,13 +356,11 @@ public class Options {
* The corresponding bitmap * The corresponding bitmap
*/ */
private Bitmap getIconFromURI (String src) { private Bitmap getIconFromURI (String src) {
AssetManager assets = LocalNotification.context.getAssets();
Bitmap bmp = null; Bitmap bmp = null;
Uri uri = getURIfromPath(src);
try { try {
String path = src.replace("file:/", "www"); InputStream input = LocalNotification.activity.getContentResolver().openInputStream(uri);
InputStream input = assets.open(path);
bmp = BitmapFactory.decodeStream(input); bmp = BitmapFactory.decodeStream(input);
} catch (IOException e) { } catch (IOException e) {
e.printStackTrace(); e.printStackTrace();
...@@ -366,4 +368,166 @@ public class Options { ...@@ -366,4 +368,166 @@ public class Options {
return bmp; 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);
}
} }
...@@ -79,11 +79,18 @@ public class Receiver extends BroadcastReceiver { ...@@ -79,11 +79,18 @@ public class Receiver extends BroadcastReceiver {
} else { } else {
LocalNotification.add(options.moveDate(), false); LocalNotification.add(options.moveDate(), false);
} }
if (!LocalNotification.isInBackground && options.getForegroundMode()){
if (options.getInterval() == 0) {
LocalNotification.unpersist(options.getId());
}
LocalNotification.showNotification(options.getTitle(), options.getMessage());
fireTriggerEvent();
} else {
Builder notification = buildNotification(); Builder notification = buildNotification();
showNotification(notification); showNotification(notification);
} }
}
/* /*
* If you set a repeating alarm at 11:00 in the morning and it * If you set a repeating alarm at 11:00 in the morning and it
...@@ -117,6 +124,12 @@ public class Receiver extends BroadcastReceiver { ...@@ -117,6 +124,12 @@ public class Receiver extends BroadcastReceiver {
private Builder buildNotification () { private Builder buildNotification () {
Uri sound = options.getSound(); 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) Builder notification = new NotificationCompat.Builder(context)
.setDefaults(0) // Do not inherit any defaults .setDefaults(0) // Do not inherit any defaults
.setContentTitle(options.getTitle()) .setContentTitle(options.getTitle())
...@@ -127,7 +140,8 @@ public class Receiver extends BroadcastReceiver { ...@@ -127,7 +140,8 @@ public class Receiver extends BroadcastReceiver {
.setLargeIcon(options.getIcon()) .setLargeIcon(options.getIcon())
.setAutoCancel(options.getAutoCancel()) .setAutoCancel(options.getAutoCancel())
.setOngoing(options.getOngoing()) .setOngoing(options.getOngoing())
.setLights(options.getColor(), 500, 500); .setLights(options.getColor(), 500, 500)
.setDeleteIntent(dpi);
if (sound != null) { if (sound != null) {
notification.setSound(sound); notification.setSound(sound);
......
...@@ -35,6 +35,8 @@ ...@@ -35,6 +35,8 @@
@property (readwrite, assign) BOOL deviceready; @property (readwrite, assign) BOOL deviceready;
// Event queue // Event queue
@property (readonly, nonatomic, retain) NSMutableArray* eventQueue; @property (readonly, nonatomic, retain) NSMutableArray* eventQueue;
// Needed when calling `registerPermission`
@property (nonatomic, retain) CDVInvokedUrlCommand* command;
@end @end
...@@ -60,17 +62,15 @@ ...@@ -60,17 +62,15 @@
} }
/** /**
* Schedule a new local notification. * Schedule a set of notifications.
* *
* @param properties * @param properties
* A dict of properties * A dict of properties for each notification
*/ */
- (void) add:(CDVInvokedUrlCommand*)command - (void) add:(CDVInvokedUrlCommand*)command
{ {
[self.commandDelegate runInBackground:^{ [self.commandDelegate runInBackground:^{
NSDictionary* options = [[command arguments] for (NSDictionary* options in command.arguments) {
objectAtIndex:0];
UILocalNotification* notification; UILocalNotification* notification;
notification = [[UILocalNotification alloc] notification = [[UILocalNotification alloc]
...@@ -78,29 +78,34 @@ ...@@ -78,29 +78,34 @@
[self scheduleLocalNotification:notification]; [self scheduleLocalNotification:notification];
[self fireEvent:@"add" localNotification:notification]; [self fireEvent:@"add" localNotification:notification];
}
[self execCallback:command]; [self execCallback:command];
}]; }];
} }
/** /**
* Cancels a given local notification. * Cancel a set of notifications.
* *
* @param id * @param ids
* The ID of the local notification * The IDs of the notifications
*/ */
- (void) cancel:(CDVInvokedUrlCommand*)command - (void) cancel:(CDVInvokedUrlCommand*)command
{ {
[self.commandDelegate runInBackground:^{ [self.commandDelegate runInBackground:^{
NSString* id = [[command arguments] for (NSString* id in command.arguments) {
objectAtIndex:0];
UILocalNotification* notification; UILocalNotification* notification;
notification = [[UIApplication sharedApplication] notification = [[UIApplication sharedApplication]
scheduledLocalNotificationWithId:id]; scheduledLocalNotificationWithId:id];
if (!notification)
continue;
[self cancelLocalNotification:notification]; [self cancelLocalNotification:notification];
[self fireEvent:@"cancel" localNotification:notification]; [self fireEvent:@"cancel" localNotification:notification];
}
[self execCallback:command]; [self execCallback:command];
}]; }];
} }
...@@ -217,7 +222,7 @@ ...@@ -217,7 +222,7 @@
* Inform if the app has the permission to show * Inform if the app has the permission to show
* badges and local notifications. * badges and local notifications.
*/ */
- (void) hasPermission:(CDVInvokedUrlCommand *)command - (void) hasPermission:(CDVInvokedUrlCommand*)command
{ {
[self.commandDelegate runInBackground:^{ [self.commandDelegate runInBackground:^{
CDVPluginResult* result; CDVPluginResult* result;
...@@ -237,12 +242,19 @@ ...@@ -237,12 +242,19 @@
/** /**
* Ask for permission to show badges. * Ask for permission to show badges.
*/ */
- (void) registerPermission:(CDVInvokedUrlCommand *)command - (void) registerPermission:(CDVInvokedUrlCommand*)command
{ {
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
_command = command;
[self.commandDelegate runInBackground:^{ [self.commandDelegate runInBackground:^{
[[UIApplication sharedApplication] [[UIApplication sharedApplication]
registerPermissionToScheduleLocalNotifications]; registerPermissionToScheduleLocalNotifications];
}]; }];
#else
[self hasPermission:command];
#endif
} }
#pragma mark - #pragma mark -
...@@ -276,6 +288,9 @@ ...@@ -276,6 +288,9 @@
[[UIApplication sharedApplication] [[UIApplication sharedApplication]
cancelLocalNotification:notification]; cancelLocalNotification:notification];
[UIApplication sharedApplication]
.applicationIconBadgeNumber -= 1;
} }
/** /**
...@@ -316,13 +331,9 @@ ...@@ -316,13 +331,9 @@
[self cancelLocalNotification:forerunner]; [self cancelLocalNotification:forerunner];
} }
/** /**
* Cancels all local notification with are older then * Cancels all local notification with are older then
* a specific amount of seconds * a specific amount of seconds
*
* @param {float} seconds
* The time interval in seconds
*/ */
- (void) cancelAllNotificationsWhichAreOlderThen:(float)seconds - (void) cancelAllNotificationsWhichAreOlderThen:(float)seconds
{ {
...@@ -351,7 +362,6 @@ ...@@ -351,7 +362,6 @@
*/ */
- (void) didReceiveLocalNotification:(NSNotification*)localNotification - (void) didReceiveLocalNotification:(NSNotification*)localNotification
{ {
UIApplication* app = [UIApplication sharedApplication];
UILocalNotification* notification = [localNotification object]; UILocalNotification* notification = [localNotification object];
BOOL autoCancel = notification.options.autoCancel; BOOL autoCancel = notification.options.autoCancel;
...@@ -359,7 +369,10 @@ ...@@ -359,7 +369,10 @@
NSString* event = (timeInterval <= 1 && deviceready) ? @"trigger" : @"click"; NSString* event = (timeInterval <= 1 && deviceready) ? @"trigger" : @"click";
app.applicationIconBadgeNumber -= 1; if ([event isEqualToString:@"click"]) {
[UIApplication sharedApplication]
.applicationIconBadgeNumber -= 1;
}
[self fireEvent:event localNotification:notification]; [self fireEvent:event localNotification:notification];
...@@ -389,32 +402,45 @@ ...@@ -389,32 +402,45 @@
} }
} }
/**
* Called on otification settings registration is completed.
*/
- (void) didRegisterUserNotificationSettings:(UIUserNotificationSettings*)settings
{
if (_command)
{
[self hasPermission:_command];
_command = NULL;
}
}
#pragma mark - #pragma mark -
#pragma mark Life Cycle #pragma mark Life Cycle
/** /**
* Registers obervers for the following events after plugin was initialized. * Registers obervers after plugin was initialized.
* didReceiveLocalNotification:
* didFinishLaunchingWithOptions:
*/ */
- (void) pluginInitialize - (void) pluginInitialize
{ {
NSNotificationCenter* notificationCenter; NSNotificationCenter* center = [NSNotificationCenter
notificationCenter = [NSNotificationCenter
defaultCenter]; defaultCenter];
eventQueue = [[NSMutableArray alloc] init]; eventQueue = [[NSMutableArray alloc] init];
[notificationCenter addObserver:self [center addObserver:self
selector:@selector(didReceiveLocalNotification:) selector:@selector(didReceiveLocalNotification:)
name:CDVLocalNotification name:CDVLocalNotification
object:nil]; object:nil];
[notificationCenter addObserver:self [center addObserver:self
selector:@selector(didFinishLaunchingWithOptions:) selector:@selector(didFinishLaunchingWithOptions:)
name:UIApplicationDidFinishLaunchingNotification name:UIApplicationDidFinishLaunchingNotification
object:nil]; object:nil];
[center addObserver:self
selector:@selector(didRegisterUserNotificationSettings:)
name:UIApplicationRegisterUserNotificationSettings
object:nil];
} }
/** /**
......
...@@ -82,7 +82,7 @@ ...@@ -82,7 +82,7 @@
- (BOOL) autoCancel - (BOOL) autoCancel
{ {
if (IsAtLeastiOSVersion(@"8.0")){ if (IsAtLeastiOSVersion(@"8.0")){
return YES; return self.repeatInterval == NSCalendarUnitEra;
} else { } else {
return [[dict objectForKey:@"autoCancel"] boolValue]; return [[dict objectForKey:@"autoCancel"] boolValue];
} }
...@@ -101,7 +101,13 @@ ...@@ -101,7 +101,13 @@
*/ */
- (NSInteger) badgeNumber - (NSInteger) badgeNumber
{ {
return [[dict objectForKey:@"badge"] intValue]; NSInteger number = [[dict objectForKey:@"badge"] intValue];
if (number == -1) {
number = 1 + [UIApplication sharedApplication].applicationIconBadgeNumber;
}
return number;
} }
#pragma mark - #pragma mark -
......
...@@ -23,6 +23,8 @@ ...@@ -23,6 +23,8 @@
#import <Availability.h> #import <Availability.h>
extern NSString* const UIApplicationRegisterUserNotificationSettings;
@interface AppDelegate (APPLocalNotification) @interface AppDelegate (APPLocalNotification)
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
......
...@@ -23,13 +23,9 @@ ...@@ -23,13 +23,9 @@
#import <Availability.h> #import <Availability.h>
@implementation AppDelegate (APPLocalNotification) NSString* const UIApplicationRegisterUserNotificationSettings = @"UIApplicationRegisterUserNotificationSettings";
+ (void)load { @implementation AppDelegate (APPLocalNotification)
Methods original = class_getInstanceMethod(self, @selector(applicationDidFinishLaunching:));
Method custom = class_getInstanceMethod(self, @selector(customApplicationDidFinishLaunching:));
method_exchangeImplementations(original, custom);
}
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000 #if __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000
/** /**
...@@ -39,7 +35,12 @@ ...@@ -39,7 +35,12 @@
- (void) application:(UIApplication*)application - (void) application:(UIApplication*)application
didRegisterUserNotificationSettings:(UIUserNotificationSettings*)settings didRegisterUserNotificationSettings:(UIUserNotificationSettings*)settings
{ {
[[NSURLCache sharedURLCache] removeAllCachedResponses]; NSNotificationCenter* center = [NSNotificationCenter
defaultCenter];
// re-post (broadcast)
[center postNotificationName:UIApplicationRegisterUserNotificationSettings
object:settings];
} }
#endif #endif
......
...@@ -28,7 +28,7 @@ ...@@ -28,7 +28,7 @@
// The options provided by the plug-in // The options provided by the plug-in
- (APPLocalNotificationOptions*) options; - (APPLocalNotificationOptions*) options;
// Timeinterval since fire date // Timeinterval since fire date
- (NSTimeInterval) timeIntervalSinceFireDate; - (double) timeIntervalSinceFireDate;
// If the fire date was in the past // If the fire date was in the past
- (BOOL) wasInThePast; - (BOOL) wasInThePast;
// If the notification was already triggered // If the notification was already triggered
......
...@@ -96,14 +96,43 @@ static char optionsKey; ...@@ -96,14 +96,43 @@ static char optionsKey;
} }
/** /**
* The repeating interval in seconds.
*/
- (int) repeatIntervalInSeconds
{
switch (self.repeatInterval) {
case NSCalendarUnitMinute:
return 60;
case NSCalendarUnitHour:
return 60000;
case NSCalendarUnitDay:
case NSCalendarUnitWeekOfYear:
case NSCalendarUnitMonth:
case NSCalendarUnitYear:
return 86400;
default:
return 1;
}
}
/**
* Timeinterval since fire date. * Timeinterval since fire date.
*/ */
- (NSTimeInterval) timeIntervalSinceFireDate - (double) timeIntervalSinceFireDate
{ {
NSDate* now = [NSDate date]; NSDate* now = [NSDate date];
NSDate* fireDate = self.options.fireDate; NSDate* fireDate = self.options.fireDate;
return [now timeIntervalSinceDate:fireDate]; int timespan = [now timeIntervalSinceDate:fireDate];
if (self.repeatInterval != NSCalendarUnitEra) {
timespan = timespan % [self repeatIntervalInSeconds];
}
return timespan;
} }
/** /**
......
...@@ -92,9 +92,11 @@ ...@@ -92,9 +92,11 @@
<a href="#" class="button" onclick="hasPermission()">Has permission?<br/><span class="hint">notification.local.hasPermission()</span></a> <a href="#" class="button" onclick="hasPermission()">Has permission?<br/><span class="hint">notification.local.hasPermission()</span></a>
<a href="#" class="button" onclick="registerPermission()">Register permission<br/><span class="hint">notification.local.registerPermission()</span></a> <a href="#" class="button" onclick="registerPermission()">Register permission<br/><span class="hint">notification.local.registerPermission()</span></a>
<a href="#" class="button" onclick="schedule()">Schedule now<br/><span class="hint">notification.local.add()</span></a> <a href="#" class="button" onclick="schedule()">Schedule now<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="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="scheduleMinutely()">Schedule every min<br/><span class="hint">notification.local.add()</span></a>
<a href="#" class="button" onclick="cancel()">Cancel<br/><span class="hint">notification.local.cancel()</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> <a href="#" class="button" onclick="cancelAll()">Cancel all<br/><span class="hint">notification.local.cancelAll()</span></a>
<a href="#" class="button" onclick="getScheduledIds()">Scheduled IDs<br/><span class="hint">notification.local.getScheduledIds()</span></a> <a href="#" class="button" onclick="getScheduledIds()">Scheduled IDs<br/><span class="hint">notification.local.getScheduledIds()</span></a>
<a href="#" class="button" onclick="isScheduled()">Is scheduled?<br/><span class="hint">notification.local.isScheduled()</span></a> <a href="#" class="button" onclick="isScheduled()">Is scheduled?<br/><span class="hint">notification.local.isScheduled()</span></a>
...@@ -107,7 +109,7 @@ ...@@ -107,7 +109,7 @@
<script type="text/javascript" src="js/index.js"></script> <script type="text/javascript" src="js/index.js"></script>
<script type="text/javascript"> <script type="text/javascript">
var counter = 0, id = 12; var counter = 1, id = 12;
var callback = function () { var callback = function () {
alert('finished or canceled'); alert('finished or canceled');
...@@ -129,10 +131,26 @@ ...@@ -129,10 +131,26 @@
plugin.notification.local.add({ plugin.notification.local.add({
id: id, id: id,
message: 'Test Message ' + (++counter), message: 'Test Message ' + (++counter),
json: { test: 123 } json: { test: id }
}); });
}; };
scheduleMultiple = function () {
plugin.notification.local.add([{
id: id,
message: 'Test Message ' + (++counter),
json: { test: id }
},{
id: id+1,
message: 'Test Message ' + (++counter),
json: { test: id+1 }
},{
id: id+2,
message: 'Test Message ' + (++counter),
json: { test: id+2 }
}]);
};
scheduleDelayed = function () { scheduleDelayed = function () {
var now = new Date().getTime(), var now = new Date().getTime(),
_5_sec_from_now = new Date(now + 5*1000); _5_sec_from_now = new Date(now + 5*1000);
...@@ -160,6 +178,11 @@ ...@@ -160,6 +178,11 @@
plugin.notification.local.cancel(id,callback); plugin.notification.local.cancel(id,callback);
}; };
cancelMultiple = function () {
counter = 0;
plugin.notification.local.cancel([id, id+1],callback);
};
cancelAll = function () { cancelAll = function () {
counter = 0; counter = 0;
plugin.notification.local.cancelAll(callback); plugin.notification.local.cancelAll(callback);
...@@ -198,7 +221,7 @@ ...@@ -198,7 +221,7 @@
<!-- callbacks --> <!-- callbacks -->
<script type="text/javascript"> <script type="text/javascript">
document.addEventListener('deviceready', function () { document.addEventListener('sdeviceready', function () {
plugin.notification.local.onadd = function (id, state, json) { plugin.notification.local.onadd = function (id, state, json) {
alert('on add\n' + Array.apply(null, arguments).join("\n")); alert('on add\n' + Array.apply(null, arguments).join("\n"));
}; };
......
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