Commit e364b93b by PKnittel

Added getFunctions to request notifications arguments

Changed add-,cancel-, and clear function
Revised class-structure
parent e60af757
......@@ -100,10 +100,15 @@
<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 -->
......
......@@ -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();
});
}
......
......@@ -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) {}
}
......
/*
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.notification;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.StrictMode;
import android.util.Log;
public class Asset {
private Activity activity;
protected final String STORAGE_FOLDER;
/**
* Constructor of Asset Class. Takes Applications Activity and a foldername for temporary saving.
*
*@param activity Applications Activity
*@param storageFolder foldername for temporary saving.
*/
public Asset(Activity activity,String storageFolder){
this.activity = activity;
this.STORAGE_FOLDER = storageFolder;
}
/**
* Parse given PathStrings to Uris
* @param notification Notifications JSONObject
* @return new Notification JSONObject with additional iconUri and soundUri
*/
public JSONObject parseURIs(JSONObject notification){
//sound
String sound = notification.optString("sound", null);
Uri soundUri = null;
if (sound != null) {
try {
int soundId = (Integer) RingtoneManager.class.getDeclaredField(sound).get(Integer.class);
soundUri = RingtoneManager.getDefaultUri(soundId);
} catch (Exception e) {
soundUri = getURIfromPath(sound);
}
}
if (soundUri!= null&&soundUri!=Uri.EMPTY){
try{
notification.put("soundUri", soundUri.toString());
} catch (JSONException jse){
jse.printStackTrace();
}
}
//image
String icon = notification.optString("icon", "icon");
Uri iconUri = null;
iconUri = getURIfromPath(icon);
if (iconUri != Uri.EMPTY&&iconUri != null){
try{
notification.put("iconUri", iconUri.toString());
} catch (JSONException jse){
jse.printStackTrace();
}
}
return notification;
}
/**
* The URI for a path.
*
* @param path The given path
*
* @return The URI pointing to the given path
*/
public 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);
} else if (path.startsWith("http")){
return getUriForHTTP(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("Asset", "File not found: " + file.getAbsolutePath());
return Uri.EMPTY;
}
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 = activity.getExternalCacheDir();
if (dir == null) {
Log.e("Asset", "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 = activity.getAssets();
FileOutputStream outStream = new FileOutputStream(file);
InputStream inputStream = assets.open(resPath);
copyFile(inputStream, outStream);
outStream.flush();
outStream.close();
return Uri.fromFile(file);
} catch (Exception e) {
Log.e("Asset", "File not found: assets/" + resPath);
e.printStackTrace();
}
return Uri.EMPTY;
}
/**
* The URI for a resource.
*
* @param path
* The given relative path
*
* @return 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 = activity.getExternalCacheDir();
if (dir == null) {
Log.e("Asset", "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("Asset", "File not found: " + resPath);
return Uri.EMPTY;
}
new File(storage).mkdir();
try {
Resources res = activity.getResources();
FileOutputStream outStream = new FileOutputStream(file);
InputStream inputStream = res.openRawResource(resId);
copyFile(inputStream, outStream);
outStream.flush();
outStream.close();
return Uri.fromFile(file);
} catch (Exception e) {
e.printStackTrace();
}
return Uri.EMPTY;
}
/**
*Get Uri for HTTP Content
* @param path HTTP adress
* @return Uri of the downloaded file
*/
private Uri getUriForHTTP(String path) {
try {
URL url = new URL(path);
String fileName = path.substring(path.lastIndexOf('/') + 1);
String resName = fileName.substring(0, fileName.lastIndexOf('.'));
String extension = path.substring(path.lastIndexOf('.'));
File dir = activity.getExternalCacheDir();
if (dir == null) {
Log.e("Asset", "Missing external cache dir");
return Uri.EMPTY;
}
String storage = dir.toString() + STORAGE_FOLDER;
File file = new File(storage, resName + extension);
new File(storage).mkdir();
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();
FileOutputStream outStream = new FileOutputStream(file);
copyFile(input, outStream);
outStream.flush();
outStream.close();
return Uri.fromFile(file);
} catch (MalformedURLException e) {
Log.e("Asset", "Incorrect URL");
e.printStackTrace();
} catch (FileNotFoundException e) {
Log.e("Asset", "Failed to create new File from HTTP Content");
e.printStackTrace();
} catch (IOException e) {
Log.e("Asset", "No Input can be created from http Stream");
e.printStackTrace();
}
return Uri.EMPTY;
}
/**
* 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 = 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 activity.getPackageName();
}
}
package de.appplant.cordova.plugin.notification;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Build;
public class Manager {
//---------------Global Parameter------------------------------------------------------------
private Context context;
private final String PLUGIN_NAME;
//---------------Constructor-----------------------------------------------------------------
/**
* Constructor of NotificationWrapper-Class
*/
public Manager(Context context,String PluginName){
this.context = context;
this.PLUGIN_NAME = PluginName;
}
//---------------Public Functions------------------------------------------------------------
/**
* Checks if a notification with an ID is scheduled.
*
* @param id
* The notification ID to be check.
* @return true if the notification is scheduled
*/
public boolean isScheduled (String id) {
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();
}
}
return (isScheduled && isNotTriggered);
}
/**
* Checks if a notification with an ID was triggered.
*
* @param id
* The notification ID to be check.
* @return true if the notification is triggered
*/
public boolean isTriggered (String id) {
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();
}
}
return isTriggered;
}
/**
* Checks whether a notification with an ID exist.
*
* @param id
* The notification ID to check.
* @return true if the notification exist
*/
public boolean exist(String id){
boolean exist;
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
exist = alarms.containsKey(id);
return exist;
}
/**
* Retrieves a list with all currently pending notification Ids.
*
* @return JSONArray with all Id-Strings
*/
public JSONArray getScheduledIds () {
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);
}
}
return scheduledIds;
}
/**
* Retrieves a list with all currently triggered notification Ids.
*
* @return JSONArray with all Id-Strings
*/
public JSONArray getTriggeredIds () {
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);
}
}
return triggeredIds;
}
/**
* Retrieves a list with all currently triggered or scheduled notification-Ids.
* @return JSONArray with all Id-Strings
*/
public JSONArray getAllIds (){
JSONArray allIds = new JSONArray();
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
for (String id : alarmIds) {
allIds.put(id);
}
return allIds;
}
/**
* Retrieves a list with all currently pending notification JSONObject.
*
* @return JSONArray with all notification-JSONObjects
*/
public JSONArray getAll(){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray all = new JSONArray();
for (String id : alarmIds) {
JSONObject arguments;
try{
arguments = new JSONObject(alarms.get(id).toString());
all.put(arguments);
} catch(JSONException jse) {
jse.printStackTrace();
}
}
return all;
}
/**
* Retrieves a list with all currently scheduled notification-JSONObjects.
*
* @return JSONArray with all notification-JSONObjects
*/
public JSONArray getScheduled(){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray scheduled = new JSONArray();
for (String id : alarmIds) {
boolean isScheduled;
JSONObject arguments = null;
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){
scheduled.put(arguments);
}
}
return scheduled;
}
/**
* Retrieves a list with all currently triggered notification-JSONObjects.
*
* @return JSONArray with all notification-JSONObjects
*/
public JSONArray getTriggered(){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray triggered = new JSONArray();
Date now = new Date();
for (String id : alarmIds) {
boolean isTriggered;
JSONObject arguments = null;
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) {
triggered.put(arguments);
}
}
return triggered;
}
/**
* Retrieves a list with all currently pending notification JSONObject.
*
* @return JSONArray with all notification-JSONObjects
*/
public JSONArray getAll(JSONArray ids){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray all = new JSONArray();
for (String id : alarmIds) {
for(int i=0;i<ids.length();i++){
if(ids.optString(i).equals(id)){
JSONObject arguments;
try{
arguments = new JSONObject(alarms.get(id).toString());
all.put(arguments);
} catch(JSONException jse) {
jse.printStackTrace();
}
}
}
}
return all;
}
/**
* Retrieves a list with all currently scheduled notification-JSONObjects.
*
* @return JSONArray with all notification-JSONObjects
*/
public JSONArray getScheduled(JSONArray ids){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray scheduled = new JSONArray();
boolean isScheduled;
for (String id : alarmIds) {
for(int i=0;i<ids.length();i++){
if(ids.optString(i).equals(id)){
JSONObject arguments = null;
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){
scheduled.put(arguments);
}
}
}
}
return scheduled;
}
/**
* Retrieves a list with all currently triggered notification-JSONObjects.
*
* @return JSONArray with all notification-JSONObjects
*/
public JSONArray getTriggered(JSONArray ids){
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet();
JSONArray triggered = new JSONArray();
Date now = new Date();
for (String id : alarmIds) {
for(int i=0;i<ids.length();i++){
if(ids.optString(i).equals(id)){
boolean isTriggered;
JSONObject arguments = null;
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) {
triggered.put(arguments);
}
}
}
}
return triggered;
}
//---------------Manage Shared Preferences---------------------------------------------------
/**
* The Local storage for the application.
*/
private SharedPreferences getSharedPreferences () {
return context.getSharedPreferences(PLUGIN_NAME, Context.MODE_PRIVATE);
}
/**
* 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.
*
* @param alarmId
* The Id of the notification that must be persisted.
* @param args
* The assumption is that parse has been called already.
*/
public void persist (String alarmId, JSONObject args) {
Editor editor = getSharedPreferences().edit();
if (alarmId != null) {
editor.putString(alarmId, args.toString());
if (Build.VERSION.SDK_INT<9) {
editor.commit();
} else {
editor.apply();
}
}
}
/**
* Remove a specific alarm from the Android shared Preferences.
*
* @param alarmId
* The Id of the notification that must be removed.
*/
public void unpersist (String alarmId) {
Editor editor = getSharedPreferences().edit();
if (alarmId != null) {
editor.remove(alarmId);
if (Build.VERSION.SDK_INT<9) {
editor.commit();
} else {
editor.apply();
}
}
}
}
/*
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.notification;
import java.util.Random;
import android.annotation.SuppressLint;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import android.support.v4.app.NotificationCompat.Builder;
import android.widget.Toast;
public class NotificationBuilder {
private Options options;
private Context context;
private Builder notification;
private final String OPTIONS;
private Class<?> deleteIntentReceiver;
private Class<?> receiverActivity;
/**
* Constructor of NotificationBuilder
* @param options
* @param context
* @param OPTIONS
* @param deleteIntentReceiver
* @param receiverActivity
*/
public NotificationBuilder(Options options,Context context, String OPTIONS,
Class<?> deleteIntentReceiver, Class<?> receiverActivity){
this.options = options;
this.context = context;
this.OPTIONS = OPTIONS;
this.deleteIntentReceiver = deleteIntentReceiver;
this.receiverActivity = receiverActivity;
}
/**
* Creates the notification.
*/
@SuppressLint("NewApi")
public void buildNotification () {
Uri sound = options.getSound();
//DeleteIntent is called when the user clears a notification manually
Intent deleteIntent = new Intent(context, deleteIntentReceiver)
.setAction("" + options.getId())
.putExtra(OPTIONS, options.getJSONObject().toString());
PendingIntent dpi = PendingIntent.getBroadcast(context, 0, deleteIntent, PendingIntent.FLAG_CANCEL_CURRENT);
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);
}
/**
* Adds an onclick handler to the notification
*/
private Builder setClickEvent (Builder notification) {
Intent intent = new Intent(context, receiverActivity)
.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")
public void showNotification () {
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());
}
}
/**
* Show a notification as a Toast when App is runing in foreground
* @param title Title of the notification
* @param notification Notification to show
*/
public void showNotificationToast(){
String title = options.getTitle();
String message = options.getMessage();
int duration = Toast.LENGTH_LONG;
if(title.equals("")){
title = "Notification";
}
String text = title + " \n " + message;
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.notification;
import java.util.Date;
import java.util.Map;
import java.util.Set;
import org.json.JSONException;
import org.json.JSONObject;
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;
/**
* Wrapper class to schedule, cancel, clear, and update notifications.
*
*/
public class NotificationWrapper {
//---------------Global Parameter------------------------------------------------------------
private Context context;
private Class<?> receiver;
private final String PLUGIN_NAME;
private final String OPTIONS;
//---------------Constructor-----------------------------------------------------------------
/**
* Constructor of NotificationWrapper-Class
*/
public NotificationWrapper(Context context, Class<?> receiver,String PluginName, String OPTIONS){
this.context = context;
this.receiver = receiver;
this.PLUGIN_NAME = PluginName;
this.OPTIONS = OPTIONS;
}
//---------------public functions------------------------------------------------------------
/**
* Schedule new notification
*/
public void schedule(Options options){
long triggerTime = options.getDate();
persist(options.getId(), options.getJSONObject());
//Intent is called when the Notification gets fired
Intent intent = new Intent(context, receiver)
.setAction("" + options.getId())
.putExtra(OPTIONS, options.getJSONObject().toString());
AlarmManager am = getAlarmManager();
PendingIntent pi = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
am.set(AlarmManager.RTC_WAKEUP, triggerTime, pi);
}
/**
* Cancel existing notification
*/
public 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)
.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) {}
unpersist(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 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();
}
/**
* Update an existing notification
*
* @param updates JSONObject with update-content
*/
public 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)
.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);
schedule(options);
}
/**
* 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 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;
}
}
/**
* Clear all notifications without canceling repeating alarms
*/
public 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();
}
//---------------Manage Shared Preferences---------------------------------------------------
/**
* The Local storage for the application.
*/
private SharedPreferences getSharedPreferences () {
return context.getSharedPreferences(PLUGIN_NAME, Context.MODE_PRIVATE);
}
/**
* 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.
*
* @param alarmId
* The Id of the notification that must be persisted.
* @param args
* The assumption is that parse has been called already.
*/
public void persist (String alarmId, JSONObject args) {
Editor editor = getSharedPreferences().edit();
if (alarmId != null) {
editor.putString(alarmId, args.toString());
if (Build.VERSION.SDK_INT<9) {
editor.commit();
} else {
editor.apply();
}
}
}
/**
* Remove a specific alarm from the Android shared Preferences.
*
* @param alarmId
* The Id of the notification that must be removed.
*/
public void unpersist (String alarmId) {
Editor editor = getSharedPreferences().edit();
if (alarmId != null) {
editor.remove(alarmId);
if (Build.VERSION.SDK_INT<9) {
editor.commit();
} else {
editor.apply();
}
}
}
//---------------private functions-----------------------------------------------------------
/**
* The alarm manager for the application.
*/
private AlarmManager getAlarmManager () {
return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
/**
* The notification manager for the application.
*/
private NotificationManager getNotificationManager () {
return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE);
}
/**
* Update the Arguments Input with content from updates-input
*
* @param arguments The notifications optionArray
* @param updates The content you like to change
*
* @return The updated value
*/
private 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;
}
/**
* Function to set the value of "initialDate" in the JSONArray
* @param args The given JSONArray
* @return A new JSONArray with the parameter "initialDate" set.
*/
private JSONObject setInitDate(JSONObject arguments){
long initialDate = arguments.optLong("date", 0) * 1000;
try {
arguments.put("initialDate", initialDate);
} catch (JSONException e) {
e.printStackTrace();
}
return arguments;
}
}
......@@ -19,51 +19,40 @@
under the License.
*/
package de.appplant.cordova.plugin.localnotification;
package de.appplant.cordova.plugin.notification;
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;
private Context context;
Options (Activity activity) {
packageName = activity.getPackageName();
}
Options (Context context) {
packageName = context.getPackageName();
public Options(Context context){
this.context= context;
this.packageName = context.getPackageName();
}
/**
* Parses the given properties
*/
......@@ -156,18 +145,13 @@ public class Options {
* 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);
}
Uri soundUri = null;
try{
soundUri = Uri.parse(options.optString("soundUri"));
return soundUri;
} catch (Exception e){
e.printStackTrace();
}
return null;
}
......@@ -177,11 +161,15 @@ public class Options {
public Bitmap getIcon () {
String icon = options.optString("icon", "icon");
Bitmap bmp = null;
Uri iconUri = null;
try{
iconUri = Uri.parse(options.optString("iconUri"));
} catch (Exception e){
e.printStackTrace();
}
if (icon.startsWith("http")) {
bmp = getIconFromURL(icon);
} else if (icon.startsWith("file://") || (icon.startsWith("res"))) {
bmp = getIconFromURI(icon);
if (iconUri != null) {
bmp = getIconFromUri(iconUri);
}
if (bmp == null) {
......@@ -267,6 +255,14 @@ public class Options {
}
/**
* Shows the behavior of notifications when the application is in foreground
*
*/
public boolean getForegroundMode(){
return options.optBoolean("foregroundMode",false);
}
/**
* Returns numerical icon Value
*
* @param {String} className
......@@ -293,7 +289,7 @@ public class Options {
* The corresponding bitmap
*/
private Bitmap getIconFromRes (String icon) {
Resources res = LocalNotification.context.getResources();
Resources res = context.getResources();
int iconId = 0;
iconId = getIconValue(packageName, icon);
......@@ -311,41 +307,7 @@ public class Options {
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.
......@@ -355,12 +317,11 @@ public class Options {
* @return
* The corresponding bitmap
*/
private Bitmap getIconFromURI (String src) {
private Bitmap getIconFromUri (Uri uri) {
Bitmap bmp = null;
Uri uri = getURIfromPath(src);
try {
InputStream input = LocalNotification.activity.getContentResolver().openInputStream(uri);
InputStream input = context.getContentResolver().openInputStream(uri);
bmp = BitmapFactory.decodeStream(input);
} catch (IOException e) {
e.printStackTrace();
......@@ -370,164 +331,17 @@ public class Options {
}
/**
* 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
* Function to set the value of "initialDate" in the JSONArray
* @param args The given JSONArray
* @return A new JSONArray with the parameter "initialDate" set.
*/
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();
public void setInitDate(){
long initialDate = options.optLong("date", 0) * 1000;
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);
options.put("initialDate", initialDate);
} catch (JSONException e) {
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);
}
}
......@@ -120,7 +120,7 @@ exports.add = function (props, callback, scope) {
this.convertProperties(properties);
}
if (device.platform != 'iOS') {
if (device.platform != 'iOS'&&device.platform != 'Android' ) {
notifications = notifications[0];
}
......@@ -152,10 +152,12 @@ exports.update = function (options, callback, 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);
};
/**
......@@ -186,7 +188,7 @@ exports.cancel = function (ids, callback, scope) {
ids = this.convertIds(ids);
if (device.platform != 'iOS') {
if (device.platform != 'iOS'&&device.platform != 'Android' ) {
ids = ids[0];
}
......
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