Commit 53fe0a5e by Sebastián Katzer

Release v0.8rc

parent 7f6c1ce0
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0" <plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
id="de.appplant.cordova.plugin.local-notification" id="de.appplant.cordova.plugin.local-notification"
version="0.8.0dev"> version="0.8.0rc">
<name>LocalNotification</name> <name>LocalNotification</name>
...@@ -14,12 +14,16 @@ ...@@ -14,12 +14,16 @@
<author>Sebastián Katzer</author> <author>Sebastián Katzer</author>
<!-- cordova -->
<engines> <engines>
<engine name="cordova" version=">=3.0.0" /> <engine name="cordova" version=">=3.0.0" />
</engines> </engines>
<dependency id="org.apache.cordova.device" url="https://github.com/apache/cordova-plugin-device" /> <dependency
id="org.apache.cordova.device"
url="https://github.com/apache/cordova-plugin-device" />
<!-- js -->
<js-module src="www/local-notification.js" name="LocalNotification"> <js-module src="www/local-notification.js" name="LocalNotification">
<clobbers target="cordova.plugins.notification.local" /> <clobbers target="cordova.plugins.notification.local" />
<clobbers target="plugin.notification.local" /> <clobbers target="plugin.notification.local" />
...@@ -34,15 +38,15 @@ ...@@ -34,15 +38,15 @@
</feature> </feature>
</config-file> </config-file>
<header-file src="src/ios/AppDelegate+APPLocalNotification.h" />
<source-file src="src/ios/AppDelegate+APPLocalNotification.m" />
<header-file src="src/ios/APPLocalNotification.h" /> <header-file src="src/ios/APPLocalNotification.h" />
<source-file src="src/ios/APPLocalNotification.m" /> <source-file src="src/ios/APPLocalNotification.m" />
<header-file src="src/ios/APPLocalNotificationOptions.h" /> <header-file src="src/ios/APPLocalNotificationOptions.h" />
<source-file src="src/ios/APPLocalNotificationOptions.m" /> <source-file src="src/ios/APPLocalNotificationOptions.m" />
<header-file src="src/ios/AppDelegate+APPLocalNotification.h" />
<source-file src="src/ios/AppDelegate+APPLocalNotification.m" />
<header-file src="src/ios/UIApplication+APPLocalNotification.h" /> <header-file src="src/ios/UIApplication+APPLocalNotification.h" />
<source-file src="src/ios/UIApplication+APPLocalNotification.m" /> <source-file src="src/ios/UIApplication+APPLocalNotification.m" />
...@@ -59,38 +63,39 @@ ...@@ -59,38 +63,39 @@
</config-file> </config-file>
<config-file target="AndroidManifest.xml" parent="/manifest/application"> <config-file target="AndroidManifest.xml" parent="/manifest/application">
<!--
* The alarm receiver is triggered when a scheduled alarm is fired. This class <receiver
* reads the information in the intent and displays this information in the android:name="de.appplant.cordova.plugin.localnotification.TriggerReceiver"
* Android notification bar. The notification uses the default notification android:exported="false" />
* sound and it vibrates the phone.
--> <receiver
<receiver android:name="de.appplant.cordova.plugin.localnotification.Receiver" android:exported="false" /> android:name="de.appplant.cordova.plugin.localnotification.ClearReceiver"
android:exported="false" />
<!--
* The delete intent receiver is triggered when the user clears a notification <activity
* manually. It unpersists the cleared notification from the shared preferences. android:name="de.appplant.cordova.plugin.localnotification.ClickActivity"
--> android:launchMode="singleInstance"
<receiver android:name="de.appplant.cordova.plugin.localnotification.DeleteIntentReceiver" android:exported="false"/> android:theme="@android:style/Theme.NoDisplay" />
<!-- <receiver
* This class is triggered upon reboot of the device. It needs to re-register android:name="de.appplant.cordova.plugin.notification.TriggerReceiver"
* the alarms with the AlarmManager since these alarms are lost in case of android:exported="false" />
* reboot.
--> <receiver
<receiver android:name="de.appplant.cordova.plugin.localnotification.Restore" > android:name="de.appplant.cordova.plugin.notification.ClearReceiver"
android:exported="false" />
<receiver android:name="de.appplant.cordova.plugin.localnotification.RestoreReceiver" >
<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:name="de.appplant.cordova.plugin.notification.ClickActivity"
android:launchMode="singleInstance"
android:theme="@android:style/Theme.NoDisplay" />
<!--
* The receiver activity is triggered when a notification is clicked by a user.
* The activity calls the background callback and brings the launch inten
* up to foreground.
-->
<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">
...@@ -99,29 +104,74 @@ ...@@ -99,29 +104,74 @@
<lib-file src="libs/android/android-support-v4.jar" /> <lib-file src="libs/android/android-support-v4.jar" />
<source-file src="src/android/LocalNotification.java" target-dir="src/de/appplant/cordova/plugin/localnotification" /> <source-file
<source-file src="src/android/Receiver.java" target-dir="src/de/appplant/cordova/plugin/localnotification" /> src="src/android/LocalNotification.java"
<source-file src="src/android/Restore.java" target-dir="src/de/appplant/cordova/plugin/localnotification" /> 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 --> <source-file
<!-- <platform name="wp8"> src="src/android/TriggerReceiver.java"
<config-file target="config.xml" parent="/*"> target-dir="src/de/appplant/cordova/plugin/localnotification" />
<feature name="LocalNotification">
<param name="wp-package" value="LocalNotification"/>
</feature>
</config-file>
<source-file src="src/wp8/LocalNotification.cs" /> <source-file
<source-file src="src/wp8/Options.cs" /> src="src/android/ClickActivity.java"
</platform> --> target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file
src="src/android/ClearReceiver.java"
target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file
src="src/android/RestoreReceiver.java"
target-dir="src/de/appplant/cordova/plugin/localnotification" />
<source-file
src="src/android/notification/AbstractClearReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/AbstractClickActivity.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/AbstractRestoreReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/AbstractTriggerReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/AssetUtil.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/Builder.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/ClearReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/ClickActivity.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/Manager.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/Notification.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/Options.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
<source-file
src="src/android/notification/TriggerReceiver.java"
target-dir="src/de/appplant/cordova/plugin/notification" />
</platform>
</plugin> </plugin>
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.localnotification;
import de.appplant.cordova.plugin.notification.Notification;
/**
* The clear intent receiver is triggered when the user clears a
* notification manually. It un-persists the cleared notification from the
* shared preferences.
*/
public class ClearReceiver extends de.appplant.cordova.plugin.notification.ClearReceiver {
/**
* Called when a local notification was cleared from outside of the app.
*
* @param notification
* Wrapper around the local notification
*/
@Override
public void onClear (Notification notification) {
super.onClear(notification);
LocalNotification.fireEvent("clear", notification);
}
}
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.localnotification;
import de.appplant.cordova.plugin.notification.*;
import de.appplant.cordova.plugin.notification.TriggerReceiver;
/**
* The receiver activity is triggered when a notification is clicked by a user.
* The activity calls the background callback and brings the launch intent
* up to foreground.
*/
public class ClickActivity extends de.appplant.cordova.plugin.notification.ClickActivity {
/**
* Called when local notification was clicked by the user.
*
* @param notification
* Wrapper around the local notification
*/
@Override
public void onClick(Notification notification) {
LocalNotification.fireEvent("click", notification);
if (!notification.isRepeating()) {
LocalNotification.fireEvent("cancel", notification);
}
super.onClick(notification);
}
/**
* Build notification specified by options.
*
* @param builder
* Notification builder
*/
@Override
public Notification buildNotification (Builder builder) {
return builder
.setTriggerReceiver(TriggerReceiver.class)
.build();
}
}
/*
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.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.BroadcastReceiver;
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;
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)){
options.setInitDate();
LocalNotification.persist(options.getId(), options.getJSONObject());
}
else if((new Date(options.getDate()).before(now))){
LocalNotification.unpersist(options.getId());
}
fireClearEvent(options);
}
/**
* Fires onclear event.
*/
private void fireClearEvent (Options options) {
JSONArray data = new JSONArray().put(options.getJSONObject());
LocalNotification.fireEvent("clear", options.getId(), options.getJSON(),data);
}
}
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*/ *
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.localnotification; package de.appplant.cordova.plugin.localnotification;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List;
import org.apache.cordova.CallbackContext; import org.apache.cordova.CallbackContext;
import org.apache.cordova.CordovaInterface;
import org.apache.cordova.CordovaPlugin; import org.apache.cordova.CordovaPlugin;
import org.apache.cordova.CordovaWebView; import org.apache.cordova.CordovaWebView;
import org.apache.cordova.PluginResult; import org.apache.cordova.PluginResult;
...@@ -32,474 +34,478 @@ import org.json.JSONArray; ...@@ -32,474 +34,478 @@ 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.NotificationManager;
import android.content.Context;
import android.content.SharedPreferences;
import android.content.SharedPreferences.Editor;
import android.os.Build; import android.os.Build;
import android.annotation.TargetApi;
import de.appplant.cordova.plugin.notification.*; import de.appplant.cordova.plugin.notification.*;
/** /**
* This plugin utilizes the Android AlarmManager in combination with StatusBar * This plugin utilizes the Android AlarmManager in combination with local
* notifications. When a local notification is scheduled the alarm manager takes * notifications. When a local notification is scheduled the alarm manager takes
* care of firing the event. When the event is processed, a notification is put * care of firing the event. When the event is processed, a notification is put
* in the Android status bar. * in the Android notification center and status bar.
*/ */
public class LocalNotification extends CordovaPlugin { 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 CordovaWebView webView = null;
private static Boolean deviceready = false; private static Boolean deviceready = false;
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;
Asset asset;
Manager manager;
NotificationWrapper nWrapper;
@Override
public void initialize (CordovaInterface cordova, CordovaWebView webView) {
super.initialize(cordova, webView);
/**
* Called after plugin construction and fields have been initialized.
*/
@Override
protected void pluginInitialize() {
LocalNotification.webView = super.webView; 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);
} }
/**
* Called when the system is about to start resuming a previous activity.
*
* @param multitasking
* Flag indicating if multitasking is turned on for app
*/
@Override @Override
public boolean execute (String action, final JSONArray args, final CallbackContext command) throws JSONException { public void onPause(boolean multitasking) {
super.onPause(multitasking);
if (action.equalsIgnoreCase("add")) { isInBackground = true;
cordova.getThreadPool().execute( new Runnable() { }
public void run() {
add(args); /**
* Called when the activity will start interacting with the user.
*
* @param multitasking
* Flag indicating if multitasking is turned on for app
*/
@Override
public void onResume(boolean multitasking) {
super.onResume(multitasking);
isInBackground = false;
}
/**
* Executes the request.
*
* This method is called from the WebView thread. To do a non-trivial
* amount of work, use:
* cordova.getThreadPool().execute(runnable);
*
* To run on the UI thread, use:
* cordova.getActivity().runOnUiThread(runnable);
*
* @param action
* The action to execute.
* @param args
* The exec() arguments in JSON form.
* @param command
* The callback context used when calling back into JavaScript.
* @return
* Whether the action was valid.
*/
@Override
public boolean execute (final String action, final JSONArray args,
final CallbackContext command) throws JSONException {
Notification.setDefaultTriggerReceiver(TriggerReceiver.class);
cordova.getThreadPool().execute(new Runnable() {
public void run() {
if (action.equals("schedule")) {
schedule(args);
command.success(); command.success();
} }
}); else if (action.equals("update")) {
} update(args);
command.success();
if (action.equalsIgnoreCase("update")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
update(args);
command.success();
} }
}); else if (action.equals("cancel")) {
} cancel(args);
if (action.equalsIgnoreCase("cancel")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
cancel(args);
command.success(); command.success();
} }
}); else if (action.equals("cancelAll")) {
} cancelAll();
if (action.equalsIgnoreCase("cancelAll")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
cancelAll(args);
command.success(); command.success();
} }
}); else if (action.equals("clear")) {
} clear(args);
if (action.equalsIgnoreCase("clear")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
clear(args);
command.success(); command.success();
} }
}); else if (action.equals("clearAll")) {
} clearAll();
if (action.equalsIgnoreCase("clearAll")) {
cordova.getThreadPool().execute( new Runnable() {
public void run() {
clearAll(args);
command.success(); command.success();
} }
}); else if (action.equals("isPresent")) {
} isPresent(args.optInt(0), command);
}
else if (action.equals("isScheduled")) {
isScheduled(args.optInt(0), command);
}
else if (action.equals("isTriggered")) {
isTriggered(args.optInt(0), command);
}
else if (action.equals("getAllIds")) {
getAllIds(command);
}
else if (action.equals("getScheduledIds")) {
getScheduledIds(command);
}
else if (action.equals("getTriggeredIds")) {
getTriggeredIds(command);
}
else if (action.equals("getAll")) {
getAll(args, command);
}
else if (action.equals("getScheduled")) {
getScheduled(args, command);
}
else if (action.equals("getTriggered")) {
getTriggered(args, command);
}
else if (action.equals("deviceready")) {
deviceready();
}
}
});
if (action.equalsIgnoreCase("isScheduled")) { return true;
String id = args.optString(0); }
boolean isScheduled = manager.isScheduled(id);
PluginResult result = new PluginResult(PluginResult.Status.OK, (isScheduled));
command.sendPluginResult(result);
}
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("exist")) {
String id = args.optString(0);
boolean exist = manager.exist(id);
PluginResult result = new PluginResult(PluginResult.Status.OK, exist);
command.sendPluginResult(result);
}
if (action.equalsIgnoreCase("getScheduledIds")) { /**
JSONArray scheduledIds = manager.getScheduledIds(); * Schedule multiple local notifications.
command.success(scheduledIds); *
} * @param notifications
* Properties for each local notification
*/
private void schedule (JSONArray notifications) {
for (int i = 0; i < notifications.length(); i++) {
JSONObject options = notifications.optJSONObject(i);
if (action.equalsIgnoreCase("getTriggeredIds")) { getNotificationMgr().schedule(options, TriggerReceiver.class);
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")) { /**
cordova.getThreadPool().execute( new Runnable() { * Update multiple local notifications.
public void run() { *
deviceready(); * @param updates
} * Notification properties including their IDs
}); */
} private void update (JSONArray updates) {
for (int i = 0; i < updates.length(); i++) {
JSONObject update = updates.optJSONObject(i);
int id = update.optInt("id", 0);
if (action.equalsIgnoreCase("pause")) { Notification notification =
isInBackground = true; getNotificationMgr().update(id, update, TriggerReceiver.class);
}
if (action.equalsIgnoreCase("resume")) { fireEvent("update", notification);
isInBackground = false;
} }
}
return true; /**
* Cancel multiple local notifications.
*
* @param ids
* Set of local notification IDs
*/
private void cancel (JSONArray ids) {
for (int i = 0; i < ids.length(); i++) {
int id = ids.optInt(i, 0);
Notification notification =
getNotificationMgr().cancel(id);
fireEvent("cancel", notification);
}
} }
//------------------------------------------------exec-Functions-----------------------------------------------
/** /**
* Schedule notifications contained in the args-Array * Cancel all scheduled notifications.
* @param args
*/ */
private void add(JSONArray args){ private void cancelAll() {
JSONArray notifications = args; getNotificationMgr().cancelAll();
JSONObject arguments; fireEvent("cancelall");
for(int i=0;i<notifications.length();i++){
arguments = notifications.optJSONObject(i);
arguments = asset.parseURIs(arguments);
Options options = new Options(context).parse(arguments);
options.setInitDate();
nWrapper.schedule(options);
JSONArray fireData= new JSONArray().put(options.getJSONObject());
fireEvent("add", options.getId(),options.getJSON(), fireData);
}
} }
/** /**
* Update existing notifications * Clear multiple local notifications without canceling them.
* @param args *
* @param ids
* Set of local notification IDs
*/ */
private void update(JSONArray args){ private void clear(JSONArray ids){
JSONArray updates = args; for (int i = 0; i < ids.length(); i++) {
JSONObject updateContent; int id = ids.optInt(i, 0);
for(int i=0;i<updates.length();i++){
updateContent = args.optJSONObject(i); Notification notification =
getNotificationMgr().clear(id);
nWrapper.update(updateContent);
} fireEvent("clear", notification);
}
} }
/** /**
* Cancel scheduled Notifications * Clear all triggered notifications without canceling them.
* @param args
*/ */
private void cancel(JSONArray args){ private void clearAll() {
JSONArray ids = args; getNotificationMgr().clearAll();
String id; fireEvent("clearall");
for(int i=0;i<ids.length();i++){
id = args.optString(i);
nWrapper.cancel(id);
JSONArray managerId = new JSONArray().put(id);
JSONArray data = manager.getAll(managerId);
fireEvent("cancel", id, "",data);
}
} }
/** /**
* Cancel all scheduled notifications * If a notification with an ID is present.
* @param args *
* @param id
* Notification ID
* @param command
* The callback context used when calling back into JavaScript.
*/ */
public void cancelAll(JSONArray args){ private void isPresent (int id, CallbackContext command) {
JSONArray options = manager.getAll(); boolean exist = getNotificationMgr().exist(id);
nWrapper.cancelAll();
String id; PluginResult result = new PluginResult(
JSONObject arguments; PluginResult.Status.OK, exist);
for(int i=0;i<options.length();i++){
arguments= (JSONObject) options.opt(i); command.sendPluginResult(result);
JSONArray data = new JSONArray().put(arguments);
id = arguments.optString("id");
fireEvent("cancel", id, "",data);
}
} }
/** /**
* Clear triggered notifications without cancel repeating. * If a notification with an ID is scheduled.
* @param args *
* @param id
* Notification ID
* @param command
* The callback context used when calling back into JavaScript.
*/ */
public void clear(JSONArray args){ private void isScheduled (int id, CallbackContext command) {
JSONArray ids = args; boolean exist = getNotificationMgr().exist(
String id; id, Notification.Type.SCHEDULED);
for(int i=0;i<ids.length();i++){
id = args.optString(i); PluginResult result = new PluginResult(
nWrapper.clear(id); PluginResult.Status.OK, exist);
JSONArray managerId = new JSONArray().put(id);
JSONArray data = manager.getAll(managerId); command.sendPluginResult(result);
fireEvent("clear", id, "",data);
}
} }
/** /**
* Clear all triggered notifications without cancel repeating. * If a notification with an ID is triggered.
* @param args *
* @param id
* Notification ID
* @param command
* The callback context used when calling back into JavaScript.
*/ */
public void clearAll(JSONArray args){ private void isTriggered (int id, CallbackContext command) {
JSONArray options = manager.getAll(); boolean exist = getNotificationMgr().exist(
nWrapper.clearAll(); id, Notification.Type.TRIGGERED);
String id;
JSONObject arguments; PluginResult result = new PluginResult(
for(int i=0;i<options.length();i++){ PluginResult.Status.OK, exist);
arguments= (JSONObject) options.opt(i);
JSONArray data = new JSONArray().put(arguments); command.sendPluginResult(result);
id = arguments.optString("id");
fireEvent("clear", id, "",data);
}
} }
//-------------------------------------------------------------------------------------------------------------
/** /**
* Calls all pending callbacks after the deviceready event has been fired. * Set of IDs from all existent notifications.
*
* @param command
* The callback context used when calling back into JavaScript.
*/ */
private static void deviceready () { private void getAllIds (CallbackContext command) {
deviceready = true; List<Integer> ids = getNotificationMgr().getIds();
for (String js : eventQueue) { command.success(new JSONArray(ids));
sendJavascript(js); }
}
eventQueue.clear(); /**
* Set of IDs from all scheduled notifications.
*
* @param command
* The callback context used when calling back into JavaScript.
*/
private void getScheduledIds (CallbackContext command) {
List<Integer> ids = getNotificationMgr().getIdsByType(
Notification.Type.SCHEDULED);
command.success(new JSONArray(ids));
} }
/** /**
* Persist the information of this alarm to the Android Shared Preferences. * Set of IDs from all triggered notifications.
* This will allow the application to restore the alarm upon device reboot.
* Also this is used by the cancelAll method.
* *
* @param alarmId * @param command
* The Id of the notification that must be persisted. * The callback context used when calling back into JavaScript.
* @param args
* The assumption is that parse has been called already.
*/ */
public static void persist (String alarmId, JSONObject args) { private void getTriggeredIds (CallbackContext command) {
Editor editor = getSharedPreferences().edit(); List<Integer> ids = getNotificationMgr().getIdsByType(
Notification.Type.TRIGGERED);
if (alarmId != null) {
editor.putString(alarmId, args.toString()); command.success(new JSONArray(ids));
if (Build.VERSION.SDK_INT<9) {
editor.commit();
} else {
editor.apply();
}
}
} }
/** /**
* Remove a specific alarm from the Android shared Preferences. * Set of options from local notification.
* *
* @param alarmId * @param ids
* The Id of the notification that must be removed. * Set of local notification IDs
* @param command
* The callback context used when calling back into JavaScript.
*/ */
public static void unpersist (String alarmId) { private void getAll (JSONArray ids, CallbackContext command) {
Editor editor = getSharedPreferences().edit(); List<JSONObject> options;
if (alarmId != null) { if (ids.length() == 0) {
editor.remove(alarmId); options = getNotificationMgr().getOptions();
if (Build.VERSION.SDK_INT<9) { } else {
editor.commit(); options = getNotificationMgr().getOptionsById(toList(ids));
} else {
editor.apply();
}
} }
command.success(new JSONArray(options));
} }
/** /**
* Clear all alarms from the Android shared Preferences. * Set of options from scheduled notifications.
*
* @param ids
* Set of local notification IDs
* @param command
* The callback context used when calling back into JavaScript.
*/ */
public static void unpersistAll () { private void getScheduled (JSONArray ids, CallbackContext command) {
Editor editor = getSharedPreferences().edit(); List<JSONObject> options;
editor.clear(); if (ids.length() == 0) {
if (Build.VERSION.SDK_INT<9) { options = getNotificationMgr().getOptionsByType(Notification.Type.SCHEDULED);
editor.commit();
} else { } else {
editor.apply(); options = getNotificationMgr().getOptionsBy(
Notification.Type.SCHEDULED, toList(ids));
} }
command.success(new JSONArray(options));
} }
//
/** /**
* Fires the given event (Only one Callback also for multiple notifications in one action). * Set of options from triggered notifications.
* *
* @param {String} event The Name of the event * @param ids
* @param ids The IDs of the notifications as JSONArray * Set of local notification IDs
* @param json The notifications JSONObjects in a JSONArray * @param command
* The callback context used when calling back into JavaScript.
*/ */
public static void fireEvent (String event, JSONArray ids, JSONArray json) { private void getTriggered (JSONArray ids, CallbackContext command) {
String state = getApplicationState(); List<JSONObject> options;
String params = ids + ",\"" + state + "\"," + json;
String js = "setTimeout('plugin.notification.local.on" + event + "(" + params + ")',0)"; if (ids.length() == 0) {
options = getNotificationMgr().getOptionsByType(Notification.Type.TRIGGERED);
// webview may available, but callbacks needs to be executed
// after deviceready
if (deviceready == false) {
eventQueue.add(js);
} else { } else {
options = getNotificationMgr().getOptionsBy(
Notification.Type.TRIGGERED, toList(ids));
}
command.success(new JSONArray(options));
}
/**
* Call all pending callbacks after the deviceready event has been fired.
*/
private static synchronized void deviceready () {
isInBackground = false;
deviceready = true;
for (String js : eventQueue) {
sendJavascript(js); sendJavascript(js);
} }
eventQueue.clear();
} }
//
/** /**
* Fires the given event. (Standard-method) * Fire given event on JS side. Does inform all event listeners.
* *
* @param {String} event The Name of the event * @param event
* @param {String} id The ID of the notification * The event name
* @param {String} json A custom (JSON) string
* @param data The notifications as JSONObject
*/ */
public static void fireEvent (String event, String id, String json, JSONArray data) { private void fireEvent (String event) {
String state = getApplicationState(); fireEvent(event, null);
String params = "\"" + id + "\",\"" + state + "\"," + JSONObject.quote(json)+","+ data;
String js = "setTimeout('plugin.notification.local.on" + event + "(" + params + ")',0)";
// webview may available, but callbacks needs to be executed
// after deviceready
if (deviceready == false) {
eventQueue.add(js);
} else {
sendJavascript(js);
}
} }
/** /**
* Retrieves the application state * Fire given event on JS side. Does inform all event listeners.
* *
* @return {String} * @param event
* Either "background" or "foreground" * The event name
* @param notification
* Optional local notification to pass the id and properties.
*/ */
protected static String getApplicationState () { static void fireEvent (String event, Notification notification) {
return isInBackground ? "background" : "foreground"; String state = getApplicationState();
String params = "\"" + state + "\"";
if (notification != null) {
params = notification.toString() + "," + params;
}
String js = "cordova.plugins.notification.local.fireEvent(" +
"\"" + event + "\"," + params + ")";
sendJavascript(js);
} }
/** /**
* Set the application context if not already set. * Use this instead of deprecated sendJavascript
*
* @param js
* JS code snippet as string
*/ */
protected static void setContext (Context context) { private static void sendJavascript(final String js) {
if (LocalNotification.context == null) {
LocalNotification.context = context; if (!deviceready) {
eventQueue.add(js);
return;
} }
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);
}
}
});
} }
/** /**
* The Local storage for the application. * Convert JSON array of integers to List.
*
* @param ary
* Array of integers
*/ */
protected static SharedPreferences getSharedPreferences () { private List<Integer> toList (JSONArray ary) {
return context.getSharedPreferences(PLUGIN_NAME, Context.MODE_PRIVATE); ArrayList<Integer> list = new ArrayList<Integer>();
for (int i = 0; i < ary.length(); i++) {
list.add(ary.optInt(i));
}
return list;
} }
/** /**
* The alarm manager for the application. * Current application state.
*
* @return
* "background" or "foreground"
*/ */
protected static AlarmManager getAlarmManager () { static String getApplicationState () {
return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE); return isInBackground ? "background" : "foreground";
} }
/** /**
* The notification manager for the application. * Notification manager instance.
*/ */
protected static NotificationManager getNotificationManager () { private Manager getNotificationMgr() {
return (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); return Manager.getInstance(cordova.getActivity());
} }
/**
* Use this instead of deprecated sendJavascript
*/
@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);
}
}
});
}
} }
/*
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.Calendar;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.NotificationCompat.Builder;
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
* Android notification bar. The notification uses the default notification
* sound and it vibrates the phone.
*/
public class Receiver extends BroadcastReceiver {
public static final String OPTIONS = "LOCAL_NOTIFICATION_OPTIONS";
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;
try {
args = new JSONObject(bundle.getString(OPTIONS));
options = new Options(context).parse(args);
} catch (JSONException e) {
return;
}
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);
fireTriggerEvent();
if (options.getInterval() == 0) {
} else if (isFirstAlarmInFuture()) {
return;
} else {
JSONArray data = new JSONArray().put(options.getJSONObject());
LocalNotification.fireEvent("updateCall", options.getId(), options.getJSON(),data);
nWrapper.schedule(options.moveDate());
}
if (!LocalNotification.isInBackground && options.getForegroundMode()){
if (options.getInterval() == 0) {
LocalNotification.unpersist(options.getId());
}
nWrapper.showNotificationToast(options);
fireTriggerEvent();
} else {
Builder notification = builder.buildNotification();
nWrapper.showNotification(notification, options);
}
}
/*
* If you set a repeating alarm at 11:00 in the morning and it
* should trigger every morning at 08:00 o'clock, it will
* immediately fire. E.g. Android tries to make up for the
* 'forgotten' reminder for that day. Therefore we ignore the event
* if Android tries to 'catch up'.
*/
private Boolean isFirstAlarmInFuture () {
if (options.getInterval() > 0) {
Calendar now = Calendar.getInstance();
Calendar alarm = options.getCalendar();
int alarmHour = alarm.get(Calendar.HOUR_OF_DAY);
int alarmMin = alarm.get(Calendar.MINUTE);
int currentHour = now.get(Calendar.HOUR_OF_DAY);
int currentMin = now.get(Calendar.MINUTE);
if (currentHour != alarmHour && currentMin != alarmMin) {
return true;
}
}
return false;
}
/**
* Fires ontrigger event.
*/
private void fireTriggerEvent () {
JSONArray data = new JSONArray().put(options.getJSONObject());
LocalNotification.fireEvent("trigger", options.getId(), options.getJSON(),data);
}
}
/*
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 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. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Intent intent = this.getIntent();
Bundle bundle = intent.getExtras();
try {
JSONObject args = new JSONObject(bundle.getString(Receiver.OPTIONS));
Options options = new Options(getApplicationContext()).parse(args);
launchMainIntent();
fireClickEvent(options);
} catch (JSONException e) {}
}
/**
* Launch main intent for package.
*/
private void launchMainIntent () {
Context context = getApplicationContext();
String packageName = context.getPackageName();
Intent launchIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
launchIntent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(launchIntent);
}
/**
* Fires the onclick event.
*/
private void fireClickEvent (Options options) {
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(),data);
}
}
}
/*
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.Set;
import org.json.JSONArray;
import org.json.JSONException;
import android.content.BroadcastReceiver;
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
* reboot.
*/
public class Restore extends BroadcastReceiver {
@Override
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();
Set<String> alarmIds = alarms.getAll().keySet();
/*
* For each alarm, parse its alarm options and register is again with
* the Alarm Manager
*/
for (String alarmId : alarmIds) {
try {
JSONArray args = new JSONArray(alarms.getString(alarmId, ""));
Options options = new Options(context).parse(args.getJSONObject(0));
/*
* If the trigger date was in the past, the notification will be displayed immediately.
*/
nWrapper.schedule(options);
} catch (JSONException e) {}
}
}
}
/*
* Copyright (c) 2014-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.localnotification;
import de.appplant.cordova.plugin.notification.AbstractRestoreReceiver;
import de.appplant.cordova.plugin.notification.Builder;
import de.appplant.cordova.plugin.notification.Notification;
/**
* This class is triggered upon reboot of the device. It needs to re-register
* the alarms with the AlarmManager since these alarms are lost in case of
* reboot.
*/
public class RestoreReceiver extends AbstractRestoreReceiver {
/**
* Called when a local notification need to be restored.
*
* @param notification
* Wrapper around the local notification
*/
@Override
public void onRestore (Notification notification) {
notification.schedule();
}
/**
* Build notification specified by options.
*
* @param builder
* Notification builder
*/
@Override
public Notification buildNotification (Builder builder) {
return builder
.setTriggerReceiver(TriggerReceiver.class)
.setClearReceiver(ClearReceiver.class)
.setClickActivity(ClickActivity.class)
.build();
}
}
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.localnotification;
import de.appplant.cordova.plugin.notification.*;
/**
* The alarm receiver is triggered when a scheduled alarm is fired. This class
* reads the information in the intent and displays this information in the
* Android notification bar. The notification uses the default notification
* sound and it vibrates the phone.
*/
public class TriggerReceiver extends de.appplant.cordova.plugin.notification.TriggerReceiver {
/**
* Called when a local notification was triggered. Does present the local
* notification, re-schedule the alarm if necessary and fire trigger event.
*
* @param notification
* Wrapper around the local notification
* @param updated
* If an update has triggered or the original
*/
@Override
public void onTrigger (Notification notification, boolean updated) {
super.onTrigger(notification, updated);
if (!updated) {
LocalNotification.fireEvent("trigger", notification);
}
}
/**
* Build notification specified by options.
*
* @param builder
* Notification builder
*/
@Override
public Notification buildNotification (Builder builder) {
return builder
.setTriggerReceiver(TriggerReceiver.class)
.setClickActivity(ClickActivity.class)
.setClearReceiver(ClearReceiver.class)
.build();
}
}
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Abstract delete receiver for local notifications. Creates the local
* notification and calls the event functions for further proceeding.
*/
abstract public class AbstractClearReceiver extends BroadcastReceiver {
/**
* Called when the notification was cleared from the notification center.
*
* @param context
* Application context
* @param intent
* Received intent with content data
*/
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
JSONObject options;
try {
String data = bundle.getString(Options.EXTRA);
options = new JSONObject(data);
} catch (JSONException e) {
e.printStackTrace();
return;
}
Notification notification =
new Builder(context, options).build();
onClear(notification);
}
/**
* Called when a local notification was cleared from outside of the app.
*
* @param notification
* Wrapper around the local notification
*/
abstract public void onClear (Notification notification);
}
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import org.json.JSONException;
import org.json.JSONObject;
/**
* Abstract content receiver activity for local notifications. Creates the
* local notification and calls the event functions for further proceeding.
*/
abstract public class AbstractClickActivity extends Activity {
/**
* Called when local notification was clicked to launch the main intent.
*
* @param state
* Saved instance state
*/
@Override
public void onCreate (Bundle state) {
super.onCreate(state);
Intent intent = getIntent();
Bundle bundle = intent.getExtras();
Context context = getApplicationContext();
try {
String data = bundle.getString(Options.EXTRA);
JSONObject options = new JSONObject(data);
Builder builder =
new Builder(context, options);
Notification notification =
buildNotification(builder);
onClick(notification);
} catch (JSONException e) {
e.printStackTrace();
}
}
/**
* Called when local notification was clicked by the user.
*
* @param notification
* Wrapper around the local notification
*/
abstract public void onClick (Notification notification);
/**
* Build notification specified by options.
*
* @param builder
* Notification builder
*/
abstract public Notification buildNotification (Builder builder);
/**
* Launch main intent from package.
*/
public void launchApp() {
Context context = getApplicationContext();
String pkgName = context.getPackageName();
Intent intent = context
.getPackageManager()
.getLaunchIntentForPackage(pkgName);
intent.addFlags(
Intent.FLAG_ACTIVITY_REORDER_TO_FRONT | Intent.FLAG_ACTIVITY_SINGLE_TOP);
context.startActivity(intent);
}
}
/*
* Copyright (c) 2014-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import org.json.JSONObject;
import java.util.List;
/**
* This class is triggered upon reboot of the device. It needs to re-register
* the alarms with the AlarmManager since these alarms are lost in case of
* reboot.
*/
abstract public class AbstractRestoreReceiver extends BroadcastReceiver {
/**
* Called on device reboot.
*
* @param context
* Application context
* @param intent
* Received intent with content data
*/
@Override
public void onReceive (Context context, Intent intent) {
Manager notificationMgr =
Manager.getInstance(context);
List<JSONObject> options =
notificationMgr.getOptions();
for (JSONObject data : options) {
Builder builder = new Builder(context, data);
Notification notification =
buildNotification(builder);
onRestore(notification);
}
}
/**
* Called when a local notification need to be restored.
*
* @param notification
* Wrapper around the local notification
*/
abstract public void onRestore (Notification notification);
/**
* Build notification specified by options.
*
* @param builder
* Notification builder
*/
abstract public Notification buildNotification (Builder builder);
}
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Calendar;
/**
* Abstract broadcast receiver for local notifications. Creates the
* notification options and calls the event functions for further proceeding.
*/
abstract public class AbstractTriggerReceiver extends BroadcastReceiver {
/**
* Called when an alarm was triggered.
*
* @param context
* Application context
* @param intent
* Received intent with content data
*/
@Override
public void onReceive(Context context, Intent intent) {
Bundle bundle = intent.getExtras();
Options options;
try {
String data = bundle.getString(Options.EXTRA);
JSONObject dict = new JSONObject(data);
options = new Options(context).parse(dict);
} catch (JSONException e) {
e.printStackTrace();
return;
}
if (options == null)
return;
if (isFirstAlarmInFuture(options))
return;
Builder builder = new Builder(options);
Notification notification = buildNotification(builder);
boolean updated = notification.isUpdate();
onTrigger(notification, updated);
}
/**
* Called when a local notification was triggered.
*
* @param notification
* Wrapper around the local notification
* @param updated
* If an update has triggered or the original
*/
abstract public void onTrigger (Notification notification, boolean updated);
/**
* Build notification specified by options.
*
* @param builder
* Notification builder
*/
abstract public Notification buildNotification (Builder builder);
/*
* If you set a repeating alarm at 11:00 in the morning and it
* should trigger every morning at 08:00 o'clock, it will
* immediately fire. E.g. Android tries to make up for the
* 'forgotten' reminder for that day. Therefore we ignore the event
* if Android tries to 'catch up'.
*/
private Boolean isFirstAlarmInFuture (Options options) {
Notification notification = new Builder(options).build();
if (!notification.isRepeating())
return false;
Calendar now = Calendar.getInstance();
Calendar alarm = Calendar.getInstance();
alarm.setTime(notification.getOptions().getTriggerDate());
int alarmHour = alarm.get(Calendar.HOUR_OF_DAY);
int alarmMin = alarm.get(Calendar.MINUTE);
int currentHour = now.get(Calendar.HOUR_OF_DAY);
int currentMin = now.get(Calendar.MINUTE);
return (currentHour != alarmHour && currentMin != alarmMin);
}
}
/*
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.EMPTY;
}
/**
* 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();
}
}
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification;
import 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 android.content.Context;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.media.RingtoneManager;
import android.net.Uri;
import android.os.StrictMode;
import android.util.Log;
/**
* Util class to map unified asset URIs to native URIs. URIs like file:///
* map to absolute paths while file:// point relatively to the www folder
* within the asset resources. And res:// means a resource from the native
* res folder. Remote assets are accessible via http:// for example.
*/
class AssetUtil {
// Name of the storage folder
private static final String STORAGE_FOLDER = "/localnotification";
// Placeholder URI for default sound
private static final String DEFAULT_SOUND = "res://platform_default";
// Ref to the context passed through the constructor to access the
// resources and app directory.
private final Context context;
/**
* Constructor
*
* @param context
* Application context
*/
private AssetUtil(Context context) {
this.context = context;
}
/**
* Static method to retrieve class instance.
*
* @param context
* Application context
*/
static AssetUtil getInstance(Context context) {
return new AssetUtil(context);
}
/**
* Parse path path to native URI.
*
* @param path
* Path to path file
*/
Uri parseSound (String path) {
if (path == null || path.isEmpty())
return Uri.EMPTY;
if (path.equalsIgnoreCase(DEFAULT_SOUND)) {
return RingtoneManager.getDefaultUri(RingtoneManager
.TYPE_NOTIFICATION);
}
return parse(path);
}
/**
* The URI for a path.
*
* @param path
* The given path
*/
Uri parse (String path) {
if (path.startsWith("res:")) {
return getUriForResourcePath(path);
} else if (path.startsWith("file:///")) {
return getUriFromPath(path);
} else if (path.startsWith("file://")) {
return getUriFromAsset(path);
} else if (path.startsWith("http")){
return getUriFromRemote(path);
}
return Uri.EMPTY;
}
/**
* URI for a file.
*
* @param path
* Absolute path like file:///...
*
* @return
* URI pointing to the given path
*/
private Uri getUriFromPath(String path) {
String absPath = path.replaceFirst("file://", "");
File file = new File(absPath);
if (!file.exists()) {
Log.e("Asset", "File not found: " + file.getAbsolutePath());
return Uri.EMPTY;
}
return Uri.fromFile(file);
}
/**
* URI for an asset.
*
* @param path
* Asset path like file://...
*
* @return
* URI pointing to the given path
*/
private Uri getUriFromAsset(String path) {
File dir = context.getExternalCacheDir();
if (dir == null) {
Log.e("Asset", "Missing external cache dir");
return Uri.EMPTY;
}
String resPath = path.replaceFirst("file:/", "www");
String fileName = resPath.substring(resPath.lastIndexOf('/') + 1);
String storage = dir.toString() + STORAGE_FOLDER;
File file = new File(storage, fileName);
//noinspection ResultOfMethodCallIgnored
new File(storage).mkdir();
try {
AssetManager assets = context.getAssets();
FileOutputStream outStream = new FileOutputStream(file);
InputStream inputStream = assets.open(resPath);
copyFile(inputStream, outStream);
outStream.flush();
outStream.close();
return Uri.fromFile(file);
} catch (Exception e) {
Log.e("Asset", "File not found: assets/" + resPath);
e.printStackTrace();
}
return Uri.EMPTY;
}
/**
* The URI for a resource.
*
* @param path
* The given relative path
*
* @return
* URI pointing to the given path
*/
private Uri getUriForResourcePath(String path) {
File dir = context.getExternalCacheDir();
if (dir == null) {
Log.e("Asset", "Missing external cache dir");
return Uri.EMPTY;
}
String resPath = path.replaceFirst("res://", "");
int resId = getResIdForDrawable(resPath);
if (resId == 0) {
Log.e("Asset", "File not found: " + resPath);
return Uri.EMPTY;
}
String resName = extractResourceName(resPath);
String extName = extractResourceExtension(resPath);
String storage = dir.toString() + STORAGE_FOLDER;
File file = new File(storage, resName + extName);
//noinspection ResultOfMethodCallIgnored
new File(storage).mkdir();
try {
Resources res = context.getResources();
FileOutputStream outStream = new FileOutputStream(file);
InputStream inputStream = res.openRawResource(resId);
copyFile(inputStream, outStream);
outStream.flush();
outStream.close();
return Uri.fromFile(file);
} catch (Exception e) {
e.printStackTrace();
}
return Uri.EMPTY;
}
/**
* Uri from remote located content.
*
* @param path
* Remote address
*
* @return
* Uri of the downloaded file
*/
private Uri getUriFromRemote(String path) {
File dir = context.getExternalCacheDir();
if (dir == null) {
Log.e("Asset", "Missing external cache dir");
return Uri.EMPTY;
}
String resName = extractResourceName(path);
String extName = extractResourceExtension(path);
String storage = dir.toString() + STORAGE_FOLDER;
File file = new File(storage, resName + extName);
//noinspection ResultOfMethodCallIgnored
new File(storage).mkdir();
try {
URL url = new URL(path);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
StrictMode.ThreadPolicy policy =
new StrictMode.ThreadPolicy.Builder().permitAll().build();
StrictMode.setThreadPolicy(policy);
connection.setRequestProperty("Connection", "close");
connection.setConnectTimeout(5000);
connection.connect();
InputStream input = connection.getInputStream();
FileOutputStream outStream = new FileOutputStream(file);
copyFile(input, outStream);
outStream.flush();
outStream.close();
return Uri.fromFile(file);
} catch (MalformedURLException e) {
Log.e("Asset", "Incorrect URL");
e.printStackTrace();
} catch (FileNotFoundException e) {
Log.e("Asset", "Failed to create new File from HTTP Content");
e.printStackTrace();
} catch (IOException e) {
Log.e("Asset", "No Input can be created from http Stream");
e.printStackTrace();
}
return Uri.EMPTY;
}
/**
* Copy content from input stream into output stream.
*
* @param in
* The input stream
* @param out
* The output stream
*/
private void copyFile(InputStream in, OutputStream out) throws IOException {
byte[] buffer = new byte[1024];
int read;
while ((read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
}
}
/**
* Resource ID for drawable.
*
* @param resPath
* Resource path as string
*/
int getResIdForDrawable(String resPath) {
int resId = getResIdForDrawable(getPkgName(), resPath);
if (resId == 0) {
resId = getResIdForDrawable("android", resPath);
}
return resId;
}
/**
* Resource ID for drawable.
*
* @param clsName
* Relative package or global android name space
* @param resPath
* Resource path as string
*/
int getResIdForDrawable(String clsName, String resPath) {
String drawable = extractResourceName(resPath);
int resId = 0;
try {
Class<?> cls = Class.forName(clsName + ".R$drawable");
resId = (Integer) cls.getDeclaredField(drawable).get(Integer.class);
} catch (Exception ignore) {}
return resId;
}
/**
* Convert drawable resource to bitmap.
*
* @param drawable
* Drawable resource name
*/
Bitmap getIconFromDrawable (String drawable) {
Resources res = context.getResources();
int iconId;
iconId = getResIdForDrawable(getPkgName(), drawable);
if (iconId == 0) {
iconId = getResIdForDrawable("android", drawable);
}
if (iconId == 0) {
iconId = android.R.drawable.ic_menu_info_details;
}
return BitmapFactory.decodeResource(res, iconId);
}
/**
* Convert URI to Bitmap.
*
* @param uri
* Internal image URI
*/
Bitmap getIconFromUri (Uri uri) throws IOException {
InputStream input = context.getContentResolver().openInputStream(uri);
return BitmapFactory.decodeStream(input);
}
/**
* Extract name of drawable resource from path.
*
* @param resPath
* Resource path as string
*/
private String extractResourceName (String resPath) {
String drawable = resPath;
if (drawable.contains("/")) {
drawable = drawable.substring(drawable.lastIndexOf('/') + 1);
}
if (resPath.contains(".")) {
drawable = drawable.substring(0, drawable.lastIndexOf('.'));
}
return drawable;
}
/**
* Extract extension of drawable resource from path.
*
* @param resPath
* Resource path as string
*/
private String extractResourceExtension (String resPath) {
String extName = "png";
if (resPath.contains(".")) {
extName = resPath.substring(resPath.lastIndexOf('.'));
}
return extName;
}
/**
* Package name specified by context.
*/
private String getPkgName () {
return context.getPackageName();
}
}
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification;
import java.util.Random;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.support.v4.app.NotificationCompat;
import org.json.JSONObject;
/**
* Builder class for local notifications. Build fully configured local
* notification specified by JSON object passed from JS side.
*/
public class Builder {
// Application context passed by constructor
private final Context context;
// Notification options passed by JS
private final Options options;
// Receiver to handle the trigger event
private Class<?> triggerReceiver;
// Receiver to handle the clear event
private Class<?> clearReceiver = ClearReceiver.class;
// Activity to handle the click event
private Class<?> clickActivity = ClickActivity.class;
/**
* Constructor
*
* @param context
* Application context
* @param options
* Notification options
*/
public Builder(Context context, JSONObject options) {
this.context = context;
this.options = new Options(context).parse(options);
}
/**
* Constructor
*
* @param options
* Notification options
*/
public Builder(Options options) {
this.context = options.getContext();
this.options = options;
}
/**
* Set trigger receiver.
*
* @param receiver
* Broadcast receiver
*/
public Builder setTriggerReceiver(Class<?> receiver) {
this.triggerReceiver = receiver;
return this;
}
/**
* Set clear receiver.
*
* @param receiver
* Broadcast receiver
*/
public Builder setClearReceiver(Class<?> receiver) {
this.clearReceiver = receiver;
return this;
}
/**
* Set click activity.
*
* @param activity
* Activity
*/
public Builder setClickActivity(Class<?> activity) {
this.clickActivity = activity;
return this;
}
/**
* Creates the notification with all its options passed through JS.
*/
public Notification build() {
Uri sound = options.getSoundUri();
NotificationCompat.BigTextStyle style;
NotificationCompat.Builder builder;
style = new NotificationCompat.BigTextStyle()
.bigText(options.getText());
builder = new NotificationCompat.Builder(context)
.setDefaults(0)
.setContentTitle(options.getTitle())
.setContentText(options.getText())
.setNumber(options.getBadgeNumber())
.setTicker(options.getText())
.setSmallIcon(options.getSmallIcon())
.setLargeIcon(options.getIconBitmap())
.setAutoCancel(true)
.setOngoing(options.isOngoing())
.setStyle(style)
.setLights(options.getLedColor(), 500, 500);
if (sound != null) {
builder.setSound(sound);
}
applyDeleteReceiver(builder);
applyContentReceiver(builder);
return new Notification(context, options, builder, triggerReceiver);
}
/**
* Set intent to handle the delete event. Will clean up some persisted
* preferences.
*
* @param builder
* Local notification builder instance
*/
private void applyDeleteReceiver(NotificationCompat.Builder builder) {
if (clearReceiver == null)
return;
Intent deleteIntent = new Intent(context, clearReceiver)
.setAction(options.getId())
.putExtra(Options.EXTRA, options.toString());
PendingIntent dpi = PendingIntent.getBroadcast(
context, 0, deleteIntent, PendingIntent.FLAG_CANCEL_CURRENT);
builder.setDeleteIntent(dpi);
}
/**
* Set intent to handle the click event. Will bring the app to
* foreground.
*
* @param builder
* Local notification builder instance
*/
private void applyContentReceiver(NotificationCompat.Builder builder) {
if (clickActivity == null)
return;
Intent intent = new Intent(context, clickActivity)
.putExtra(Options.EXTRA, options.toString())
.setFlags(Intent.FLAG_ACTIVITY_NO_HISTORY);
int requestCode = new Random().nextInt();
PendingIntent contentIntent = PendingIntent.getActivity(
context, requestCode, intent, PendingIntent.FLAG_CANCEL_CURRENT);
builder.setContentIntent(contentIntent);
}
}
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification;
/**
* The clear intent receiver is triggered when the user clears a
* notification manually. It un-persists the cleared notification from the
* shared preferences.
*/
public class ClearReceiver extends AbstractClearReceiver {
/**
* Called when a local notification was cleared from outside of the app.
*
* @param notification
* Wrapper around the local notification
*/
@Override
public void onClear (Notification notification) {
notification.clear();
}
}
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification;
/**
* The receiver activity is triggered when a notification is clicked by a user.
* The activity calls the background callback and brings the launch intent
* up to foreground.
*/
public class ClickActivity extends AbstractClickActivity {
/**
* Called when local notification was clicked by the user. Will
* move the app to foreground.
*
* @param notification
* Wrapper around the local notification
*/
@Override
public void onClick(Notification notification) {
launchApp();
}
/**
* Build notification specified by options.
*
* @param builder
* Notification builder
*/
public Notification buildNotification (Builder builder) {
return builder.build();
}
}
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification; package de.appplant.cordova.plugin.notification;
import java.util.Date; import static de.appplant.cordova.plugin.notification.Notification.PREF_KEY;
import java.util.Map;
import java.util.Set; import android.app.NotificationManager;
import android.content.Context;
import android.content.SharedPreferences;
import org.json.JSONArray;
import org.json.JSONException; import org.json.JSONException;
import org.json.JSONObject; import org.json.JSONObject;
import android.content.Context; import java.util.ArrayList;
import android.content.SharedPreferences; import java.util.Date;
import android.content.SharedPreferences.Editor; import java.util.HashSet;
import android.os.Build; import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
public class Manager { /**
//---------------Global Parameter------------------------------------------------------------ * Central way to access all or single local notifications set by specific
* state like triggered or scheduled. Offers shortcut ways to schedule,
* cancel or clear local notifications.
*/
public class Manager {
// Context passed through constructor and used for notification builder.
private Context context; private Context context;
private final String PLUGIN_NAME;
/**
//---------------Constructor----------------------------------------------------------------- * Constructor
/** *
* Constructor of NotificationWrapper-Class * @param context
*/ * Application context
public Manager(Context context,String PluginName){ */
private Manager(Context context){
this.context = context; this.context = context;
this.PLUGIN_NAME = PluginName;
} }
//---------------Public Functions------------------------------------------------------------ /**
/** * Static method to retrieve class instance.
* Checks if a notification with an ID is scheduled.
* *
* @param id * @param context
* The notification ID to be check. * Application context
* @return true if the notification is scheduled
*/ */
public boolean isScheduled (String id) { public static Manager getInstance(Context context) {
SharedPreferences settings = getSharedPreferences(); return new Manager(context);
Map<String, ?> alarms = settings.getAll(); }
boolean isScheduled = alarms.containsKey(id);
boolean isNotTriggered = false; /**
* Schedule local notification specified by JSON object.
if (isScheduled) { *
JSONObject arguments; * @param options
try { * JSON object with set of options
arguments = new JSONObject(alarms.get(id).toString()); * @param receiver
Options options = new Options(context).parse(arguments); * Receiver to handle the trigger event
Date fireDate = new Date(options.getDate()); */
isNotTriggered = new Date().before(fireDate); public Notification schedule (JSONObject options, Class<?> receiver) {
} catch (JSONException e) { return schedule(new Options(context).parse(options), receiver);
isNotTriggered = false; }
e.printStackTrace();
} /**
* Schedule local notification specified by options object.
} *
* @param options
return (isScheduled && isNotTriggered); * Set of notification options
* @param receiver
* Receiver to handle the trigger event
*/
public Notification schedule (Options options, Class<?> receiver) {
Notification notification = new Builder(options)
.setTriggerReceiver(receiver)
.build();
notification.schedule();
return notification;
} }
/** /**
* Checks if a notification with an ID was triggered. * Clear local notification specified by ID.
* *
* @param id * @param id
* The notification ID to be check. * The notification ID
* @return true if the notification is triggered * @param updates
* JSON object with notification options
* @param receiver
* Receiver to handle the trigger event
*/ */
public boolean isTriggered (String id) { public Notification update (int id, JSONObject updates, Class<?> receiver) {
SharedPreferences settings = getSharedPreferences(); Notification notification = get(id);
Map<String, ?> alarms = settings.getAll();
boolean isScheduled = alarms.containsKey(id); if (notification == null)
boolean isTriggered = isScheduled; return null;
if (isScheduled) { notification.cancel();
JSONObject arguments;
try { JSONObject options = mergeJSONObjects(
arguments = new JSONObject(alarms.get(id).toString()); notification.getOptions().getDict(), updates);
Options options = new Options(context).parse(arguments);
Date fireDate = new Date(options.getInitialDate()); try {
isTriggered = new Date().after(fireDate); options.putOpt("updatedAt", new Date().getTime());
} catch (JSONException e) { } catch (JSONException ignore) {}
isTriggered = false;
e.printStackTrace(); return schedule(options, receiver);
}
}
return isTriggered;
} }
/** /**
* Checks whether a notification with an ID exist. * Clear local notification specified by ID.
* *
* @param id * @param id
* The notification ID to check. * The notification ID
* @return true if the notification exist
*/ */
public boolean exist(String id){ public Notification clear (int id) {
boolean exist; Notification notification = get(id);
SharedPreferences settings = getSharedPreferences();
Map<String, ?> alarms = settings.getAll(); if (notification != null) {
exist = alarms.containsKey(id); notification.clear();
return exist; }
return notification;
} }
/** /**
* Retrieves a list with all currently pending notification Ids. * Clear local notification specified by ID.
* *
* @return JSONArray with all Id-Strings * @param id
* The notification ID
*/ */
public JSONArray getScheduledIds () { public Notification cancel (int id) {
SharedPreferences settings = getSharedPreferences(); Notification notification = get(id);
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet(); if (notification != null) {
JSONArray scheduledIds = new JSONArray(); notification.cancel();
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 notification;
return scheduledIds;
} }
/**
* Clear all local notifications.
*/
public void clearAll () {
List<Notification> notifications = getAll();
for (Notification notification : notifications) {
notification.clear();
}
getNotMgr().cancelAll();
}
/** /**
* Retrieves a list with all currently triggered notification Ids. * Cancel all local notifications.
*
* @return JSONArray with all Id-Strings
*/ */
public JSONArray getTriggeredIds () { public void cancelAll () {
SharedPreferences settings = getSharedPreferences(); List<Notification> notifications = getAll();
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) { for (Notification notification : notifications) {
triggeredIds.put(id); notification.cancel();
}
} }
return triggeredIds; getNotMgr().cancelAll();
} }
/** /**
* Retrieves a list with all currently triggered or scheduled notification-Ids. * All local notifications IDs.
* @return JSONArray with all Id-Strings
*/ */
public JSONArray getAllIds (){ public List<Integer> getIds() {
JSONArray allIds = new JSONArray(); Set<String> keys = getPrefs().getAll().keySet();
SharedPreferences settings = getSharedPreferences(); ArrayList<Integer> ids = new ArrayList<Integer>();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet(); for (String key : keys) {
for (String id : alarmIds) { ids.add(Integer.parseInt(key));
allIds.put(id);
} }
return allIds;
return ids;
} }
/** /**
* Retrieves a list with all currently pending notification JSONObject. * All local notification IDs for given type.
* *
* @return JSONArray with all notification-JSONObjects * @param type
* The notification life cycle type
*/ */
public JSONArray getAll(){ public List<Integer> getIdsByType(Notification.Type type) {
SharedPreferences settings = getSharedPreferences(); List<Notification> notifications = getAll();
Map<String, ?> alarms = settings.getAll(); ArrayList<Integer> ids = new ArrayList<Integer>();
Set<String> alarmIds = alarms.keySet();
JSONArray all = new JSONArray(); for (Notification notification : notifications) {
if (notification.getType() == type) {
for (String id : alarmIds) { ids.add(notification.getId());
JSONObject arguments;
try{
arguments = new JSONObject(alarms.get(id).toString());
all.put(arguments);
} catch(JSONException jse) {
jse.printStackTrace();
} }
} }
return all;
return ids;
} }
/** /**
* Retrieves a list with all currently scheduled notification-JSONObjects. * List of local notifications with matching ID.
* *
* @return JSONArray with all notification-JSONObjects * @param ids
* Set of notification IDs
*/ */
public JSONArray getScheduled(){ public List<Notification> getByIds(List<Integer> ids) {
SharedPreferences settings = getSharedPreferences(); ArrayList<Notification> notifications = new ArrayList<Notification>();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet(); for (int id : ids) {
JSONArray scheduled = new JSONArray(); Notification notification = get(id);
for (String id : alarmIds) { if (notification != null) {
boolean isScheduled; notifications.add(notification);
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 notifications;
}
return scheduled;
/**
* List of all local notification.
*/
public List<Notification> getAll() {
return getByIds(getIds());
} }
/** /**
* Retrieves a list with all currently triggered notification-JSONObjects. * List of local notifications from given type.
* *
* @return JSONArray with all notification-JSONObjects * @param type
* The notification life cycle type
*/ */
public JSONArray getTriggered(){ public List<Notification> getByType(Notification.Type type) {
SharedPreferences settings = getSharedPreferences(); List<Notification> notifications = getAll();
Map<String, ?> alarms = settings.getAll(); ArrayList<Notification> list = new ArrayList<Notification>();
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) { for (Notification notification : notifications) {
triggered.put(arguments); if (notification.getType() == type) {
list.add(notification);
} }
} }
return triggered; return list;
} }
/** /**
* Retrieves a list with all currently pending notification JSONObjects that matches with the given String-Array * List of local notifications with matching ID from given type.
* *
* @return JSONArray with notification-JSONObjects * @param type
* The notification life cycle type
* @param ids
* Set of notification IDs
*/ */
public JSONArray getAll(JSONArray ids){ @SuppressWarnings("UnusedDeclaration")
SharedPreferences settings = getSharedPreferences(); public List<Notification> getBy(Notification.Type type, List<Integer> ids) {
Map<String, ?> alarms = settings.getAll(); ArrayList<Notification> notifications = new ArrayList<Notification>();
Set<String> alarmIds = alarms.keySet();
JSONArray all = new JSONArray(); for (int id : ids) {
for (String id : alarmIds) { Notification notification = get(id);
for(int i=0;i<ids.length();i++){
if(ids.optString(i).equals(id)){ if (notification != null && notification.isScheduled()) {
JSONObject arguments; notifications.add(notification);
try{ }
arguments = new JSONObject(alarms.get(id).toString());
all.put(arguments);
} catch(JSONException jse) {
jse.printStackTrace();
}
}
}
} }
return all;
return notifications;
} }
/** /**
* Retrieves a list with all currently scheduled notification-JSONObjects. * If a notification with an ID exists.
* *
* @return JSONArray with all notification-JSONObjects * @param id
* Notification ID
*/ */
public JSONArray getScheduled(JSONArray ids){ public boolean exist (int id) {
SharedPreferences settings = getSharedPreferences(); return get(id) != null;
Map<String, ?> alarms = settings.getAll(); }
Set<String> alarmIds = alarms.keySet();
JSONArray scheduled = new JSONArray(); /**
boolean isScheduled; * If a notification with an ID and type exists.
*
for (String id : alarmIds) { * @param id
for(int i=0;i<ids.length();i++){ * Notification ID
if(ids.optString(i).equals(id)){ * @param type
JSONObject arguments = null; * Notification type
try { */
arguments = new JSONObject(alarms.get(id).toString()); public boolean exist (int id, Notification.Type type) {
Options options = new Options(context).parse(arguments); Notification notification = get(id);
Date fireDate = new Date(options.getDate());
isScheduled = new Date().before(fireDate);
} catch (JSONException e) {
isScheduled = false;
e.printStackTrace();
}
if (isScheduled){
scheduled.put(arguments);
}
}
}
}
return notification != null && notification.getType() == type;
return scheduled;
} }
/** /**
* Retrieves a list with all currently triggered notification-JSONObjects. * List of properties from all local notifications.
*/
public List<JSONObject> getOptions() {
return getOptionsById(getIds());
}
/**
* List of properties from local notifications with matching ID.
* *
* @return JSONArray with all notification-JSONObjects * @param ids
* Set of notification IDs
*/ */
public JSONArray getTriggered(JSONArray ids){ public List<JSONObject> getOptionsById(List<Integer> ids) {
SharedPreferences settings = getSharedPreferences(); ArrayList<JSONObject> options = new ArrayList<JSONObject>();
Map<String, ?> alarms = settings.getAll();
Set<String> alarmIds = alarms.keySet(); for (int id : ids) {
JSONArray triggered = new JSONArray(); Notification notification = get(id);
Date now = new Date();
if (notification != null) {
for (String id : alarmIds) { options.add(notification.getOptions().getDict());
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; return options;
} }
//---------------Manage Shared Preferences---------------------------------------------------
/** /**
* The Local storage for the application. * List of properties from all local notifications from given type.
*
* @param type
* The notification life cycle type
*/ */
private SharedPreferences getSharedPreferences () { public List<JSONObject> getOptionsByType(Notification.Type type) {
return context.getSharedPreferences(PLUGIN_NAME, Context.MODE_PRIVATE); ArrayList<JSONObject> options = new ArrayList<JSONObject>();
List<Notification> notifications = getByType(type);
for (Notification notification : notifications) {
options.add(notification.getOptions().getDict());
}
return options;
} }
/** /**
* Persist the information of this alarm to the Android Shared Preferences. * List of properties from local notifications with matching ID from
* This will allow the application to restore the alarm upon device reboot. * given type.
* Also this is used by the cancelAll method.
* *
* @param alarmId * @param type
* The Id of the notification that must be persisted. * The notification life cycle type
* @param args * @param ids
* The assumption is that parse has been called already. * Set of notification IDs
*/ */
public void persist (String alarmId, JSONObject args) { public List<JSONObject> getOptionsBy(Notification.Type type,
Editor editor = getSharedPreferences().edit(); List<Integer> ids) {
if (alarmId != null) { ArrayList<JSONObject> options = new ArrayList<JSONObject>();
editor.putString(alarmId, args.toString()); List<Notification> notifications = getByIds(ids);
if (Build.VERSION.SDK_INT<9) {
editor.commit(); for (Notification notification : notifications) {
} else { if (notification.getType() == type) {
editor.apply(); options.add(notification.getOptions().getDict());
} }
} }
return options;
} }
/** /**
* Remove a specific alarm from the Android shared Preferences. * Get existent local notification.
* *
* @param alarmId * @param id
* The Id of the notification that must be removed. * Notification ID
*/ */
public void unpersist (String alarmId) { public Notification get(int id) {
Editor editor = getSharedPreferences().edit(); Map<String, ?> alarms = getPrefs().getAll();
String notId = Integer.toString(id);
if (alarmId != null) { JSONObject options;
editor.remove(alarmId);
if (Build.VERSION.SDK_INT<9) { if (!alarms.containsKey(notId))
editor.commit(); return null;
} else {
editor.apply();
try {
String json = alarms.get(notId).toString();
options = new JSONObject(json);
} catch (JSONException e) {
e.printStackTrace();
return null;
}
Builder builder = new Builder(context, options);
return builder.build();
}
/**
* Merge two JSON objects.
*
* @param obj1
* JSON object
* @param obj2
* JSON object with new options
*/
private JSONObject mergeJSONObjects (JSONObject obj1, JSONObject obj2) {
Iterator it = obj2.keys();
while (it.hasNext()) {
try {
String key = (String)it.next();
obj1.put(key, obj2.opt(key));
} catch (JSONException e) {
e.printStackTrace();
} }
} }
return obj1;
} }
/**
* Shared private preferences for the application.
*/
private SharedPreferences getPrefs () {
return context.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE);
}
/**
* Notification manager for the application.
*/
private NotificationManager getNotMgr () {
return (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
}
} }
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification;
import android.app.AlarmManager;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Build;
import android.support.v4.app.NotificationCompat;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Date;
/**
* Wrapper class around OS notification class. Handles basic operations
* like show, delete, cancel for a single local notification instance.
*/
public class Notification {
// Used to differ notifications by their life cycle state
public static enum Type {
SCHEDULED, TRIGGERED
}
// Default receiver to handle the trigger event
private static Class<?> defaultReceiver = TriggerReceiver.class;
// Key for private preferences
static final String PREF_KEY = "LocalNotification";
// Application context passed by constructor
private final Context context;
// Notification options passed by JS
private final Options options;
// Builder with full configuration
private final NotificationCompat.Builder builder;
// Receiver to handle the trigger event
private Class<?> receiver = defaultReceiver;
/**
* Constructor
*
* @param context
* Application context
* @param options
* Parsed notification options
* @param builder
* Pre-configured notification builder
*/
protected Notification (Context context, Options options,
NotificationCompat.Builder builder, Class<?> receiver) {
this.context = context;
this.options = options;
this.builder = builder;
this.receiver = receiver != null ? receiver : defaultReceiver;
}
/**
* Get application context.
*/
public Context getContext () {
return context;
}
/**
* Get notification options.
*/
public Options getOptions () {
return options;
}
/**
* Get notification ID.
*/
public int getId () {
return options.getIdAsInt();
}
/**
* If it's a repeating notification.
*/
public boolean isRepeating () {
return getOptions().getRepeatInterval() > 0;
}
/**
* If the notification was in the past.
*/
public boolean wasInThePast () {
return new Date().after(options.getTriggerDate());
}
/**
* If the notification is scheduled.
*/
public boolean isScheduled () {
return isRepeating() || !wasInThePast();
}
/**
* If the notification is triggered.
*/
public boolean isTriggered () {
return wasInThePast();
}
/**
* If the notification is an update.
*/
protected boolean isUpdate () {
if (!options.getDict().has("updatedAt"))
return false;
long now = new Date().getTime();
long updatedAt = options.getDict().optLong("updatedAt", now);
return (now - updatedAt) < 1000;
}
/**
* Notification type can be one of pending or scheduled.
*/
public Type getType () {
return isTriggered() ? Type.TRIGGERED : Type.SCHEDULED;
}
/**
* Schedule the local notification.
*/
public void schedule() {
long triggerTime = getNextTriggerTime();
persist();
// Intent gets called when the Notification gets fired
Intent intent = new Intent(context, receiver)
.setAction(options.getId())
.putExtra(Options.EXTRA, options.toString());
PendingIntent pi = PendingIntent.getBroadcast(
context, 0, intent, PendingIntent.FLAG_CANCEL_CURRENT);
getAlarmMgr().set(AlarmManager.RTC_WAKEUP, triggerTime, pi);
}
/**
* Re-schedule the local notification if repeating.
*/
void reschedule () {
if (isRepeating()) {
schedule();
}
}
/**
* Clear the local notification without canceling repeating alarms.
*
*/
public void clear () {
if (!isRepeating() && wasInThePast()) {
unpersist();
} else {
getNotMgr().cancel(getId());
}
}
/**
* Cancel the local notification.
*
* Create an intent that looks similar, to the one that was registered
* using schedule. Making sure the notification id in the action is the
* same. Now we can search for such an intent using the 'getService'
* method and cancel it.
*/
public void cancel() {
Intent intent = new Intent(context, receiver)
.setAction(options.getId());
PendingIntent pi = PendingIntent.
getBroadcast(context, 0, intent, 0);
getAlarmMgr().cancel(pi);
getNotMgr().cancel(options.getIdAsInt());
unpersist();
}
/**
* Present the local notification to user.
*/
public void show () {
// TODO Show dialog when in foreground
showNotification();
}
/**
* Show as local notification when in background.
*/
@SuppressWarnings("deprecation")
private void showNotification () {
int id = getOptions().getIdAsInt();
if (Build.VERSION.SDK_INT <= 15) {
// Notification for HoneyComb to ICS
getNotMgr().notify(id, builder.getNotification());
} else {
// Notification for Jellybean and above
getNotMgr().notify(id, builder.build());
}
}
/**
* Show as modal dialog when in foreground.
*/
private void showDialog () {
// TODO
}
/**
* Next trigger time.
*/
public long getNextTriggerTime() {
long triggerTime = options.getTriggerTime();
if (!isRepeating() || !isTriggered())
return triggerTime;
long interval = options.getRepeatInterval();
int triggerCount = getTriggerCountSinceSchedule();
return triggerTime + (triggerCount + 1) * interval;
}
/**
* Count of triggers since schedule.
*/
public int getTriggerCountSinceSchedule() {
long now = System.currentTimeMillis();
long initTriggerTime = options.getTriggerTime();
if (!wasInThePast())
return 0;
if (!isRepeating())
return 1;
return (int) ((now - initTriggerTime) / options.getRepeatInterval());
}
/**
* Encode options to JSON.
*/
public String toString() {
JSONObject dict = options.getDict();
JSONObject json = new JSONObject();
try {
json = new JSONObject(dict.toString());
} catch (JSONException e) {
e.printStackTrace();
}
json.remove("updatedAt");
json.remove("soundUri");
json.remove("iconUri");
return json.toString();
}
/**
* Persist the information of this notification to the Android Shared
* Preferences. This will allow the application to restore the notification
* upon device reboot, app restart, retrieve notifications, aso.
*/
private void persist () {
SharedPreferences.Editor editor = getPrefs().edit();
editor.putString(options.getId(), options.toString());
if (Build.VERSION.SDK_INT < 9) {
editor.commit();
} else {
editor.apply();
}
}
/**
* Remove the notification from the Android shared Preferences.
*/
private void unpersist () {
SharedPreferences.Editor editor = getPrefs().edit();
editor.remove(options.getId());
if (Build.VERSION.SDK_INT < 9) {
editor.commit();
} else {
editor.apply();
}
}
/**
* Shared private preferences for the application.
*/
private SharedPreferences getPrefs () {
return context.getSharedPreferences(PREF_KEY, Context.MODE_PRIVATE);
}
/**
* Notification manager for the application.
*/
private NotificationManager getNotMgr () {
return (NotificationManager) context
.getSystemService(Context.NOTIFICATION_SERVICE);
}
/**
* Alarm manager for the application.
*/
private AlarmManager getAlarmMgr () {
return (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
}
/**
* Set default receiver to handle the trigger event.
*
* @param receiver
* broadcast receiver
*/
public static void setDefaultTriggerReceiver (Class<?> receiver) {
defaultReceiver = receiver;
}
}
/*
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.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;
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 Builder 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);
return 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);
}
}
/*
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;
import android.support.v4.app.NotificationCompat.Builder;
import android.util.Log;
import android.widget.Toast;
/**
* 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) {
Log.e("NotificationWrapper", "Update failed. No Notification available for the given id: " + id );
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) {
unpersist(notificationId);
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();
}
/**
* Shows the notification
*/
@SuppressWarnings("deprecation")
public void showNotification (Builder notification, Options options) {
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(Options options){
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();
}
//---------------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"));
}
if(!updates.isNull("date")){
arguments.put("date", updates.get("date"));
}
if(!updates.isNull("repeat")){
arguments.put("repeat", updates.get("repeat"));
}
if(!updates.isNull("json")){
arguments.put("json", updates.get("json"));
}
if(!updates.isNull("autoCancel")){
arguments.put("autoCancel", updates.get("autoCancel"));
}
if(!updates.isNull("ongoing")){
arguments.put("ongoing", updates.get("ongoing"));
}
} 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;
}
}
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*/ *
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification; package de.appplant.cordova.plugin.notification;
import java.io.IOException;
import java.io.InputStream;
import java.util.Calendar;
import java.util.Date; import java.util.Date;
import org.json.JSONException; import org.json.JSONException;
...@@ -31,303 +30,268 @@ import org.json.JSONObject; ...@@ -31,303 +30,268 @@ import org.json.JSONObject;
import android.app.AlarmManager; import android.app.AlarmManager;
import android.content.Context; import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap; import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri; import android.net.Uri;
/** /**
* Class that helps to store the options that can be specified per alarm. * Wrapper around the JSON object passed through JS which contains all
* possible option values. Class provides simple readers and more advanced
* methods to convert independent values into platform specific values.
*/ */
public class Options { public class Options {
// Key name for bundled extras
static final String EXTRA = "NOTIFICATION_OPTIONS";
// The original JSON object
private JSONObject options = new JSONObject(); private JSONObject options = new JSONObject();
private String packageName = null;
private long interval = 0;
private Context context;
// Repeat interval
private long interval = 0;
// Application context
private final Context context;
// Asset util instance
private final AssetUtil assets;
/**
* Constructor
*
* @param context
* Application context
*/
public Options(Context context){ public Options(Context context){
this.context= context; this.context = context;
this.packageName = context.getPackageName(); this.assets = AssetUtil.getInstance(context);
} }
/** /**
* Parses the given properties * Parse given JSON properties.
*
* @param options
* JSON properties
*/ */
public Options parse (JSONObject options) { public Options parse (JSONObject options) {
String repeat = options.optString("repeat");
this.options = options; this.options = options;
if (repeat.equalsIgnoreCase("secondly")) { parseInterval();
parseAssets();
return this;
}
/**
* Parse repeat interval.
*/
private void parseInterval() {
String every = options.optString("every").toLowerCase();
if (every.isEmpty()) {
interval = 0;
} else
if (every.equals("second")) {
interval = 1000; interval = 1000;
} if (repeat.equalsIgnoreCase("minutely")) { } else
if (every.equals("minute")) {
interval = AlarmManager.INTERVAL_FIFTEEN_MINUTES / 15; interval = AlarmManager.INTERVAL_FIFTEEN_MINUTES / 15;
} if (repeat.equalsIgnoreCase("hourly")) { } else
if (every.equals("hour")) {
interval = AlarmManager.INTERVAL_HOUR; interval = AlarmManager.INTERVAL_HOUR;
} if (repeat.equalsIgnoreCase("daily")) { } else
if (every.equals("day")) {
interval = AlarmManager.INTERVAL_DAY; interval = AlarmManager.INTERVAL_DAY;
} else if (repeat.equalsIgnoreCase("weekly")) { } else
interval = AlarmManager.INTERVAL_DAY*7; if (every.equals("week")) {
} else if (repeat.equalsIgnoreCase("monthly")) { interval = AlarmManager.INTERVAL_DAY * 7;
interval = AlarmManager.INTERVAL_DAY*31; // 31 days } else
} else if (repeat.equalsIgnoreCase("yearly")) { if (every.equals("month")) {
interval = AlarmManager.INTERVAL_DAY*365; interval = AlarmManager.INTERVAL_DAY * 31;
} else
if (every.equals("year")) {
interval = AlarmManager.INTERVAL_DAY * 365;
} else { } else {
try { try {
interval = Integer.parseInt(repeat) * 60000; interval = Integer.parseInt(every) * 60000;
} catch (Exception e) {}; } catch (Exception e) {
e.printStackTrace();
}
} }
return this;
} }
/** /**
* Set new time according to interval * Parse asset URIs.
*/ */
public Options moveDate () { private void parseAssets() {
try {
options.put("date", (getDate() + interval) / 1000);
} catch (JSONException e) {}
return this; if (options.has("iconUri"))
} return;
/**
* Returns options as JSON object
*/
public JSONObject getJSONObject() {
return options;
}
/** Uri iconUri = assets.parse(options.optString("icon", "icon"));
* Returns time in milliseconds when notification is scheduled to fire Uri soundUri = assets.parseSound(options.optString("sound", null));
*/
public long getDate() { try {
return options.optLong("date", 0) * 1000; options.put("iconUri", iconUri.toString());
} options.put("soundUri", soundUri.toString());
} catch (JSONException e) {
/** e.printStackTrace();
* Returns time in milliseconds when the notification was scheduled first }
*/
public long getInitialDate() {
return options.optLong("initialDate", 0);
} }
/** /**
* Returns time as calender * Application context.
*/ */
public Calendar getCalendar () { public Context getContext () {
Calendar calendar = Calendar.getInstance(); return context;
calendar.setTime(new Date(getDate()));
return calendar;
} }
/** /**
* Returns the notification's message * Wrapped JSON object.
*/ */
public String getMessage () { JSONObject getDict () {
return options.optString("message", ""); return options;
} }
/** /**
* Returns the notification's title * Text for the local notification.
*/ */
public String getTitle () { public String getText() {
return options.optString("title", ""); return options.optString("text", "");
} }
/** /**
* Returns the path of the notification's sound file * Repeat interval (day, week, month, year, aso.)
*/ */
public Uri getSound () { public long getRepeatInterval() {
Uri soundUri = null; return interval;
try{
soundUri = Uri.parse(options.optString("soundUri"));
return soundUri;
} catch (Exception e){
e.printStackTrace();
}
return null;
} }
/** /**
* Returns the icon's ID * Badge number for the local notification.
*/ */
public Bitmap getIcon () { public int getBadgeNumber() {
String icon = options.optString("icon", "icon"); return options.optInt("badge", 0);
Bitmap bmp = null;
Uri iconUri = null;
try{
iconUri = Uri.parse(options.optString("iconUri"));
bmp = getIconFromUri(iconUri);
} catch (Exception e){
bmp = getIconFromRes(icon);
}
return bmp;
} }
/** /**
* Returns the small icon's ID * Android only ongoing flag for local notifications.
*/ */
public int getSmallIcon () { public Boolean isOngoing() {
int resId = 0; return options.optBoolean("ongoing", false);
String iconName = options.optString("smallIcon", "");
resId = getIconValue(packageName, iconName);
if (resId == 0) {
resId = getIconValue("android", iconName);
}
if (resId == 0) {
resId = getIconValue(packageName, "icon");
}
return options.optInt("smallIcon", resId);
} }
/** /**
* Returns notification repetition interval (daily, weekly, monthly, yearly) * Trigger date in milliseconds.
*/ */
public long getInterval () { public long getTriggerTime() {
return interval; return options.optLong("at", 0) * 1000;
} }
/** /**
* Returns notification badge number * Trigger date.
*/ */
public int getBadge () { public Date getTriggerDate() {
return options.optInt("badge", 0); return new Date(getTriggerTime());
} }
/** /**
* Returns PluginResults' callback ID * ID for the local notification.
*/ */
public String getId () { public String getId() {
return options.optString("id", "0"); return options.optString("id", "0");
} }
/** /**
* Returns whether notification is cancelled automatically when clicked. * ID for the local notification.
*/ */
public Boolean getAutoCancel () { public int getIdAsInt() {
return options.optBoolean("autoCancel", false); try {
return Integer.parseInt(getId());
} catch (Exception ignore) {
return 0;
}
} }
/** /**
* Returns whether the notification is ongoing (uncancellable). Android only. * Title for the local notification.
*/ */
public Boolean getOngoing () { public String getTitle() {
return options.optBoolean("ongoing", false); String title = options.optString("title", "");
}
/** if (title.isEmpty()) {
* Returns additional data as string title = context.getApplicationInfo().loadLabel(
*/ context.getPackageManager()).toString();
public String getJSON () { }
return options.optString("json", "");
return title;
} }
/** /**
* @return * @return
* The notification color for LED * The notification color for LED
*/ */
public int getColor () { public int getLedColor() {
String hexColor = options.optString("led", "000000"); String hex = options.optString("led", "000000");
int aRGB = Integer.parseInt(hexColor,16); int aRGB = Integer.parseInt(hex,16);
aRGB += 0xFF000000; aRGB += 0xFF000000;
return aRGB; return aRGB;
} }
/**
* Shows the behavior of notifications when the application is in foreground
*
*/
public boolean getForegroundMode(){
return options.optBoolean("foregroundMode",false);
}
/** /**
* Returns numerical icon Value * Sound file path for the local notification.
*
* @param {String} className
* @param {String} iconName
*/ */
private int getIconValue (String className, String iconName) { public Uri getSoundUri() {
int icon = 0; Uri uri = null;
try { try{
Class<?> klass = Class.forName(className + ".R$drawable"); uri = Uri.parse(options.optString("soundUri"));
} catch (Exception e){
icon = (Integer) klass.getDeclaredField(iconName).get(Integer.class); e.printStackTrace();
} catch (Exception e) {} }
return icon; return uri;
} }
/** /**
* Converts an resource to Bitmap. * Icon bitmap for the local notification.
*
* @param icon
* The resource name
* @return
* The corresponding bitmap
*/ */
private Bitmap getIconFromRes (String icon) { public Bitmap getIconBitmap() {
Resources res = context.getResources(); String icon = options.optString("icon", "icon");
int iconId = 0; Bitmap bmp;
iconId = getIconValue(packageName, icon);
if (iconId == 0) {
iconId = getIconValue("android", icon);
}
if (iconId == 0) { try{
iconId = android.R.drawable.ic_menu_info_details; Uri uri = Uri.parse(options.optString("iconUri"));
bmp = assets.getIconFromUri(uri);
} catch (Exception e){
bmp = assets.getIconFromDrawable(icon);
} }
Bitmap bmp = BitmapFactory.decodeResource(res, iconId);
return bmp; return bmp;
} }
/** /**
* Converts an Image URI to Bitmap. * Small icon resource ID for the local notification.
*
* @param src
* The internal image URI
* @return
* The corresponding bitmap
*/ */
private Bitmap getIconFromUri (Uri uri) throws IOException { public int getSmallIcon () {
Bitmap bmp = null; String icon = options.optString("smallIcon", "");
InputStream input = context.getContentResolver().openInputStream(uri);
bmp = BitmapFactory.decodeStream(input);
return bmp; int resId = assets.getResIdForDrawable(icon);
if (resId == 0) {
resId = android.R.drawable.screen_background_dark;
}
return resId;
} }
/** /**
* Function to set the value of "initialDate" in the JSONArray * JSON object as string.
*/ */
public void setInitDate(){ public String toString() {
long initialDate = options.optLong("date", 0) * 1000; return options.toString();
try {
options.put("initialDate", initialDate);
} catch (JSONException e) {
e.printStackTrace();
}
} }
} }
/*
* Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
* @APPPLANT_LICENSE_HEADER_START@
*
* This file contains Original Code and/or Modifications of Original Code
* as defined in and that are subject to the Apache License
* Version 2.0 (the 'License'). You may not use this file except in
* compliance with the License. Please obtain a copy of the License at
* http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
*
* The Original Code and all software distributed under the License are
* distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
* EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
* INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
* Please see the License for the specific language governing rights and
* limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/
package de.appplant.cordova.plugin.notification;
/**
* The alarm receiver is triggered when a scheduled alarm is fired. This class
* reads the information in the intent and displays this information in the
* Android notification bar. The notification uses the default notification
* sound and it vibrates the phone.
*/
public class TriggerReceiver extends AbstractTriggerReceiver {
/**
* Called when a local notification was triggered. Does present the local
* notification and re-schedule the alarm if necessary.
*
* @param notification
* Wrapper around the local notification
* @param updated
* If an update has triggered or the original
*/
@Override
public void onTrigger (Notification notification, boolean updated) {
if (notification.isRepeating()) {
notification.reschedule();
}
notification.show();
}
/**
* Build notification specified by options.
*
* @param builder
* Notification builder
*/
@Override
public Notification buildNotification (Builder builder) {
return builder.build();
}
}
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import <Foundation/Foundation.h> #import <Foundation/Foundation.h>
...@@ -32,20 +34,24 @@ ...@@ -32,20 +34,24 @@
// Register permission to show notifications // Register permission to show notifications
- (void) registerPermission:(CDVInvokedUrlCommand*)command; - (void) registerPermission:(CDVInvokedUrlCommand*)command;
// Schedule a new notification // Schedule set of notifications
- (void) add:(CDVInvokedUrlCommand*)command; - (void) schedule:(CDVInvokedUrlCommand*)command;
// Update a notification // Update set of notifications
- (void) update:(CDVInvokedUrlCommand*)command; - (void) update:(CDVInvokedUrlCommand*)command;
// Cancel a given notification // Cancel set of notifications
- (void) cancel:(CDVInvokedUrlCommand*)command; - (void) cancel:(CDVInvokedUrlCommand*)command;
// Cancel all currently scheduled notifications // Cancel all notifications
- (void) cancelAll:(CDVInvokedUrlCommand*)command; - (void) cancelAll:(CDVInvokedUrlCommand*)command;
// Clear set of notifications
- (void) clear:(CDVInvokedUrlCommand*)command;
// Clear all notifications
- (void) clearAll:(CDVInvokedUrlCommand*)command;
// If a notification with an ID exists // If a notification with an ID is present
- (void) exist:(CDVInvokedUrlCommand*)command; - (void) isPresent:(CDVInvokedUrlCommand*)command;
// If a notification with an ID was scheduled // If a notification with an ID is scheduled
- (void) isScheduled:(CDVInvokedUrlCommand*)command; - (void) isScheduled:(CDVInvokedUrlCommand*)command;
// If a notification with an ID was triggered // If a notification with an ID is triggered
- (void) isTriggered:(CDVInvokedUrlCommand*)command; - (void) isTriggered:(CDVInvokedUrlCommand*)command;
// List all ids from all local notifications // List all ids from all local notifications
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "APPLocalNotification.h" #import "APPLocalNotification.h"
...@@ -67,7 +69,7 @@ ...@@ -67,7 +69,7 @@
* @param properties * @param properties
* A dict of properties for each notification * A dict of properties for each notification
*/ */
- (void) add:(CDVInvokedUrlCommand*)command - (void) schedule:(CDVInvokedUrlCommand*)command
{ {
NSArray* notifications = command.arguments; NSArray* notifications = command.arguments;
...@@ -79,7 +81,7 @@ ...@@ -79,7 +81,7 @@
initWithOptions:options]; initWithOptions:options];
[self scheduleLocalNotification:[notification copy]]; [self scheduleLocalNotification:[notification copy]];
[self fireEvent:@"add" localNotification:notification]; [self fireEvent:@"schedule" notification:notification];
if (notifications.count > 1) { if (notifications.count > 1) {
[NSThread sleepForTimeInterval:0.01]; [NSThread sleepForTimeInterval:0.01];
...@@ -105,8 +107,7 @@ ...@@ -105,8 +107,7 @@
NSString* id = [options objectForKey:@"id"]; NSString* id = [options objectForKey:@"id"];
UILocalNotification* notification; UILocalNotification* notification;
notification = [[UIApplication sharedApplication] notification = [self.app localNotificationWithId:id];
scheduledLocalNotificationWithId:id];
if (!notification) if (!notification)
continue; continue;
...@@ -114,6 +115,8 @@ ...@@ -114,6 +115,8 @@
[self updateLocalNotification:[notification copy] [self updateLocalNotification:[notification copy]
withOptions:options]; withOptions:options];
[self fireEvent:@"update" notification:notification];
if (notifications.count > 1) { if (notifications.count > 1) {
[NSThread sleepForTimeInterval:0.01]; [NSThread sleepForTimeInterval:0.01];
} }
...@@ -135,14 +138,13 @@ ...@@ -135,14 +138,13 @@
for (NSString* id in command.arguments) { for (NSString* id in command.arguments) {
UILocalNotification* notification; UILocalNotification* notification;
notification = [[UIApplication sharedApplication] notification = [self.app localNotificationWithId:id];
scheduledLocalNotificationWithId:id];
if (!notification) if (!notification)
continue; continue;
[self cancelLocalNotification:notification]; [self.app cancelLocalNotification:notification];
[self fireEvent:@"cancel" localNotification:notification]; [self fireEvent:@"cancel" notification:notification];
} }
[self execCallback:command]; [self execCallback:command];
...@@ -150,7 +152,7 @@ ...@@ -150,7 +152,7 @@
} }
/** /**
* Cancel all currently scheduled notifications. * Cancel all local notifications.
*/ */
- (void) cancelAll:(CDVInvokedUrlCommand*)command - (void) cancelAll:(CDVInvokedUrlCommand*)command
{ {
...@@ -162,34 +164,54 @@ ...@@ -162,34 +164,54 @@
} }
/** /**
* If a notification by ID exists. * Clear a set of notifications.
* *
* @param id * @param ids
* The ID of the notification * The IDs of the notifications
*/ */
- (void) exist:(CDVInvokedUrlCommand *)command - (void) clear:(CDVInvokedUrlCommand*)command
{ {
[self.commandDelegate runInBackground:^{ [self.commandDelegate runInBackground:^{
NSString* id = [[command arguments] for (NSString* id in command.arguments) {
objectAtIndex:0]; UILocalNotification* notification;
CDVPluginResult* result; notification = [self.app localNotificationWithId:id];
UILocalNotification* notification;
notification = [[UIApplication sharedApplication] if (!notification)
localNotificationWithId:id]; continue;
bool exists = notification != NULL; [self.app clearLocalNotification:notification];
[self fireEvent:@"clear" notification:notification];
}
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK [self execCallback:command];
messageAsBool:exists]; }];
}
[self.commandDelegate sendPluginResult:result /**
callbackId:command.callbackId]; * Clear all local notifications.
*/
- (void) clearAll:(CDVInvokedUrlCommand*)command
{
[self.commandDelegate runInBackground:^{
[self clearAllLocalNotifications];
[self fireEvent:@"clearall"];
[self execCallback:command];
}]; }];
} }
/** /**
* If a notification by ID is present.
*
* @param id
* The ID of the notification
*/
- (void) isPresent:(CDVInvokedUrlCommand *)command
{
[self isPresent:command type:NotifcationTypeAll];
}
/**
* If a notification by ID is scheduled. * If a notification by ID is scheduled.
* *
* @param id * @param id
...@@ -197,48 +219,43 @@ ...@@ -197,48 +219,43 @@
*/ */
- (void) isScheduled:(CDVInvokedUrlCommand*)command - (void) isScheduled:(CDVInvokedUrlCommand*)command
{ {
[self.commandDelegate runInBackground:^{ [self isPresent:command type:NotifcationTypeScheduled];
NSString* id = [[command arguments]
objectAtIndex:0];
CDVPluginResult* result;
UILocalNotification* notification;
notification = [[UIApplication sharedApplication]
scheduledLocalNotificationWithId:id];
bool isScheduled = notification != NULL;
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsBool:isScheduled];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
} }
/** /**
* Check if a notification with an ID was triggered. * Check if a notification with an ID is triggered.
* *
* @param id * @param id
* The ID of the notification * The ID of the notification
*/ */
- (void) isTriggered:(CDVInvokedUrlCommand*)command - (void) isTriggered:(CDVInvokedUrlCommand*)command
{ {
[self isPresent:command type:NotifcationTypeTriggered];
}
/**
* Check if a notification with an ID exists.
*
* @param type
* The notification life cycle type
*/
- (void) isPresent:(CDVInvokedUrlCommand*)command
type:(APPLocalNotificationType)type;
{
[self.commandDelegate runInBackground:^{ [self.commandDelegate runInBackground:^{
NSString* id = [[command arguments] NSString* id = [command argumentAtIndex:0];
objectAtIndex:0]; BOOL exist;
CDVPluginResult* result; CDVPluginResult* result;
UILocalNotification* notification;
notification = [[UIApplication sharedApplication] if (type == NotifcationTypeAll) {
triggeredLocalNotificationWithId:id]; exist = [self.app localNotificationExist:id];
} else {
bool isTriggered = notification != NULL; exist = [self.app localNotificationExist:id type:type];
}
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsBool:isTriggered]; messageAsBool:exist];
[self.commandDelegate sendPluginResult:result [self.commandDelegate sendPluginResult:result
callbackId:command.callbackId]; callbackId:command.callbackId];
...@@ -250,19 +267,7 @@ ...@@ -250,19 +267,7 @@
*/ */
- (void) getAllIds:(CDVInvokedUrlCommand*)command - (void) getAllIds:(CDVInvokedUrlCommand*)command
{ {
[self.commandDelegate runInBackground:^{ [self getIds:command byType:NotifcationTypeAll];
CDVPluginResult* result;
NSArray* notIds;
notIds = [[UIApplication sharedApplication]
localNotificationIds];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:notIds];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
} }
/** /**
...@@ -270,19 +275,7 @@ ...@@ -270,19 +275,7 @@
*/ */
- (void) getScheduledIds:(CDVInvokedUrlCommand*)command - (void) getScheduledIds:(CDVInvokedUrlCommand*)command
{ {
[self.commandDelegate runInBackground:^{ [self getIds:command byType:NotifcationTypeScheduled];
CDVPluginResult* result;
NSArray* scheduledIds;
scheduledIds = [[UIApplication sharedApplication]
scheduledLocalNotificationIds];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:scheduledIds];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
} }
/** /**
...@@ -290,44 +283,32 @@ ...@@ -290,44 +283,32 @@
*/ */
- (void) getTriggeredIds:(CDVInvokedUrlCommand*)command - (void) getTriggeredIds:(CDVInvokedUrlCommand*)command
{ {
[self.commandDelegate runInBackground:^{ [self getIds:command byType:NotifcationTypeTriggered];
CDVPluginResult* result;
NSArray* triggeredIds;
triggeredIds = [[UIApplication sharedApplication]
triggeredLocalNotificationIds];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:triggeredIds];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
} }
/** /**
* Property list for given local notifications. * List of ids for given local notifications.
* *
* @param type
* Notification life cycle type
* @param ids * @param ids
* The IDs of the notifications * The IDs of the notifications
*/ */
- (void) getAll:(CDVInvokedUrlCommand*)command - (void) getIds:(CDVInvokedUrlCommand*)command
byType:(APPLocalNotificationType)type;
{ {
[self.commandDelegate runInBackground:^{ [self.commandDelegate runInBackground:^{
NSArray* ids = command.arguments;
NSArray* notifications;
CDVPluginResult* result; CDVPluginResult* result;
NSArray* ids;
if (ids.count == 0) { if (type == NotifcationTypeAll) {
notifications = [[UIApplication sharedApplication] ids = [self.app localNotificationIds];
localNotificationOptions];
} else { } else {
notifications = [[UIApplication sharedApplication] ids = [self.app localNotificationIdsByType:type];
localNotificationOptions:ids];
} }
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:notifications]; messageAsArray:ids];
[self.commandDelegate sendPluginResult:result [self.commandDelegate sendPluginResult:result
callbackId:command.callbackId]; callbackId:command.callbackId];
...@@ -335,6 +316,17 @@ ...@@ -335,6 +316,17 @@
} }
/** /**
* Property list for given local notifications.
*
* @param ids
* The IDs of the notifications
*/
- (void) getAll:(CDVInvokedUrlCommand*)command
{
[self getOptions:command byType:NotifcationTypeAll];
}
/**
* Property list for given scheduled notifications. * Property list for given scheduled notifications.
* *
* @param ids * @param ids
...@@ -342,25 +334,7 @@ ...@@ -342,25 +334,7 @@
*/ */
- (void) getScheduled:(CDVInvokedUrlCommand*)command - (void) getScheduled:(CDVInvokedUrlCommand*)command
{ {
[self.commandDelegate runInBackground:^{ [self getOptions:command byType:NotifcationTypeScheduled];
NSArray* ids = command.arguments;
NSArray* notifications;
CDVPluginResult* result;
if (ids.count == 0) {
notifications = [[UIApplication sharedApplication]
scheduledLocalNotificationOptions];
} else {
notifications = [[UIApplication sharedApplication]
scheduledLocalNotificationOptions:ids];
}
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsArray:notifications];
[self.commandDelegate sendPluginResult:result
callbackId:command.callbackId];
}];
} }
/** /**
...@@ -371,17 +345,37 @@ ...@@ -371,17 +345,37 @@
*/ */
- (void) getTriggered:(CDVInvokedUrlCommand *)command - (void) getTriggered:(CDVInvokedUrlCommand *)command
{ {
[self getOptions:command byType:NotifcationTypeTriggered];
}
/**
* Property list for given triggered notifications.
*
* @param type
* Notification life cycle type
* @param ids
* The IDs of the notifications
*/
- (void) getOptions:(CDVInvokedUrlCommand*)command
byType:(APPLocalNotificationType)type;
{
[self.commandDelegate runInBackground:^{ [self.commandDelegate runInBackground:^{
NSArray* ids = command.arguments; NSArray* ids = command.arguments;
NSArray* notifications; NSArray* notifications;
CDVPluginResult* result; CDVPluginResult* result;
if (ids.count == 0) { if (type == NotifcationTypeAll && ids.count == 0) {
notifications = [[UIApplication sharedApplication] notifications = [self.app localNotificationOptions];
triggeredLocalNotificationOptions]; }
} else { else if (type == NotifcationTypeAll) {
notifications = [[UIApplication sharedApplication] notifications = [self.app localNotificationOptionsById:ids];
triggeredLocalNotificationOptions:ids]; }
else if (ids.count == 0) {
notifications = [self.app localNotificationOptionsByType:type];
}
else {
notifications = [self.app localNotificationOptionsByType:type
andId:ids];
} }
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
...@@ -402,8 +396,7 @@ ...@@ -402,8 +396,7 @@
CDVPluginResult* result; CDVPluginResult* result;
BOOL hasPermission; BOOL hasPermission;
hasPermission = [[UIApplication sharedApplication] hasPermission = [self.app hasPermissionToScheduleLocalNotifications];
hasPermissionToScheduleLocalNotifications];
result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK result = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
messageAsBool:hasPermission]; messageAsBool:hasPermission];
...@@ -423,8 +416,7 @@ ...@@ -423,8 +416,7 @@
_command = command; _command = command;
[self.commandDelegate runInBackground:^{ [self.commandDelegate runInBackground:^{
[[UIApplication sharedApplication] [self.app registerPermissionToScheduleLocalNotifications];
registerPermissionToScheduleLocalNotifications];
}]; }];
#else #else
[self hasPermission:command]; [self hasPermission:command];
...@@ -440,9 +432,7 @@ ...@@ -440,9 +432,7 @@
- (void) scheduleLocalNotification:(UILocalNotification*)notification - (void) scheduleLocalNotification:(UILocalNotification*)notification
{ {
[self cancelForerunnerLocalNotification:notification]; [self cancelForerunnerLocalNotification:notification];
[self.app scheduleLocalNotification:notification];
[[UIApplication sharedApplication]
scheduleLocalNotification:notification];
} }
/** /**
...@@ -460,31 +450,24 @@ ...@@ -460,31 +450,24 @@
initWithOptions:options]; initWithOptions:options];
[self scheduleLocalNotification:notification]; [self scheduleLocalNotification:notification];
} }
/** /**
* Cancel the local notification. * Cancel all local notifications.
*/ */
- (void) cancelLocalNotification:(UILocalNotification*)notification - (void) cancelAllLocalNotifications
{ {
[[UIApplication sharedApplication] [self.app cancelAllLocalNotifications];
cancelLocalNotification:notification]; [self.app setApplicationIconBadgeNumber:0];
[UIApplication sharedApplication]
.applicationIconBadgeNumber -= 1;
} }
/** /**
* Cancel all currently scheduled notifications. * Clear all local notifications.
*/ */
- (void) cancelAllLocalNotifications - (void) clearAllLocalNotifications
{ {
[[UIApplication sharedApplication] [self.app clearAllLocalNotifications];
cancelAllLocalNotifications]; [self.app setApplicationIconBadgeNumber:0];
[[UIApplication sharedApplication]
setApplicationIconBadgeNumber:0];
} }
/** /**
...@@ -495,13 +478,12 @@ ...@@ -495,13 +478,12 @@
NSString* id = notification.options.id; NSString* id = notification.options.id;
UILocalNotification* forerunner; UILocalNotification* forerunner;
forerunner = [[UIApplication sharedApplication] forerunner = [self.app localNotificationWithId:id];
scheduledLocalNotificationWithId:id];
if (!forerunner) if (!forerunner)
return; return;
[self cancelLocalNotification:forerunner]; [self.app cancelLocalNotification:forerunner];
} }
/** /**
...@@ -512,16 +494,16 @@ ...@@ -512,16 +494,16 @@
{ {
NSArray* notifications; NSArray* notifications;
notifications = [[UIApplication sharedApplication] notifications = [self.app scheduledLocalNotifications];
scheduledLocalNotifications];
for (UILocalNotification* notification in notifications) for (UILocalNotification* notification in notifications)
{ {
if (notification && [notification isRepeating] if (notification && [notification isRepeating]
&& notification.timeIntervalSinceFireDate > seconds) && notification.timeIntervalSinceFireDate > seconds)
{ {
[self cancelLocalNotification:notification]; [self.app cancelLocalNotification:notification];
[self fireEvent:@"cancel" localNotification:notification];
[self fireEvent:@"cancel" notification:notification];
} }
} }
} }
...@@ -540,21 +522,29 @@ ...@@ -540,21 +522,29 @@
if ([notification wasUpdated]) if ([notification wasUpdated])
return; return;
BOOL autoCancel = notification.options.autoCancel; NSTimeInterval timeInterval = [notification timeIntervalSinceLastTrigger];
NSTimeInterval timeInterval = [notification timeIntervalSinceFireDate];
NSString* event = (timeInterval <= 1 && deviceready) ? @"trigger" : @"click"; NSString* event = (timeInterval <= 1 && deviceready) ? @"trigger" : @"click";
if ([event isEqualToString:@"click"]) { [self fireEvent:event notification:notification];
[UIApplication sharedApplication]
.applicationIconBadgeNumber -= 1; if ([event isEqualToString:@"click"] && ![notification isRepeating])
{
[self.app cancelLocalNotification:notification];
[self fireEvent:@"cancel" notification:notification];
return;
} }
[self fireEvent:event localNotification:notification]; if ([event isEqualToString:@"click"])
return;
timeInterval = [notification timeIntervalSinceFireDate];
if (autoCancel && [event isEqualToString:@"click"]) { if (timeInterval > 1 && [notification isRepeating])
[self cancelLocalNotification:notification]; {
[self fireEvent:@"cancel" localNotification:notification]; [self fireEvent:@"fireUpdateEvent" notification:notification];
return;
} }
} }
...@@ -639,8 +629,7 @@ ...@@ -639,8 +629,7 @@
*/ */
- (NSString*) applicationState - (NSString*) applicationState
{ {
UIApplicationState state = [[UIApplication sharedApplication] UIApplicationState state = [self.app applicationState];
applicationState];
bool isActive = state == UIApplicationStateActive; bool isActive = state == UIApplicationStateActive;
...@@ -660,37 +649,40 @@ ...@@ -660,37 +649,40 @@
} }
/** /**
* Short hand for shared application instance.
*/
- (UIApplication*) app
{
return [UIApplication sharedApplication];
}
/**
* Fire general event. * Fire general event.
*/ */
- (void) fireEvent:(NSString*)event - (void) fireEvent:(NSString*)event
{ {
[self fireEvent:event localNotification:NULL]; [self fireEvent:event notification:NULL];
} }
/** /**
* Fire event for local notification. * Fire event for local notification.
*/ */
- (void) fireEvent:(NSString*)event localNotification:(UILocalNotification*)notification - (void) fireEvent:(NSString*)event notification:(UILocalNotification*)notification
{ {
NSString* js; NSString* js;
NSString* params = [NSString stringWithFormat: NSString* params = [NSString stringWithFormat:
@"\"%@\"", self.applicationState]; @"\"%@\"", self.applicationState];
if (notification) { if (notification) {
NSString* id = notification.options.id;
NSString* json = notification.options.json;
NSString* args = [notification encodeToJSON]; NSString* args = [notification encodeToJSON];
json = [json stringByReplacingOccurrencesOfString:@"'"
withString:@"\\\\\\'"];
params = [NSString stringWithFormat: params = [NSString stringWithFormat:
@"\"%@\",\"%@\",\\'%@\\',JSON.parse(\\'%@\\')", @"%@,'%@'",
id, self.applicationState, json, args]; args, self.applicationState];
} }
js = [NSString stringWithFormat: js = [NSString stringWithFormat:
@"setTimeout('cordova.plugins.notification.local.on%@(%@)',0)", @"cordova.plugins.notification.local.fireEvent('%@', %@)",
event, params]; event, params];
if (deviceready) { if (deviceready) {
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
@interface APPLocalNotificationOptions : NSObject @interface APPLocalNotificationOptions : NSObject
...@@ -24,8 +26,6 @@ ...@@ -24,8 +26,6 @@
- (id) initWithDict:(NSDictionary*)dict; - (id) initWithDict:(NSDictionary*)dict;
@property (readonly, getter=id) NSString* id; @property (readonly, getter=id) NSString* id;
@property (readonly, getter=autoCancel) BOOL autoCancel;
@property (readonly, getter=json) NSString* json;
@property (readonly, getter=badgeNumber) NSInteger badgeNumber; @property (readonly, getter=badgeNumber) NSInteger badgeNumber;
@property (readonly, getter=alertBody) NSString* alertBody; @property (readonly, getter=alertBody) NSString* alertBody;
@property (readonly, getter=soundName) NSString* soundName; @property (readonly, getter=soundName) NSString* soundName;
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "APPLocalNotificationOptions.h" #import "APPLocalNotificationOptions.h"
#import <Cordova/CDVAvailability.h>
// Default sound ressource path
NSString* const DEFAULT_SOUND = @"res://platform_default";
@interface APPLocalNotificationOptions () @interface APPLocalNotificationOptions ()
...@@ -71,29 +75,9 @@ ...@@ -71,29 +75,9 @@
/** /**
* The notification's message. * The notification's message.
*/ */
- (NSString*) message - (NSString*) text
{
return [dict objectForKey:@"message"];
}
/**
* The notification's auto cancel flag.
*/
- (BOOL) autoCancel
{ {
if (IsAtLeastiOSVersion(@"8.0")){ return [dict objectForKey:@"text"];
return ![self isRepeating];
} else {
return [[dict objectForKey:@"autoCancel"] boolValue];
}
}
/**
* The notification's JSON data.
*/
- (NSString*) json
{
return [dict objectForKey:@"json"];
} }
/** /**
...@@ -101,13 +85,7 @@ ...@@ -101,13 +85,7 @@
*/ */
- (NSInteger) badgeNumber - (NSInteger) badgeNumber
{ {
NSInteger number = [[dict objectForKey:@"badge"] intValue]; return [[dict objectForKey:@"badge"] intValue];
if (number == -1) {
number = 1 + [UIApplication sharedApplication].applicationIconBadgeNumber;
}
return number;
} }
#pragma mark - #pragma mark -
...@@ -119,7 +97,7 @@ ...@@ -119,7 +97,7 @@
- (NSString*) alertBody - (NSString*) alertBody
{ {
NSString* title = [self title]; NSString* title = [self title];
NSString* msg = [self message]; NSString* msg = [self text];
NSString* alertBody = msg; NSString* alertBody = msg;
...@@ -139,16 +117,19 @@ ...@@ -139,16 +117,19 @@
{ {
NSString* path = [dict objectForKey:@"sound"]; NSString* path = [dict objectForKey:@"sound"];
if ([self stringIsNullOrEmpty:path])
return NULL;
if ([path isEqualToString:DEFAULT_SOUND])
return UILocalNotificationDefaultSoundName;
if ([path hasPrefix:@"file:/"]) if ([path hasPrefix:@"file:/"])
{
return [self soundNameForAsset:path]; return [self soundNameForAsset:path];
}
else if ([path hasPrefix:@"res:"]) if ([path hasPrefix:@"res:"])
{
return [self soundNameForResource:path]; return [self soundNameForResource:path];
}
return UILocalNotificationDefaultSoundName; return NULL;
} }
/** /**
...@@ -156,7 +137,7 @@ ...@@ -156,7 +137,7 @@
*/ */
- (NSDate*) fireDate - (NSDate*) fireDate
{ {
double timestamp = [[dict objectForKey:@"date"] double timestamp = [[dict objectForKey:@"at"]
doubleValue]; doubleValue];
return [NSDate dateWithTimeIntervalSince1970:timestamp]; return [NSDate dateWithTimeIntervalSince1970:timestamp];
...@@ -167,34 +148,30 @@ ...@@ -167,34 +148,30 @@
*/ */
- (NSCalendarUnit) repeatInterval - (NSCalendarUnit) repeatInterval
{ {
NSString* interval = [dict objectForKey:@"repeat"]; NSString* interval = [dict objectForKey:@"every"];
if ([interval isEqualToString:@"secondly"]) if ([self stringIsNullOrEmpty:interval]) {
{ return NSCalendarUnitEra;
}
else if ([interval isEqualToString:@"second"]) {
return NSCalendarUnitSecond; return NSCalendarUnitSecond;
} }
else if ([interval isEqualToString:@"minutely"]) else if ([interval isEqualToString:@"minute"]) {
{
return NSCalendarUnitMinute; return NSCalendarUnitMinute;
} }
else if ([interval isEqualToString:@"hourly"]) else if ([interval isEqualToString:@"houre"]) {
{
return NSCalendarUnitHour; return NSCalendarUnitHour;
} }
else if ([interval isEqualToString:@"daily"]) else if ([interval isEqualToString:@"day"]) {
{
return NSCalendarUnitDay; return NSCalendarUnitDay;
} }
else if ([interval isEqualToString:@"weekly"]) else if ([interval isEqualToString:@"week"]) {
{
return NSCalendarUnitWeekOfYear; return NSCalendarUnitWeekOfYear;
} }
else if ([interval isEqualToString:@"monthly"]) else if ([interval isEqualToString:@"month"]) {
{
return NSCalendarUnitMonth; return NSCalendarUnitMonth;
} }
else if ([interval isEqualToString:@"yearly"]) else if ([interval isEqualToString:@"year"]) {
{
return NSCalendarUnitYear; return NSCalendarUnitYear;
} }
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "AppDelegate.h" #import "AppDelegate.h"
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "AppDelegate+APPLocalNotification.h" #import "AppDelegate+APPLocalNotification.h"
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "UILocalNotification+APPLocalNotification.h"
@interface UIApplication (APPLocalNotification) @interface UIApplication (APPLocalNotification)
@property (readonly, getter=localNotifications) NSArray* localNotifications; @property (readonly, getter=localNotifications) NSArray* localNotifications;
@property (readonly, getter=scheduledLocalNotifications2) NSArray* triggeredLocalNotifications2;
@property (readonly, getter=triggeredLocalNotifications) NSArray* triggeredLocalNotifications;
@property (readonly, getter=localNotificationIds) NSArray* localNotificationIds; @property (readonly, getter=localNotificationIds) NSArray* localNotificationIds;
@property (readonly, getter=triggeredLocalNotificationIds) NSArray* triggeredLocalNotificationIds;
@property (readonly, getter=scheduledLocalNotificationIds) NSArray* scheduledLocalNotificationIds;
// If the app has the permission to schedule local notifications // If the app has the permission to schedule local notifications
- (BOOL) hasPermissionToScheduleLocalNotifications; - (BOOL) hasPermissionToScheduleLocalNotifications;
// Ask for permission to schedule local notifications // Ask for permission to schedule local notifications
- (void) registerPermissionToScheduleLocalNotifications; - (void) registerPermissionToScheduleLocalNotifications;
// Get local notification by ID // List of all local notification IDs from given type
- (NSArray*) localNotificationIdsByType:(APPLocalNotificationType)type;
// If local notification with ID exists
- (BOOL) localNotificationExist:(NSString*)id;
// If local notification with ID and type exists
- (BOOL) localNotificationExist:(NSString*)id type:(APPLocalNotificationType)type;
// Local notification by ID
- (UILocalNotification*) localNotificationWithId:(NSString*)id; - (UILocalNotification*) localNotificationWithId:(NSString*)id;
// Get scheduled local notification by ID // Local notification by ID and type
- (UILocalNotification*) scheduledLocalNotificationWithId:(NSString*)id; - (UILocalNotification*) localNotificationWithId:(NSString*)id andType:(APPLocalNotificationType)type;
// Get triggered local notification by ID
- (UILocalNotification*) triggeredLocalNotificationWithId:(NSString*)id;
// Property list from all local notifications // Property list from all local notifications
- (NSArray*) localNotificationOptions; - (NSArray*) localNotificationOptions;
// Property list from all scheduled notifications
- (NSArray*) scheduledLocalNotificationOptions;
// Property list from all triggered notifications
- (NSArray*) triggeredLocalNotificationOptions;
// Property list from given local notifications // Property list from given local notifications
- (NSArray*) localNotificationOptions:(NSArray*)ids; - (NSArray*) localNotificationOptionsById:(NSArray*)ids;
// Property list from given scheduled notifications // Property list from all local notifications with type constraint
- (NSArray*) scheduledLocalNotificationOptions:(NSArray*)ids; - (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type;
// Property list from given triggered notifications // Property list from given local notifications with type constraint
- (NSArray*) triggeredLocalNotificationOptions:(NSArray*)ids; - (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type andId:(NSArray*)ids;
// Clear single local notfications
- (void) clearLocalNotification:(UILocalNotification*)notification;
// Clear all local notfications
- (void) clearAllLocalNotifications;
@end @end
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "UIApplication+APPLocalNotification.h" #import "UIApplication+APPLocalNotification.h"
...@@ -101,7 +103,7 @@ ...@@ -101,7 +103,7 @@
for (UILocalNotification* notification in scheduledNotifications) for (UILocalNotification* notification in scheduledNotifications)
{ {
if (notification && [notification wasScheduled]) { if (notification && [notification isScheduled]) {
[notifications addObject:notification]; [notifications addObject:notification];
} }
} }
...@@ -120,7 +122,7 @@ ...@@ -120,7 +122,7 @@
for (UILocalNotification* notification in notifications) for (UILocalNotification* notification in notifications)
{ {
if ([notification wasTriggered]) { if ([notification isTriggered]) {
[triggeredNotifications addObject:notification]; [triggeredNotifications addObject:notification];
} }
} }
...@@ -129,8 +131,7 @@ ...@@ -129,8 +131,7 @@
} }
/** /**
* List of all triggered local notifications IDs which have been scheduled * List of all local notifications IDs.
* and not yet removed from the notification center.
*/ */
- (NSArray*) localNotificationIds - (NSArray*) localNotificationIds
{ {
...@@ -146,67 +147,58 @@ ...@@ -146,67 +147,58 @@
} }
/** /**
* List of all added local notifications IDs which have been scheduled * List of all local notifications IDs from given type.
* and not yet removed from the notification center. *
* @param type
* Notification life cycle type
*/ */
- (NSArray*) triggeredLocalNotificationIds - (NSArray*) localNotificationIdsByType:(APPLocalNotificationType)type
{ {
NSArray* notifications = self.triggeredLocalNotifications; NSArray* notifications = self.localNotifications;
NSMutableArray* ids = [[NSMutableArray alloc] init]; NSMutableArray* ids = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications) for (UILocalNotification* notification in notifications)
{ {
[ids addObject:notification.options.id]; if (notification.type == type) {
[ids addObject:notification.options.id];
}
} }
return ids; return ids;
} }
/** /*
* List of all scheduled local notifications IDs. * If local notification with ID exists.
*
* @param id
* Notification ID
*/ */
- (NSArray*) scheduledLocalNotificationIds - (BOOL) localNotificationExist:(NSString*)id
{ {
NSArray* notifications = self.scheduledLocalNotifications2; return [self localNotificationWithId:id] != NULL;
NSMutableArray* ids = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications)
{
[ids addObject:notification.options.id];
}
return ids;
} }
/** /* If local notification with ID and type exists
* Get local notification by ID.
* *
* @param id * @param id
* Notification ID * Notification ID
* @param type
* Notification life cycle type
*/ */
- (UILocalNotification*) localNotificationWithId:(NSString*)id - (BOOL) localNotificationExist:(NSString*)id type:(APPLocalNotificationType)type
{ {
NSArray* notifications = self.localNotifications; return [self localNotificationWithId:id andType:type] != NULL;
for (UILocalNotification* notification in notifications)
{
if ([notification.options.id isEqualToString:id]) {
return notification;
}
}
return NULL;
} }
/** /**
* Get scheduled local notification by ID. * Get local notification with ID.
* *
* @param id * @param id
* Notification ID * Notification ID
*/ */
- (UILocalNotification*) scheduledLocalNotificationWithId:(NSString*)id - (UILocalNotification*) localNotificationWithId:(NSString*)id
{ {
NSArray* notifications = self.scheduledLocalNotifications2; NSArray* notifications = self.localNotifications;
for (UILocalNotification* notification in notifications) for (UILocalNotification* notification in notifications)
{ {
...@@ -218,19 +210,20 @@ ...@@ -218,19 +210,20 @@
return NULL; return NULL;
} }
/** /*
* Get triggered local notification by ID. * Get local notification with ID and type.
* *
* @param id * @param id
* Notification ID * Notification ID
* @param type
* Notification life cycle type
*/ */
- (UILocalNotification*) triggeredLocalNotificationWithId:(NSString*)id - (UILocalNotification*) localNotificationWithId:(NSString*)id andType:(APPLocalNotificationType)type
{ {
UILocalNotification* notification = [self localNotificationWithId:id]; UILocalNotification* notification = [self localNotificationWithId:id];
if (notification && [notification wasTriggered]) { if (notification && notification.type == type)
return notification; return notification;
}
return NULL; return NULL;
} }
...@@ -252,32 +245,21 @@ ...@@ -252,32 +245,21 @@
} }
/** /**
* List of properties from all scheduled notifications. * List of properties from all local notifications from given type.
*/ *
- (NSArray*) scheduledLocalNotificationOptions * @param type
{ * Notification life cycle type
NSArray* notifications = [self scheduledLocalNotifications2];
NSMutableArray* options = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications)
{
[options addObject:notification.userInfo];
}
return options;
}
/**
* List of properties from all triggered notifications.
*/ */
- (NSArray*) triggeredLocalNotificationOptions - (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type
{ {
NSArray* notifications = self.triggeredLocalNotifications; NSArray* notifications = self.localNotifications;
NSMutableArray* options = [[NSMutableArray alloc] init]; NSMutableArray* options = [[NSMutableArray alloc] init];
for (UILocalNotification* notification in notifications) for (UILocalNotification* notification in notifications)
{ {
[options addObject:notification.userInfo]; if (notification.type == type) {
[options addObject:notification.userInfo];
}
} }
return options; return options;
...@@ -289,7 +271,7 @@ ...@@ -289,7 +271,7 @@
* @param ids * @param ids
* Notification IDs * Notification IDs
*/ */
- (NSArray*) localNotificationOptions:(NSArray*)ids - (NSArray*) localNotificationOptionsById:(NSArray*)ids
{ {
UILocalNotification* notification; UILocalNotification* notification;
NSMutableArray* options = [[NSMutableArray alloc] init]; NSMutableArray* options = [[NSMutableArray alloc] init];
...@@ -307,21 +289,23 @@ ...@@ -307,21 +289,23 @@
} }
/** /**
* List of properties from given scheduled notifications. * List of properties from given local notifications.
* *
* @param type
* Notification life cycle type
* @param ids * @param ids
* Notification IDs * Notification IDs
*/ */
- (NSArray*) scheduledLocalNotificationOptions:(NSArray*)ids - (NSArray*) localNotificationOptionsByType:(APPLocalNotificationType)type andId:(NSArray*)ids
{ {
UILocalNotification* notification; UILocalNotification* notification;
NSMutableArray* options = [[NSMutableArray alloc] init]; NSMutableArray* options = [[NSMutableArray alloc] init];
for (NSString* id in ids) for (NSString* id in ids)
{ {
notification = [self scheduledLocalNotificationWithId:id]; notification = [self localNotificationWithId:id];
if (notification) { if (notification && notification.type == type) {
[options addObject:notification.userInfo]; [options addObject:notification.userInfo];
} }
} }
...@@ -329,27 +313,33 @@ ...@@ -329,27 +313,33 @@
return options; return options;
} }
/** /*
* List of properties from given triggered notifications. * Clear all local notfications.
*
* @param ids
* Notification IDs
*/ */
- (NSArray*) triggeredLocalNotificationOptions:(NSArray*)ids - (void) clearAllLocalNotifications
{ {
UILocalNotification* notification; NSArray* notifications = self.triggeredLocalNotifications;
NSMutableArray* options = [[NSMutableArray alloc] init];
for (NSString* id in ids)
{
notification = [self triggeredLocalNotificationWithId:id];
if (notification) { for (UILocalNotification* notification in notifications) {
[options addObject:notification.userInfo]; [self clearLocalNotification:notification];
}
} }
}
return options; /*
* Clear single local notfication.
*
* @param notification
* The local notification object
*/
- (void) clearLocalNotification:(UILocalNotification*)notification
{
[self cancelLocalNotification:notification];
if ([notification isRepeating]) {
notification.fireDate = notification.options.fireDate;
[self scheduleLocalNotification:notification];
};
} }
@end @end
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "APPLocalNotificationOptions.h" #import "APPLocalNotificationOptions.h"
typedef NS_ENUM(NSUInteger, APPLocalNotificationType) {
NotifcationTypeAll = 0,
NotifcationTypeScheduled = 1,
NotifcationTypeTriggered = 2
};
@interface UILocalNotification (APPLocalNotification) @interface UILocalNotification (APPLocalNotification)
// Initialize a new local notification // Initialize a new local notification
- (id) initWithOptions:(NSDictionary*)dict; - (id) initWithOptions:(NSDictionary*)dict;
// The options provided by the plug-in // The options provided by the plug-in
- (APPLocalNotificationOptions*) options; - (APPLocalNotificationOptions*) options;
// Timeinterval since last trigger date
- (double) timeIntervalSinceLastTrigger;
// Timeinterval since fire date // Timeinterval since fire date
- (double) 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 scheduled // If the notification was already scheduled
- (BOOL) wasScheduled; - (BOOL) isScheduled;
// If the notification was already triggered // If the notification was already triggered
- (BOOL) wasTriggered; - (BOOL) isTriggered;
// If the notification was updated // If the notification was updated
- (BOOL) wasUpdated; - (BOOL) wasUpdated;
// If it's a repeating notification // If it's a repeating notification
- (BOOL) isRepeating; - (BOOL) isRepeating;
// Notifciation type
- (APPLocalNotificationType) type;
// Encode the user info dict to JSON // Encode the user info dict to JSON
- (NSString*) encodeToJSON; - (NSString*) encodeToJSON;
......
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*
* @APPPLANT_LICENSE_HEADER_END@
*/ */
#import "UILocalNotification+APPLocalNotification.h" #import "UILocalNotification+APPLocalNotification.h"
...@@ -25,6 +27,9 @@ ...@@ -25,6 +27,9 @@
static char optionsKey; static char optionsKey;
NSInteger const APPLocalNotificationTypeScheduled = 1;
NSInteger const APPLocalNotificationTypeTriggered = 2;
@implementation UILocalNotification (APPLocalNotification) @implementation UILocalNotification (APPLocalNotification)
#pragma mark - #pragma mark -
...@@ -131,10 +136,20 @@ static char optionsKey; ...@@ -131,10 +136,20 @@ static char optionsKey;
- (double) timeIntervalSinceFireDate - (double) timeIntervalSinceFireDate
{ {
NSDate* now = [NSDate date]; NSDate* now = [NSDate date];
NSDate* fireDate = self.options.fireDate; NSDate* fireDate = self.fireDate;
int timespan = [now timeIntervalSinceDate:fireDate]; int timespan = [now timeIntervalSinceDate:fireDate];
return timespan;
}
/**
* Timeinterval since last trigger date.
*/
- (double) timeIntervalSinceLastTrigger
{
int timespan = [self timeIntervalSinceFireDate];
if ([self isRepeating]) { if ([self isRepeating]) {
timespan = timespan % [self repeatIntervalInSeconds]; timespan = timespan % [self repeatIntervalInSeconds];
} }
...@@ -173,11 +188,11 @@ static char optionsKey; ...@@ -173,11 +188,11 @@ static char optionsKey;
*/ */
- (BOOL) wasInThePast - (BOOL) wasInThePast
{ {
return [self timeIntervalSinceFireDate] > 0; return [self timeIntervalSinceLastTrigger] > 0;
} }
// If the notification was already scheduled // If the notification was already scheduled
- (BOOL) wasScheduled - (BOOL) isScheduled
{ {
return [self isRepeating] || ![self wasInThePast]; return [self isRepeating] || ![self wasInThePast];
} }
...@@ -185,7 +200,7 @@ static char optionsKey; ...@@ -185,7 +200,7 @@ static char optionsKey;
/** /**
* If the notification was already triggered. * If the notification was already triggered.
*/ */
- (BOOL) wasTriggered - (BOOL) isTriggered
{ {
NSDate* now = [NSDate date]; NSDate* now = [NSDate date];
NSDate* fireDate = self.fireDate; NSDate* fireDate = self.fireDate;
...@@ -219,4 +234,12 @@ static char optionsKey; ...@@ -219,4 +234,12 @@ static char optionsKey;
return [self.options isRepeating]; return [self.options isRepeating];
} }
/**
* Process state type of the local notification.
*/
- (APPLocalNotificationType) type
{
return [self isTriggered] ? NotifcationTypeTriggered : NotifcationTypeScheduled;
}
@end @end
/*
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.
*/
using System;
using System.Linq;
using Microsoft.Phone.Shell;
using WPCordovaClassLib.Cordova;
using WPCordovaClassLib.Cordova.Commands;
using WPCordovaClassLib.Cordova.JSON;
using De.APPPlant.Cordova.Plugin.LocalNotification;
namespace Cordova.Extension.Commands
{
/// <summary>
/// Implementes access to application live tiles
/// http://msdn.microsoft.com/en-us/library/hh202948(v=VS.92).aspx
/// </summary>
public class LocalNotification : BaseCommand
{
/// <summary>
/// Informs if the device is ready and the deviceready event has been fired
/// </summary>
private bool DeviceReady = false;
/// <summary>
/// Informs either the app is running in background or foreground
/// </summary>
private bool RunsInBackground = false;
/// <summary>
/// Sets application live tile
/// </summary>
public void add (string jsonArgs)
{
string[] args = JsonHelper.Deserialize<string[]>(jsonArgs);
Options options = JsonHelper.Deserialize<Options>(args[0]);
// Application Tile is always the first Tile, even if it is not pinned to Start.
ShellTile AppTile = ShellTile.ActiveTiles.First();
if (AppTile != null)
{
// Set the properties to update for the Application Tile
// Empty strings for the text values and URIs will result in the property being cleared.
FlipTileData TileData = CreateTileData(options);
AppTile.Update(TileData);
FireEvent("trigger", options.ID, options.JSON);
FireEvent("add", options.ID, options.JSON);
}
DispatchCommandResult();
}
/// <summary>
/// Clears the application live tile
/// </summary>
public void cancel (string jsonArgs)
{
string[] args = JsonHelper.Deserialize<string[]>(jsonArgs);
string notificationID = args[0];
cancelAll(jsonArgs);
FireEvent("cancel", notificationID, "");
DispatchCommandResult();
}
/// <summary>
/// Clears the application live tile
/// </summary>
public void cancelAll (string jsonArgs)
{
// Application Tile is always the first Tile, even if it is not pinned to Start.
ShellTile AppTile = ShellTile.ActiveTiles.First();
if (AppTile != null)
{
// Set the properties to update for the Application Tile
// Empty strings for the text values and URIs will result in the property being cleared.
FlipTileData TileData = new FlipTileData
{
Count = 0,
BackTitle = "",
BackContent = "",
WideBackContent = "",
SmallBackgroundImage = new Uri("appdata:Background.png"),
BackgroundImage = new Uri("appdata:Background.png"),
WideBackgroundImage = new Uri("/Assets/Tiles/FlipCycleTileLarge.png", UriKind.Relative),
};
// Update the Application Tile
AppTile.Update(TileData);
}
DispatchCommandResult();
}
/// <summary>
/// Checks wether a notification with an ID is scheduled
/// </summary>
public void isScheduled (string jsonArgs)
{
DispatchCommandResult();
}
/// <summary>
/// Retrieves a list with all currently pending notifications
/// </summary>
public void getScheduledIds (string jsonArgs)
{
DispatchCommandResult();
}
/// <summary>
/// Checks wether a notification with an ID was triggered
/// </summary>
public void isTriggered (string jsonArgs)
{
DispatchCommandResult();
}
/// <summary>
/// Retrieves a list with all currently triggered notifications
/// </summary>
public void getTriggeredIds (string jsonArgs)
{
DispatchCommandResult();
}
/// <summary>
/// Informs that the device is ready and the deviceready event has been fired
/// </summary>
public void deviceready (string jsonArgs)
{
DeviceReady = true;
}
/// <summary>
/// Creates tile data
/// </summary>
private FlipTileData CreateTileData (Options options)
{
FlipTileData tile = new FlipTileData();
// Badge sollte nur gelöscht werden, wenn expliziet eine `0` angegeben wurde
if (options.Badge != 0)
{
tile.Count = options.Badge;
}
tile.BackTitle = options.Title;
tile.BackContent = options.ShortMessage;
tile.WideBackContent = options.Message;
if (!String.IsNullOrEmpty(options.SmallImage))
{
tile.SmallBackgroundImage = new Uri(options.SmallImage, UriKind.RelativeOrAbsolute);
}
if (!String.IsNullOrEmpty(options.Image))
{
tile.BackgroundImage = new Uri(options.Image, UriKind.RelativeOrAbsolute);
}
if (!String.IsNullOrEmpty(options.WideImage))
{
tile.WideBackgroundImage = new Uri(options.WideImage, UriKind.RelativeOrAbsolute);
}
return tile;
}
/// <summary>
/// Fires the given event.
/// </summary>
private void FireEvent (string Event, string Id, string JSON = "")
{
string state = ApplicationState();
string args = String.Format("\'{0}\',\'{1}\',\'{2}\'", Id, state, JSON);
string js = String.Format("window.plugin.notification.local.on{0}({1})", Event, args);
PluginResult pluginResult = new PluginResult(PluginResult.Status.OK, js);
pluginResult.KeepCallback = true;
DispatchCommandResult(pluginResult);
}
/// <summary>
/// Retrieves the application state
/// Either "background" or "foreground"
/// </summary>
private String ApplicationState ()
{
return RunsInBackground ? "background" : "foreground";
}
/// <summary>
/// Occurs when the application is being deactivated.
/// </summary>
public override void OnPause (object sender, DeactivatedEventArgs e)
{
RunsInBackground = true;
}
/// <summary>
/// Occurs when the application is being made active after previously being put
/// into a dormant state or tombstoned.
/// </summary>
public override void OnResume (object sender, Microsoft.Phone.Shell.ActivatedEventArgs e)
{
RunsInBackground = false;
}
}
}
/*
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.
*/
using System;
using System.Linq;
using System.Runtime.Serialization;
namespace De.APPPlant.Cordova.Plugin.LocalNotification
{
/// <summary>
/// Represents LiveTile options
/// </summary>
[DataContract]
class Options
{
/// <summary>
/// The Title that is displayed
/// </summary>
[DataMember(IsRequired = false, Name = "title")]
public string Title { get; set; }
/// <summary>
/// The message that is displayed
/// </summary>
[DataMember(IsRequired = false, Name = "message")]
public string Message { get; set; }
/// <summary>
/// Gekürzte Nachricht (alles ab dem Zeilenumbruch entfernt)
/// </summary>
public string ShortMessage
{
get
{
string[] separator = new string[] { "\r\n", "\n" };
return Message.Split(separator, StringSplitOptions.RemoveEmptyEntries).First();
}
}
/// <summary>
/// Displays number badge to notification
/// </summary>
[DataMember(IsRequired = false, Name = "badge")]
public int Badge { get; set; }
/// <summary>
/// Tile count
/// </summary>
[DataMember(IsRequired = false, Name = "Date")]
public int Date { get; set; }
/// <summary>
/// Has the options of daily', 'weekly',''monthly','yearly')
/// </summary>
[DataMember(IsRequired = false, Name = "repeat")]
public string Repeat { get; set; }
/// <summary>
/// Notification specific data
/// </summary>
[DataMember(IsRequired = false, Name = "json")]
public string JSON { get; set; }
/// <summary>
/// Message-ID
/// </summary>
[DataMember(IsRequired = false, Name = "id")]
public string ID { get; set; }
/// <summary>
/// Setting this flag will make it so the notification is automatically canceled when the user clicks it
/// </summary>
[DataMember(IsRequired = false, Name = "autoCancel")]
public bool AutoCancel { get; set; }
/// <summary>
/// The notification small background image to be displayed
/// </summary>
[DataMember(IsRequired = false, Name = "smallImage")]
public string SmallImage { get; set; }
/// <summary>
/// The notification background image to be displayed
/// </summary>
[DataMember(IsRequired = false, Name = "image")]
public string Image { get; set; }
/// <summary>
/// The notification wide background image to be displayed
/// </summary>
[DataMember(IsRequired = false, Name = "wideImage")]
public string WideImage { get; set; }
}
}
/* /*
Copyright 2013-2014 appPlant UG * Copyright (c) 2013-2015 by appPlant UG. All rights reserved.
*
Licensed to the Apache Software Foundation (ASF) under one * @APPPLANT_LICENSE_HEADER_START@
or more contributor license agreements. See the NOTICE file *
distributed with this work for additional information * This file contains Original Code and/or Modifications of Original Code
regarding copyright ownership. The ASF licenses this file * as defined in and that are subject to the Apache License
to you under the Apache License, Version 2.0 (the * Version 2.0 (the 'License'). You may not use this file except in
"License"); you may not use this file except in compliance * compliance with the License. Please obtain a copy of the License at
with the License. You may obtain a copy of the License at * http://opensource.org/licenses/Apache-2.0/ and read it before using this
* file.
http://www.apache.org/licenses/LICENSE-2.0 *
* The Original Code and all software distributed under the License are
Unless required by applicable law or agreed to in writing, * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
software distributed under the License is distributed on an * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
KIND, either express or implied. See the License for the * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
specific language governing permissions and limitations * Please see the License for the specific language governing rights and
under the License. * limitations under the License.
*/ *
* @APPPLANT_LICENSE_HEADER_END@
*/
var exec = require('cordova/exec'), var exec = require('cordova/exec'),
channel = require('cordova/channel'); channel = require('cordova/channel');
// Called after 'deviceready' event /*************
channel.deviceready.subscribe( function () { * INTERFACE *
// Device is ready now, the listeners are registered *************/
// and all queued events can be executed.
exec(null, null, 'LocalNotification', 'deviceready', []);
});
// Called before 'deviceready' event
channel.onCordovaReady.subscribe( function () {
// The cordova device plugin is ready now
channel.onCordovaInfoReady.subscribe( function () {
if (device.platform == 'Android') {
channel.onPause.subscribe( function () {
// Necessary to set the state to `background`
exec(null, null, 'LocalNotification', 'pause', []);
});
channel.onResume.subscribe( function () {
// Necessary to set the state to `foreground`
exec(null, null, 'LocalNotification', 'resume', []);
});
// Necessary to set the state to `foreground`
exec(null, null, 'LocalNotification', 'resume', []);
}
// Merges the platform specific properties into the default properties
exports.applyPlatformSpecificOptions();
});
});
/**
* @private
*
* Default values.
*/
exports._defaults = {
message: '',
title: '',
autoCancel: false,
badge: -1,
id: '0',
json: '',
repeat: '',
date: undefined
};
/** /**
* Returns the default settings * Returns the default settings
...@@ -90,14 +47,14 @@ exports.setDefaults = function (newDefaults) { ...@@ -90,14 +47,14 @@ exports.setDefaults = function (newDefaults) {
var defaults = this.getDefaults(); var defaults = this.getDefaults();
for (var key in defaults) { for (var key in defaults) {
if (newDefaults[key] !== undefined) { if (newDefaults.hasOwnProperty(key)) {
defaults[key] = newDefaults[key]; defaults[key] = newDefaults[key];
} }
} }
}; };
/** /**
* Add a new entry to the registry * Schedule a new local notification.
* *
* @param {Object} opts * @param {Object} opts
* The notification properties * The notification properties
...@@ -106,7 +63,7 @@ exports.setDefaults = function (newDefaults) { ...@@ -106,7 +63,7 @@ exports.setDefaults = function (newDefaults) {
* @param {Object?} scope * @param {Object?} scope
* The scope for the callback function * The scope for the callback function
*/ */
exports.add = function (opts, callback, scope) { exports.schedule = function (opts, callback, scope) {
this.registerPermission(function(granted) { this.registerPermission(function(granted) {
if (!granted) if (!granted)
...@@ -121,7 +78,7 @@ exports.add = function (opts, callback, scope) { ...@@ -121,7 +78,7 @@ exports.add = function (opts, callback, scope) {
this.convertProperties(properties); this.convertProperties(properties);
} }
this.exec('add', notifications, callback, scope); this.exec('schedule', notifications, callback, scope);
}, this); }, this);
}; };
...@@ -141,7 +98,7 @@ exports.update = function (opts, callback, scope) { ...@@ -141,7 +98,7 @@ exports.update = function (opts, callback, scope) {
for (var i = 0; i < notifications.length; i++) { for (var i = 0; i < notifications.length; i++) {
var properties = notifications[i]; var properties = notifications[i];
this.convertUpdateProperties(properties); this.convertProperties(properties);
} }
this.exec('update', notifications, callback, scope); this.exec('update', notifications, callback, scope);
...@@ -209,7 +166,7 @@ exports.cancelAll = function (callback, scope) { ...@@ -209,7 +166,7 @@ exports.cancelAll = function (callback, scope) {
}; };
/** /**
* Check if a notification with an ID exists. * Check if a notification with an ID is present.
* *
* @param {String} id * @param {String} id
* The ID of the notification * The ID of the notification
...@@ -218,17 +175,10 @@ exports.cancelAll = function (callback, scope) { ...@@ -218,17 +175,10 @@ exports.cancelAll = function (callback, scope) {
* @param {Object?} scope * @param {Object?} scope
* The scope for the callback function * The scope for the callback function
*/ */
exports.exist = function (id, callback, scope) { exports.isPresent = function (id, callback, scope) {
var notId = (id || '0').toString(); var notId = (id || '0').toString();
this.exec('exist', notId, callback, scope); this.exec('isPresent', notId, callback, scope);
};
/**
* Alias for `exist`.
*/
exports.exists = function () {
this.exist.apply(this, arguments);
}; };
/** /**
...@@ -489,117 +439,83 @@ exports.promptForPermission = function (callback, scope) { ...@@ -489,117 +439,83 @@ exports.promptForPermission = function (callback, scope) {
exports.registerPermission.apply(this, arguments); exports.registerPermission.apply(this, arguments);
}; };
/**
* Occurs when a notification was added.
*
* @param {String} id
* The ID of the notification
* @param {String} state
* Either "foreground" or "background"
* @param {String} json
* A custom (JSON) string
* @param {Object} data
* The notification properties
*/
exports.onadd = function (id, state, json, data) {};
/** /**********
* Occurs when the notification is triggered. * EVENTS *
* **********/
* @param {String} id
* The ID of the notification
* @param {String} state
* Either "foreground" or "background"
* @param {String} json
* A custom (JSON) string
* @param {Object} data
* The notification properties
*/
exports.ontrigger = function (id, state, json, data) {};
/** /**
* Fires after the notification was clicked. * Register callback for given event.
* *
* @param {String} id * @param {String} event
* The ID of the notification * The event's name
* @param {String} state * @param {Function} callback
* Either "foreground" or "background" * The function to be exec as callback
* @param {String} json * @param {Object?} scope
* A custom (JSON) string * The callback function's scope
* @param {Object} data
* The notification properties
*/ */
exports.onclick = function (id, state, json, data) {}; exports.on = function (event, callback, scope) {
/** if (!this._listener[event]) {
* Fires if the notification was canceled. this._listener[event] = [];
* }
* @param {String} id
* The ID of the notification
* @param {String} state
* Either "foreground" or "background"
* @param {String} json
* A custom (JSON) string
* @param {Object} data
* The notification properties
*/
exports.oncancel = function (id, state, json, data) {};
/** var item = [callback, scope || window];
* Get fired when the notification was cleared.
*
* @param {String} id
* The ID of the notification
* @param {String} state
* Either "foreground" or "background"
* @param {String} json
* A custom (JSON) string
* @param {Object} data
* The notification properties
*/
exports.onclear = function (id, state, json, data) {};
/** this._listener[event].push(item);
* Get fired when a repeating notification should be updated.
*
* @param {String} id
* The ID of the notification
* @param {String} state
* Either "foreground" or "background"
* @param {String} json
* A custom (JSON) string
* @param {Object} data
* The notification properties
* @return {Object} JSONObject with updatevalues
*/
exports.onupdate = function (id, state, json, data) {
return null;
}; };
/** /**
* Is called from the native part to receive the onupdate resultarray and send it back to native. * Unregister callback for given event.
* *
* @param {String} id * @param {String} event
* The ID of the notification * The event's name
* @param {String} state * @param {Function} callback
* Either "foreground" or "background" * The function to be exec as callback
* @param {String} json
* A custom (JSON) string
* @param {Object} data
* The notification properties
*/ */
exports.onupdateCall = function (id, state, json, data) { exports.un = function (event, callback) {
var updates = exports.onupdate(id, state, json, data); var listener = this._listener[event];
if (updates != null){
updates.id = id; if (!listener)
update(updates,null,null); return;
};
for (var i = 0; i < listener.length; i++) {
var fn = listener[i][0];
if (fn == callback) {
listener.splice(i, 1);
break;
}
}
};
/***********
* MEMBERS *
***********/
// Default values
exports._defaults = {
text: '',
title: '',
sound: 'res://platform_default',
badge: 0,
id: 0,
data: undefined,
every: undefined,
at: undefined
}; };
// listener
exports._listener = {};
/***********
* PRIVATE *
***********/
/** /**
* @private * Merge custom properties with the default values.
*
* Merges custom properties with the default values.
* *
* @param {Object} options * @param {Object} options
* Set of custom values * Set of custom values
...@@ -610,13 +526,21 @@ exports.onupdateCall = function (id, state, json, data) { ...@@ -610,13 +526,21 @@ exports.onupdateCall = function (id, state, json, data) {
exports.mergeWithDefaults = function (options) { exports.mergeWithDefaults = function (options) {
var defaults = this.getDefaults(); var defaults = this.getDefaults();
options.date = this.getValueFor(options, 'date', 'at', 'firstAt'); options.at = this.getValueFor(options, 'at', 'firstAt', 'date');
options.repeat = this.getValueFor(options, 'repeat', 'every'); options.text = this.getValueFor(options, 'text', 'message');
options.message = this.getValueFor(options, 'message', 'text'); options.data = this.getValueFor(options, 'data', 'json');
if (options.at === undefined || options.at === null) {
options.at = new Date();
}
for (var key in defaults) { for (var key in defaults) {
if (options[key] === null || options[key] === undefined) { if (options[key] === null || options[key] === undefined) {
options[key] = defaults[key]; if (options.hasOwnProperty(key) && ['data','sound'].indexOf(key) > -1) {
options[key] = undefined;
} else {
options[key] = defaults[key];
}
} }
} }
...@@ -630,8 +554,6 @@ exports.mergeWithDefaults = function (options) { ...@@ -630,8 +554,6 @@ exports.mergeWithDefaults = function (options) {
}; };
/** /**
* @private
*
* Convert the passed values to their required type. * Convert the passed values to their required type.
* *
* @param {Object} options * @param {Object} options
...@@ -642,79 +564,43 @@ exports.mergeWithDefaults = function (options) { ...@@ -642,79 +564,43 @@ exports.mergeWithDefaults = function (options) {
*/ */
exports.convertProperties = function (options) { exports.convertProperties = function (options) {
options.id = options.id.toString(); if (options.id) {
options.title = options.title.toString(); if (isNaN(options.id)) {
options.message = options.message.toString(); options.id = this.getDefaults().id;
options.autoCancel = options.autoCancel === true; } else {
options.id = options.id.toString();
if (isNaN(options.id)) { }
options.id = this.getDefaults().id;
}
if (isNaN(options.badge)) {
options.badge = this.getDefaults().badge;
}
options.badge = Number(options.badge);
if (options.date === undefined || options.date === null) {
options.date = new Date();
}
if (typeof options.date == 'object') {
options.date = Math.round(options.date.getTime()/1000);
} }
if (typeof options.json == 'object') { if (options.title) {
options.json = JSON.stringify(options.json); options.title = options.title.toString();
} }
return options; if (options.text) {
}; options.text = options.text.toString();
/**
* @private
*
* Convert the passed values to their required type only for update function.
*
* @param {Object} options
* Set of custom values
*
* @retrun {Object}
* The converted property list
*/
exports.convertUpdateProperties = function (options) {
options.id = options.id.toString();
options.title = options.title.toString();
options.message = options.message.toString();
options.autoCancel = options.autoCancel === true;
if (isNaN(options.id)) {
options.id = this.getDefaults().id;
} }
if (isNaN(options.badge)) { if (options.badge) {
options.badge = this.getDefaults().badge; if (isNaN(options.badge)) {
options.badge = this.getDefaults().badge;
} else {
options.badge = Number(options.badge);
}
} }
options.badge = Number(options.badge); if (typeof options.at == 'object') {
options.at = Math.round(options.at.getTime()/1000);
if (typeof options.date == 'object') {
options.date = Math.round(options.date.getTime()/1000);
} }
if (typeof options.json == 'object') { if (typeof options.data == 'object') {
options.json = JSON.stringify(options.json); options.data = JSON.stringify(options.data);
} }
return options; return options;
}; };
/** /**
* @private * Merge platform specific properties into the default ones.
*
* Merges the platform specific properties into the default properties.
* *
* @return {Object} * @return {Object}
* The default properties for the platform * The default properties for the platform
...@@ -724,26 +610,18 @@ exports.applyPlatformSpecificOptions = function () { ...@@ -724,26 +610,18 @@ exports.applyPlatformSpecificOptions = function () {
switch (device.platform) { switch (device.platform) {
case 'Android': case 'Android':
defaults.icon = 'icon'; defaults.icon = 'res://ic_popup_reminder';
defaults.smallIcon = null; defaults.smallIcon = 'res://ic_popup_reminder';
defaults.ongoing = false; defaults.ongoing = false;
defaults.led = 'FFFFFF'; /*RRGGBB*/ defaults.led = 'FFFFFF';
defaults.sound = 'TYPE_NOTIFICATION'; break; break;
case 'iOS':
defaults.sound = ''; break;
case 'WinCE': case 'Win32NT':
defaults.smallImage = null;
defaults.image = null;
defaults.wideImage = null;
} }
return defaults; return defaults;
}; };
/** /**
* @private * Create callback, which will be executed within a specific scope.
*
* Creates a callback, which will be executed within a specific scope.
* *
* @param {Function} callbackFn * @param {Function} callbackFn
* The callback function * The callback function
...@@ -763,8 +641,6 @@ exports.createCallbackFn = function (callbackFn, scope) { ...@@ -763,8 +641,6 @@ exports.createCallbackFn = function (callbackFn, scope) {
}; };
/** /**
* @private
*
* Convert the IDs to Strings. * Convert the IDs to Strings.
* *
* @param {String/Number[]} ids * @param {String/Number[]} ids
...@@ -782,13 +658,10 @@ exports.convertIds = function (ids) { ...@@ -782,13 +658,10 @@ exports.convertIds = function (ids) {
}; };
/** /**
* @private * First found value for the given keys.
*
* Return the first found value for the given keys.
* *
* @param {Object} options * @param {Object} options
* Object with key-value properties * Object with key-value properties
*
* @param {String[]} keys* * @param {String[]} keys*
* Key list * Key list
*/ */
...@@ -805,9 +678,30 @@ exports.getValueFor = function (options) { ...@@ -805,9 +678,30 @@ exports.getValueFor = function (options) {
}; };
/** /**
* @private * Fire event with given arguments.
* *
* Executes the native counterpart. * @param {String} event
* The event's name
* @param {args*}
* The callback's arguments
*/
exports.fireEvent = function (event) {
var args = Array.apply(null, arguments).slice(1),
listener = this._listener[event];
if (!listener)
return;
for (var i = 0; i < listener.length; i++) {
var fn = listener[i][0],
scope = listener[i][1];
fn.apply(scope, args);
}
};
/**
* Execute the native counterpart.
* *
* @param {String} action * @param {String} action
* The name of the action * The name of the action
...@@ -830,3 +724,24 @@ exports.exec = function (action, args, callback, scope) { ...@@ -830,3 +724,24 @@ exports.exec = function (action, args, callback, scope) {
exec(fn, null, 'LocalNotification', action, params); exec(fn, null, 'LocalNotification', action, params);
}; };
/*********
* HOOKS *
*********/
// Called after 'deviceready' event
channel.deviceready.subscribe(function () {
// Device is ready now, the listeners are registered
// and all queued events can be executed.
exec(null, null, 'LocalNotification', 'deviceready', []);
});
// Called before 'deviceready' event
channel.onCordovaReady.subscribe(function () {
// Device plugin is ready now
channel.onCordovaInfoReady.subscribe(function () {
// Merge platform specifics into defaults
exports.applyPlatformSpecificOptions();
});
});
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